Merge branch 'master' into release

This commit is contained in:
adelikat 2017-07-23 10:21:52 -05:00
commit 75689760c5
176 changed files with 13218 additions and 13914 deletions

View File

@ -1,39 +1,49 @@
;;NOTE: These hashes were generated using trimmed ROM headers ;;NOTE: These hashes were generated using trimmed ROM headers
;0 = normal cart (no banking or pokey or RAM)
;1 = Super Game mapper (standard mapper)
;2 = Super Game with extra ROM
;3 = F-18 Hornet Mapper
;4 = Double Dragon and Rampage
md5:91041AADD1700A7A4076F4005F2C362F Diagnostics A78 NTSC=true;board=0
md5:89E7B20E7E0C629D00C6CA68949A216F Test Rom A78 NTSC=true;board=0
md5:4332c24e4f3bc72e7fe1b77adf66c2b7 3D Asteroids A78 NTSC=true;board=0 md5:4332c24e4f3bc72e7fe1b77adf66c2b7 3D Asteroids A78 NTSC=true;board=0
md5:0be996d25144966d5541c9eb4919b289 Ace of Aces A78 NTSC=true;board=A78SG md5:A0285769753B18C407CB6E818B7DCAD2 3D Asteroids A78 NTSC=true;board=0
md5:aadde920b3aaba03bc10b40bd0619c94 Ace of Aces A78 PAL=true;board=A78SG md5:0be996d25144966d5541c9eb4919b289 Ace of Aces A78 NTSC=true;board=1
md5:877dcc97a775ed55081864b2dbf5f1e2 Alien Brigade A78 NTSC=true;board=A78S9 md5:aadde920b3aaba03bc10b40bd0619c94 Ace of Aces A78 PAL=true;board=1
md5:de3e9496cb7341f865f27e5a72c7f2f5 Alien Brigade A78 PAL=true;board=A78S9 md5:877dcc97a775ed55081864b2dbf5f1e2 Alien Brigade A78 NTSC=true;board=2
md5:0a9e58ef5eb9ff93246e0fff684dc7f1 Arkanoid (0911) A78 NTSC=true;board=A7832P md5:de3e9496cb7341f865f27e5a72c7f2f5 Alien Brigade A78 PAL=true;board=2
md5:0a9e58ef5eb9ff93246e0fff684dc7f1 Arkanoid (0911) A78 NTSC=true;board=0;Pokey=true
md5:f9fb84658c5586df159a0c75cc46b54c Asteroids Deluxe A78 NTSC=true;board=0 md5:f9fb84658c5586df159a0c75cc46b54c Asteroids Deluxe A78 NTSC=true;board=0
md5:a65f79ad4a0bbdecd59d5f7eb3623fd7 Asteroids Deluxe A78 NTSC=true;board=A7832 md5:a65f79ad4a0bbdecd59d5f7eb3623fd7 Asteroids Deluxe A78 NTSC=true;board=0
md5:1baf41de200f26ec643625021290bec2 Asteroids Deluxe A78 PAL=true;board=A7832 md5:1baf41de200f26ec643625021290bec2 Asteroids Deluxe A78 PAL=true;board=0
md5:07342c78619ba6ffcc61c10e907e3b50 Asteroids A78 NTSC=true;board=0 md5:07342c78619ba6ffcc61c10e907e3b50 Asteroids A78 NTSC=true;board=0
md5:8fc3a695eaea3984912d98ed4a543376 Ballblazer A78 NTSC=true;board=A7832P md5:8fc3a695eaea3984912d98ed4a543376 Ballblazer A78 NTSC=true;board=0;Pokey=true
md5:b558814d54904ce0582e2f6a801d03af Ballblazer A78 PAL=true;board=A7832P md5:b558814d54904ce0582e2f6a801d03af Ballblazer A78 PAL=true;board=0;Pokey=true
md5:42682415906c21c6af80e4198403ffda Barnyard Blaster A78 NTSC=true;board=A78SG md5:42682415906c21c6af80e4198403ffda Barnyard Blaster A78 NTSC=true;board=1
md5:babe2bc2976688bafb8b23c192658126 Barnyard Blaster A78 PAL=true;board=A78SG md5:babe2bc2976688bafb8b23c192658126 Barnyard Blaster A78 PAL=true;board=1
md5:f5f6b69c5eb4b55fc163158d1a6b423e Basketbrawl A78 NTSC=true;board=A78SG md5:f5f6b69c5eb4b55fc163158d1a6b423e Basketbrawl A78 NTSC=true;board=1
md5:fba002089fcfa176454ab507e0eb76cb Basketbrawl A78 PAL=true;board=A78SG md5:fba002089fcfa176454ab507e0eb76cb Basketbrawl A78 PAL=true;board=1
md5:6010a398070dfacb4c0173d75d73c50a Beef Drop A78 NTSC=true;board=0 md5:6010a398070dfacb4c0173d75d73c50a Beef Drop A78 NTSC=true;board=0
md5:c534db0a062225b17cfb8ecce0fb9090 Beef Drop A78 NTSC=true;board=0 md5:c534db0a062225b17cfb8ecce0fb9090 Beef Drop A78 NTSC=true;board=0
md5:6da5b1b9fa0001e3517f6084ff651b07 Bentley Bear - Crystal Quest A78 NTSC=true;board=A78S9 md5:CE25D34071B2C798ACE4C8792EAE8E84 Beef Drop A78 NTSC=true;board=0
md5:6da5b1b9fa0001e3517f6084ff651b07 Bentley Bear - Crystal Quest A78 NTSC=true;board=2
md5:5a09946e57dbe30408a8f253a28d07db Centipede A78 NTSC=true;board=0 md5:5a09946e57dbe30408a8f253a28d07db Centipede A78 NTSC=true;board=0
md5:38c056a48472d9a9e16ebda5ed91dae7 Centipede A78 PAL=true;board=0 md5:38c056a48472d9a9e16ebda5ed91dae7 Centipede A78 PAL=true;board=0
md5:93e4387864b014c155d7c17877990d1e Choplifter! A78 NTSC=true;board=0 md5:93e4387864b014c155d7c17877990d1e Choplifter! A78 NTSC=true;board=0
md5:59d4edb0230b5acc918b94f6bc94779f Choplifter! A78 PAL=true;board=0 md5:59d4edb0230b5acc918b94f6bc94779f Choplifter! A78 PAL=true;board=0
md5:441ac404cdc7bcbd4d787f911df7bf0d Color Test A78 NTSC=true;board=0 md5:441ac404cdc7bcbd4d787f911df7bf0d Color Test A78 NTSC=true;board=0
md5:2e8e28f6ad8b9b9267d518d880c73ebb Commando A78 NTSC=true;board=A78SGP md5:2e8e28f6ad8b9b9267d518d880c73ebb Commando A78 NTSC=true;board=1;Pokey=true
md5:55da6c6c3974d013f517e725aa60f48e Commando A78 PAL=true;board=A78SGP md5:55da6c6c3974d013f517e725aa60f48e Commando A78 PAL=true;board=1;Pokey=true
md5:db691469128d9a4217ec7e315930b646 Crack'ed A78 NTSC=true;board=A78SG md5:db691469128d9a4217ec7e315930b646 Crack'ed A78 NTSC=true;board=1
md5:7cbe78fa06f47ba6516a67a4b003c9ee Crack'ed A78 PAL=true;board=A78SG md5:7cbe78fa06f47ba6516a67a4b003c9ee Crack'ed A78 PAL=true;board=1
md5:0c9b124355d5328697a3b9e0011353f2 Crazy Brix A78 NTSC=true;board=A7816 md5:0c9b124355d5328697a3b9e0011353f2 Crazy Brix A78 NTSC=true;board=0
md5:45e1d527becc96d1715e810d1c07ac27 Crazy Brix A78 NTSC=true;board=A7816 md5:45e1d527becc96d1715e810d1c07ac27 Crazy Brix A78 NTSC=true;board=0
md5:fc7db1a9243ce2140f716762b8352a5c Crazy Brix A78 PAL=true;board=A7816 md5:fc7db1a9243ce2140f716762b8352a5c Crazy Brix A78 PAL=true;board=0
md5:a94e4560b6ad053a1c24e096f1262ebf Crossbow A78 NTSC=true;board=A78S9 md5:a94e4560b6ad053a1c24e096f1262ebf Crossbow A78 NTSC=true;board=2
md5:63db371d67a98daec547b2abd5e7aa95 Crossbow A78 PAL=true;board=A78S9 md5:63db371d67a98daec547b2abd5e7aa95 Crossbow A78 PAL=true;board=2
md5:179b76ff729d4849b8f66a502398acae CDark Chambers A78 NTSC=true;board=A78SG md5:179b76ff729d4849b8f66a502398acae CDark Chambers A78 NTSC=true;board=1
md5:a2b8e2f159642c4b91de82e9a2928494 Dark Chambers A78 PAL=true;board=A78SG md5:a2b8e2f159642c4b91de82e9a2928494 Dark Chambers A78 PAL=true;board=1
md5:95ac811c7d27af0032ba090f28c107bd Desert Falcon A78 NTSC=true;board=0 md5:95ac811c7d27af0032ba090f28c107bd Desert Falcon A78 NTSC=true;board=0
md5:2d5d99b993a885b063f9f22ce5e6523d Desert Falcon A78 PAL=true;board=0 md5:2d5d99b993a885b063f9f22ce5e6523d Desert Falcon A78 PAL=true;board=0
md5:731879ea82fc0ca245e39e036fe293e6 Dig Dug A78 NTSC=true;board=0 md5:731879ea82fc0ca245e39e036fe293e6 Dig Dug A78 NTSC=true;board=0
@ -42,16 +52,16 @@ md5:5e332fbfc1e0fc74223d2e73271ce650 Donkey Kong Junior A78 NTSC=true;board=0
md5:4dc5f88243250461bd61053b13777060 Donkey Kong Junior A78 PAL=true;board=0 md5:4dc5f88243250461bd61053b13777060 Donkey Kong Junior A78 PAL=true;board=0
md5:19f1ee292a23636bd57d408b62de79c7 Donkey Kong A78 NTSC=true;board=0 md5:19f1ee292a23636bd57d408b62de79c7 Donkey Kong A78 NTSC=true;board=0
md5:8e96ef14ce9b5d84bcbc996b66d6d4c7 Donkey Kong A78 PAL=true;board=0 md5:8e96ef14ce9b5d84bcbc996b66d6d4c7 Donkey Kong A78 PAL=true;board=0
md5:de2ebafcf0e37aaa9d0e9525a7f4dd62 Double Dragon A78 PAL=true;board=A78AC md5:de2ebafcf0e37aaa9d0e9525a7f4dd62 Double Dragon A78 PAL=true;board=4
md5:543484c00ba233736bcaba2da20eeea9 Double Dragon A78 NTSC=true;board=A78AC md5:543484c00ba233736bcaba2da20eeea9 Double Dragon A78 NTSC=true;board=4
md5:2251a6a0f3aec84cc0aff66fc9fa91e8 F-18 Hornet A78 NTSC=true;board=A78AB md5:2251a6a0f3aec84cc0aff66fc9fa91e8 F-18 Hornet A78 NTSC=true;board=3
md5:e7709da8e49d3767301947a0a0b9d2e6 F-18 Hornet A78 PAL=true;board=A78AB md5:e7709da8e49d3767301947a0a0b9d2e6 F-18 Hornet A78 PAL=true;board=3
md5:6287727ab36391a62f728bbdee88675c FailSafe A78 NTSC=true;board=A7848 md5:6287727ab36391a62f728bbdee88675c FailSafe A78 NTSC=true;board=0
md5:d2bb22f704f1610a4c396c51f5188e15 FailSafe A78 NTSC=true;board=A7848 md5:d2bb22f704f1610a4c396c51f5188e15 FailSafe A78 NTSC=true;board=0
md5:d25d5d19188e9f149977c49eb0367cd1 Fatal Run A78 NTSC=true;board=A78SG md5:d25d5d19188e9f149977c49eb0367cd1 Fatal Run A78 NTSC=true;board=1
md5:23505651ac2e47f3637152066c3aa62f Fatal Run A78 PAL=true;board=A78SG md5:23505651ac2e47f3637152066c3aa62f Fatal Run A78 PAL=true;board=1
md5:e80f24e953563e6b61556737d67d3836 Fight Night A78 PAL=true;board=A78SG md5:e80f24e953563e6b61556737d67d3836 Fight Night A78 PAL=true;board=1
md5:07dbbfe612a0a28e283c01545e59f25e Fight Night A78 NTSC=true;board=A78SG md5:07dbbfe612a0a28e283c01545e59f25e Fight Night A78 NTSC=true;board=1
md5:cf76b00244105b8e03cdc37677ec1073 Food Fight A78 NTSC=true;board=0 md5:cf76b00244105b8e03cdc37677ec1073 Food Fight A78 NTSC=true;board=0
md5:de0d4f5a9bf1c1bddee3ed2f7ec51209 Food Fight A78 PAL=true;board=0 md5:de0d4f5a9bf1c1bddee3ed2f7ec51209 Food Fight A78 PAL=true;board=0
md5:45136d1d9eddf0bebad32995647b3298 Frogger Demo A78 NTSC=true;board=0 md5:45136d1d9eddf0bebad32995647b3298 Frogger Demo A78 NTSC=true;board=0
@ -60,97 +70,97 @@ md5:f5dc7dc8e38072d3d65bd90a660148ce Galaga A78 PAL=true;board=0
md5:06204dadc975be5e5e37e7cc66f984cf Gato A78 NTSC=true;board=0 md5:06204dadc975be5e5e37e7cc66f984cf Gato A78 NTSC=true;board=0
md5:0baec96787ce17f390e204de1a136e59 Hat Trick A78 PAL=true;board=0 md5:0baec96787ce17f390e204de1a136e59 Hat Trick A78 PAL=true;board=0
md5:fd9e78e201b6baafddfd3e1fbfe6ba31 Hat Trick A78 NTSC=true;board=0 md5:fd9e78e201b6baafddfd3e1fbfe6ba31 Hat Trick A78 NTSC=true;board=0
md5:c3672482ca93f70eafd9134b936c3feb Ikari Warriors A78 NTSC=true;board=A78SG md5:c3672482ca93f70eafd9134b936c3feb Ikari Warriors A78 NTSC=true;board=1
md5:8c2c2a1ea6e9a928a44c3151ba5c1ce3 Ikari Warriors A78 PAL=true;board=A78SG md5:8c2c2a1ea6e9a928a44c3151ba5c1ce3 Ikari Warriors A78 PAL=true;board=1
md5:1745feadabb24e7cefc375904c73fa4c Impossible Mission Fixed A78 NTSC=true;board=A78SGR md5:1745feadabb24e7cefc375904c73fa4c Impossible Mission Fixed A78 NTSC=true;board=1;RAM=8
md5:baebc9246c087e893dfa489632157180 Impossible Mission A78 NTSC=true;board=A78SGR md5:baebc9246c087e893dfa489632157180 Impossible Mission A78 NTSC=true;board=1;RAM=8
md5:80dead01ea2db5045f6f4443faa6fce8 Impossible Mission A78 PAL=true;board=A78SGR md5:80dead01ea2db5045f6f4443faa6fce8 Impossible Mission A78 PAL=true;board=1;RAM=8
md5:045fd12050b7f2b842d5970f2414e912 Jinks A78 NTSC=true;board=A78SGR md5:045fd12050b7f2b842d5970f2414e912 Jinks A78 NTSC=true;board=1;RAM=8
md5:dfb86f4d06f05ad00cf418f0a59a24f7 Jinks A78 PAL=true;board=A78SGR md5:dfb86f4d06f05ad00cf418f0a59a24f7 Jinks A78 PAL=true;board=1;RAM=8
md5:f18b3b897a25ab3885b43b4bd141b396 Joust A78 NTSC=true;board=0 md5:f18b3b897a25ab3885b43b4bd141b396 Joust A78 NTSC=true;board=0
md5:f2dae0264a4b4a73762b9d7177e989f6 Joust A78 PAL=true;board=0 md5:f2dae0264a4b4a73762b9d7177e989f6 Joust A78 PAL=true;board=0
md5:548ba2e54e4fc45ab84ed634d702c136 Jr. Ms. Pac-Man A78 NTSC=true;board=A7832P md5:548ba2e54e4fc45ab84ed634d702c136 Jr. Ms. Pac-Man A78 NTSC=true;board=0;Pokey=true
md5:6bc2daeb48e28d103a4298a276e7e551 Jr. Pac-Man (Tunnels) A78 NTSC=true;board=A7832P md5:6bc2daeb48e28d103a4298a276e7e551 Jr. Pac-Man (Tunnels) A78 NTSC=true;board=0;Pokey=true
md5:0b3baf47886915dd2eec5da7671bfa63 Jr. Pac-Man A78 NTSC=true;board=A78SGR md5:0b3baf47886915dd2eec5da7671bfa63 Jr. Pac-Man A78 NTSC=true;board=1;RAM=8
md5:8281ab17fa3bfc0a6c497d6a4f350061 Jr. Pac-Man A78 NTSC=true;board=A78SGR md5:8281ab17fa3bfc0a6c497d6a4f350061 Jr. Pac-Man A78 NTSC=true;board=1;RAM=8
md5:17b3b764d33eae9b5260f01df7bb9d2f KLAX A78 NTSC=true;board=A78SG md5:17b3b764d33eae9b5260f01df7bb9d2f KLAX A78 NTSC=true;board=1
md5:5e0a1e832bbcea6facb832fde23a440a Karateka A78 PAL=true;board=A78S4 md5:5e0a1e832bbcea6facb832fde23a440a Karateka A78 PAL=true;board=1
md5:c3a5a8692a423d43d9d28dd5b7d109d9 Karateka A78 NTSC=true;board=0 md5:c3a5a8692a423d43d9d28dd5b7d109d9 Karateka A78 NTSC=true;board=0
md5:f57d0af323d4e173fb49ed447f0563d7 Kung-Fu Master A78 NTSC=true;board=0 md5:f57d0af323d4e173fb49ed447f0563d7 Kung-Fu Master A78 NTSC=true;board=0
md5:2931b75811ad03f3ac9330838f3d231b Kung-Fu Master A78 PAL=true;board=0 md5:2931b75811ad03f3ac9330838f3d231b Kung-Fu Master A78 PAL=true;board=0
md5:431ca060201ee1f9eb49d44962874049 Mario Bros. A78 NTSC=true;board=0 md5:431ca060201ee1f9eb49d44962874049 Mario Bros. A78 NTSC=true;board=0
md5:d2e861306be78e44248bb71d7475d8a3 Mario Bros. A78 PAL=true;board=0 md5:d2e861306be78e44248bb71d7475d8a3 Mario Bros. A78 PAL=true;board=0
md5:37b5692e33a98115e574185fa8398c22 Mat Mania Challenge A78 NTSC=true;board=A78SG md5:37b5692e33a98115e574185fa8398c22 Mat Mania Challenge A78 NTSC=true;board=1
md5:6819c37b96063b024898a19dbae2df54 Mat Mania Challenge A78 PAL=true;board=A78SG md5:6819c37b96063b024898a19dbae2df54 Mat Mania Challenge A78 PAL=true;board=1
md5:f2f5e5841e4dda89a2faf8933dc33ea6 Mean 18 Ultimate Golf A78 NTSC=true;board=A78SG md5:f2f5e5841e4dda89a2faf8933dc33ea6 Mean 18 Ultimate Golf A78 NTSC=true;board=1
md5:2e9dbad6c0fa381a6cd1bb9abf98a104 Mean 18 Ultimate Golf A78 PAL=true;board=A78SG md5:2e9dbad6c0fa381a6cd1bb9abf98a104 Mean 18 Ultimate Golf A78 PAL=true;board=1
md5:bedc30ec43587e0c98fc38c39c1ef9d0 Meltdown A78 NTSC=true;board=A78SG md5:bedc30ec43587e0c98fc38c39c1ef9d0 Meltdown A78 NTSC=true;board=1
md5:c80155d7eec9e3dcb79aa6b83c9ccd1e Meltdown A78 PAL=true;board=A78SG md5:c80155d7eec9e3dcb79aa6b83c9ccd1e Meltdown A78 PAL=true;board=1
md5:b02f93661f4b7e712810d2bf8e02ad79 Meteor Shower A78 NTSC=true;board=A7816 md5:b02f93661f4b7e712810d2bf8e02ad79 Meteor Shower A78 NTSC=true;board=0
md5:2f1f199ecc2b414d28e01f0de53ca8f7 Meteor Shower A78 PAL=true;board=A7816 md5:2f1f199ecc2b414d28e01f0de53ca8f7 Meteor Shower A78 PAL=true;board=0
md5:bc1e905db1008493a9632aa83ab4682b Midnight Mutants A78 NTSC=true;board=A78SG md5:bc1e905db1008493a9632aa83ab4682b Midnight Mutants A78 NTSC=true;board=1
md5:6794ea31570eba0b88a0bf1ead3f3f1b Midnight Mutants A78 PAL=true;board=A78SG md5:6794ea31570eba0b88a0bf1ead3f3f1b Midnight Mutants A78 PAL=true;board=1
md5:017066f522908081ec3ee624f5e4a8aa Missing in Action A78 NTSC=true;board=A78S9 md5:017066f522908081ec3ee624f5e4a8aa Missing in Action A78 NTSC=true;board=2
md5:d0f46bf92ed6e7b1cce63278420cae8a Missing in Action A78 NTSC=true;board=A78S9 md5:d0f46bf92ed6e7b1cce63278420cae8a Missing in Action A78 NTSC=true;board=2
md5:9ff38ea62004201d870caa8bd9463525 Moon Cresta A78 NTSC=true;board=A7832 md5:9ff38ea62004201d870caa8bd9463525 Moon Cresta A78 NTSC=true;board=0
md5:3bc8f554cf86f8132a623cc2201a564b Motor Psycho A78 NTSC=true;board=A78SG md5:3bc8f554cf86f8132a623cc2201a564b Motor Psycho A78 NTSC=true;board=1
md5:5330bfe428a6b601b7e76c2cfc4cd049 Motor Psycho A78 PAL=true;board=A78SG md5:5330bfe428a6b601b7e76c2cfc4cd049 Motor Psycho A78 PAL=true;board=1
md5:fc0ea52a9fac557251b65ee680d951e5 Ms. Pac-Man A78 NTSC=true;board=0 md5:fc0ea52a9fac557251b65ee680d951e5 Ms. Pac-Man A78 NTSC=true;board=0
md5:56469e8c5ff8983c6cb8dadc64eb0363 Ms. Pac-Man A78 PAL=true;board=0 md5:56469e8c5ff8983c6cb8dadc64eb0363 Ms. Pac-Man A78 PAL=true;board=0
md5:220121f771fc4b98cef97dc040e8d378 Ninja Golf A78 NTSC=true;board=A78SG md5:220121f771fc4b98cef97dc040e8d378 Ninja Golf A78 NTSC=true;board=1
md5:ea0c859aa54fe5eaf4c1f327fab06221 Ninja Golf A78 PAL=true;board=A78SG md5:ea0c859aa54fe5eaf4c1f327fab06221 Ninja Golf A78 PAL=true;board=1
md5:74569571a208f8b0b1ccfb22d7c914e1 One on One Basketball A78 NTSC=true;board=0 md5:74569571a208f8b0b1ccfb22d7c914e1 One on One Basketball A78 NTSC=true;board=0
md5:8dba0425f0262e5704581d8757a1a6e3 One on One Basketball A78 PAL=true;board=0 md5:8dba0425f0262e5704581d8757a1a6e3 One on One Basketball A78 PAL=true;board=0
md5:5d7bc7092de69095137456733e7b685d Pac-Man Collection A78 NTSC=true;board=0 md5:5d7bc7092de69095137456733e7b685d Pac-Man Collection A78 NTSC=true;board=0
md5:90223a8a363bdf643a19d0f97e63b1b2 PacArcade A78 NTSC=true;board=A7816 md5:90223a8a363bdf643a19d0f97e63b1b2 PacArcade A78 NTSC=true;board=0
md5:386bded4a944bae455fedf56206dd1dd Pete Rose Baseball A78 PAL=true;board=0 md5:386bded4a944bae455fedf56206dd1dd Pete Rose Baseball A78 PAL=true;board=0
md5:1a5207870dec6fae9111cb747e20d8e3 Pete Rose Baseball A78 NTSC=true;board=0 md5:1a5207870dec6fae9111cb747e20d8e3 Pete Rose Baseball A78 NTSC=true;board=0
md5:05f43244465943ce819780a71a5b572a Pitfighter A78 NTSC=true;board=A78S4 md5:05f43244465943ce819780a71a5b572a Pitfighter A78 NTSC=true;board=1
md5:33aea1e2b6634a1dec8c7006d9afda22 Planet Smashers A78 NTSC=true;board=A78SG md5:33aea1e2b6634a1dec8c7006d9afda22 Planet Smashers A78 NTSC=true;board=1
md5:2837a8fd49b7fc7ccd70fd45b69c5099 Planet Smashers A78 PAL=true;board=A78SG md5:2837a8fd49b7fc7ccd70fd45b69c5099 Planet Smashers A78 PAL=true;board=1
md5:86546808dc60961cdb1b20e761c50ab1 Plutos A78 NTSC=true;board=A78SGR md5:86546808dc60961cdb1b20e761c50ab1 Plutos A78 NTSC=true;board=1;RAM=8
md5:584582bb09ee8122e7fc09dc7d1ed813 Pole Position II A78 NTSC=true;board=0 md5:584582bb09ee8122e7fc09dc7d1ed813 Pole Position II A78 NTSC=true;board=0
md5:865457e0e0f48253b08f77b9e18f93b2 Pole Position II A78 PAL=true;board=0 md5:865457e0e0f48253b08f77b9e18f93b2 Pole Position II A78 PAL=true;board=0
md5:66e7230f7ef9d14db82d76b06b241bc0 Q-bert A78 NTSC=true;board=A7832 md5:66e7230f7ef9d14db82d76b06b241bc0 Q-bert A78 NTSC=true;board=0
md5:ac03806cef2558fc795a7d5d8dba7bc0 Rampage A78 NTSC=true;board=A78AC md5:ac03806cef2558fc795a7d5d8dba7bc0 Rampage A78 NTSC=true;board=4
md5:383ed9bd1efb9b6cb3388a777678c928 Realsports Baseball A78 NTSC=true;board=A78S4 md5:383ed9bd1efb9b6cb3388a777678c928 Realsports Baseball A78 NTSC=true;board=1
md5:8f7eb10ad0bd75474abf0c6c36c08486 Rescue on Fractalus A78 NTSC=true;board=A7832 md5:8f7eb10ad0bd75474abf0c6c36c08486 Rescue on Fractalus A78 NTSC=true;board=0
md5:43525a0405184875c2ecfd0196886a34 Rip Off A78 NTSC=true;board=A7816 md5:43525a0405184875c2ecfd0196886a34 Rip Off A78 NTSC=true;board=0
md5:106b409c6f4c219b1a3b3d099ead3b2b Rip Off A78 PAL=true;board=0A7816 md5:106b409c6f4c219b1a3b3d099ead3b2b Rip Off A78 PAL=true;board=0
md5:505f05e7f161f62ccd749dab3c4a204b Robot Finds Kitten A78 NTSC=true;board=A7832 md5:505f05e7f161f62ccd749dab3c4a204b Robot Finds Kitten A78 NTSC=true;board=0
md5:66ecaafe1b82ae68ffc96267aaf7a4d7 Robotron 2084 A78 NTSC=true;board=0 md5:66ecaafe1b82ae68ffc96267aaf7a4d7 Robotron 2084 A78 NTSC=true;board=0
md5:ae85689b21bdf85cb9dc57c3b1fec9db Santa Simon A78 NTSC=true;board=A7848 md5:ae85689b21bdf85cb9dc57c3b1fec9db Santa Simon A78 NTSC=true;board=0
md5:57651b6c8e62811fab0361cea537b79c Scramble A78 NTSC=true;board=0 md5:57651b6c8e62811fab0361cea537b79c Scramble A78 NTSC=true;board=0
md5:c265cfd65534a4514f226cb4c7f7d6bf Scramble A78 NTSC=true;board=0 md5:c265cfd65534a4514f226cb4c7f7d6bf Scramble A78 NTSC=true;board=0
md5:1ee26fc6b06b4c9ba74931914b7e719d Scramble A78 PAL=true;board=0 md5:1ee26fc6b06b4c9ba74931914b7e719d Scramble A78 PAL=true;board=0
md5:65fe82f419f6583a0f9a736242cb303d Scramble A78 PAL=true;board=0 md5:65fe82f419f6583a0f9a736242cb303d Scramble A78 PAL=true;board=0
md5:980c35ae9625773a450aa7ef51751c04 Scrapyard Dog A78 NTSC=true;board=A78SG md5:980c35ae9625773a450aa7ef51751c04 Scrapyard Dog A78 NTSC=true;board=1
md5:53db322c201323fe2ca8f074c0a2bf86 Scrapyard Dog A78 PAL=true;board=A78SG md5:53db322c201323fe2ca8f074c0a2bf86 Scrapyard Dog A78 PAL=true;board=1
md5:b697d9c2d1b9f6cb21041286d1bbfa7f Sentinel A78 NTSC=true;board=A78SG md5:b697d9c2d1b9f6cb21041286d1bbfa7f Sentinel A78 NTSC=true;board=1;Pokey=true
md5:5469b4de0608f23a5c4f98f331c9e75f Sentinel A78 PAL=true;board=A78SG md5:5469b4de0608f23a5c4f98f331c9e75f Sentinel A78 PAL=true;board=1;Pokey=true
md5:2d643ac548c40e58c99d0fe433ba4ba0 Sirius A78 NTSC=true;board=A78SGR md5:2d643ac548c40e58c99d0fe433ba4ba0 Sirius A78 NTSC=true;board=1;RAM=8
md5:a84c1b2300fbfbf21b1c02387f613dad Space Duel A78 PAL=true;board=0 md5:a84c1b2300fbfbf21b1c02387f613dad Space Duel A78 PAL=true;board=0
md5:771cb4609347657f63e6f0eb26036e35 Space Duel A78 NTSC=true;board=A7832 md5:771cb4609347657f63e6f0eb26036e35 Space Duel A78 NTSC=true;board=0
md5:6adf79558a3d7f5beca1bb8d34337417 Space Invaders A78 NTSC=true;board=0 md5:6adf79558a3d7f5beca1bb8d34337417 Space Invaders A78 NTSC=true;board=0
md5:cbb0746192540a13b4c7775c7ce2021f Summer Games A78 NTSC=true;board=A78SGR md5:cbb0746192540a13b4c7775c7ce2021f Summer Games A78 NTSC=true;board=1;RAM=16
md5:cc18e3b37a507c4217eb6cb1de8c8538 Super Huey UH-IX A78 NTSC=true;board=0 md5:cc18e3b37a507c4217eb6cb1de8c8538 Super Huey UH-IX A78 NTSC=true;board=0
md5:162f9c953f0657689cc74ab20b40280f Super Huey UH-IX A78 PAL=true;board=0 md5:162f9c953f0657689cc74ab20b40280f Super Huey UH-IX A78 PAL=true;board=0
md5:59b5793bece1c80f77b55d60fb39cb94 Super Skateboardin' A78 NTSC=true;board=0 md5:59b5793bece1c80f77b55d60fb39cb94 Super Skateboardin' A78 NTSC=true;board=0
md5:95d7c321dce8f57623a9c5b4947bb375 Super Skateboardin' A78 PAL=true;board=0 md5:95d7c321dce8f57623a9c5b4947bb375 Super Skateboardin' A78 PAL=true;board=0
md5:5c4f752371a523f15e9980fea73b874d Tank Command A78 NTSC=true;board=A78S4 md5:5c4f752371a523f15e9980fea73b874d Tank Command A78 NTSC=true;board=1
md5:3bb9c8d9adc912dd7f8471c97445cd8d Titlematch Pro Wrestling A78 PAL=true;board=0 md5:3bb9c8d9adc912dd7f8471c97445cd8d Titlematch Pro Wrestling A78 PAL=true;board=0
md5:1af475ff6429a160752b592f0f92b287 Titlematch Pro Wrestling A78 NTSC=true;board=0 md5:1af475ff6429a160752b592f0f92b287 Titlematch Pro Wrestling A78 NTSC=true;board=0
md5:c3903ab01a51222a52197dbfe6538ecf Tomcat F14 A78 NTSC=true;board=0 md5:c3903ab01a51222a52197dbfe6538ecf Tomcat F14 A78 NTSC=true;board=0
md5:682338364243b023ecc9d24f0abfc9a7 Tomcat F14 A78 PAL=true;board=0 md5:682338364243b023ecc9d24f0abfc9a7 Tomcat F14 A78 PAL=true;board=0
md5:208ef955fa90a29815eb097bce89bace Touchdown Football A78 NTSC=true;board=A78SG md5:208ef955fa90a29815eb097bce89bace Touchdown Football A78 NTSC=true;board=1
md5:8d64763db3100aadc552db5e6868506a Tower Toppler A78 NTSC=true;board=A78S4R md5:8d64763db3100aadc552db5e6868506a Tower Toppler A78 NTSC=true;board=1;RAM=8
md5:32a37244a9c6cc928dcdf02b45365aa8 Tower Toppler A78 PAL=true;board=A78S4R md5:32a37244a9c6cc928dcdf02b45365aa8 Tower Toppler A78 PAL=true;board=1;RAM=8
md5:412cc5bfa08bd03244b9c4e8d46cd0a0 Wasp (Standard Edition) A78 NTSC=true;board=A7832 md5:412cc5bfa08bd03244b9c4e8d46cd0a0 Wasp (Standard Edition) A78 NTSC=true;board=0
md5:427cb05d0a1abb068998e2760d77f4fb Water Ski A78 NTSC=true;board=A78S4 md5:427cb05d0a1abb068998e2760d77f4fb Water Ski A78 NTSC=true;board=1
md5:3799d72f78dda2ee87b0ef8bf7b91186 Winter Games A78 NTSC=true;board=A78SGR md5:3799d72f78dda2ee87b0ef8bf7b91186 Winter Games A78 NTSC=true;board=1;RAM=16
md5:6813ffff510f930c867b3f0aba78ac85 Worm (0703) A78 NTSC=true;board=A7816 md5:6813ffff510f930c867b3f0aba78ac85 Worm (0703) A78 NTSC=true;board=0
md5:05fb699db9eef564e2fe45c568746dbc Xenophobe A78 NTSC=true;board=A78SG md5:05fb699db9eef564e2fe45c568746dbc Xenophobe A78 NTSC=true;board=1
md5:70937c3184f0be33d06f7f4382ca54de Xenophobe A78 PAL=true;board=A78SG md5:70937c3184f0be33d06f7f4382ca54de Xenophobe A78 PAL=true;board=1
md5:d7dc17379aa25e5ae3c14b9e780c6f6d Xevious A78 NTSC=true;board=0 md5:d7dc17379aa25e5ae3c14b9e780c6f6d Xevious A78 NTSC=true;board=0
md5:b1a9f196ce5f47ca8caf8fa7bc4ca46c Xevious A78 PAL=true;board=0 md5:b1a9f196ce5f47ca8caf8fa7bc4ca46c Xevious A78 PAL=true;board=0
md5:ce6fbdc7b037a4efdaf87267f5f292cc b*nQ A78 NTSC=true;board=0 md5:ce6fbdc7b037a4efdaf87267f5f292cc b*nQ A78 NTSC=true;board=0

View File

@ -134,6 +134,9 @@ namespace BizHawk.Client.Common
return path; return path;
} }
if (Path.IsPathRooted(path))
return path;
//handling of initial .. was removed (Path.GetFullPath can handle it) //handling of initial .. was removed (Path.GetFullPath can handle it)
//handling of file:// or file:\\ was removed (can Path.GetFullPath handle it? not sure) //handling of file:// or file:\\ was removed (can Path.GetFullPath handle it? not sure)

View File

@ -44,7 +44,7 @@ namespace BizHawk.Client.Common
// assume we have a header of that size. Otherwise, assume it's just all rom. // assume we have a header of that size. Otherwise, assume it's just all rom.
// Other 'recognized' header sizes may need to be added. // Other 'recognized' header sizes may need to be added.
int headerOffset = fileLength % BankSize; int headerOffset = fileLength % BankSize;
if (headerOffset.In(0, 512) == false) if (headerOffset.In(0, 128, 512) == false)
{ {
Console.WriteLine("ROM was not a multiple of 1024 bytes, and not a recognized header size: {0}. Assume it's purely ROM data.", headerOffset); Console.WriteLine("ROM was not a multiple of 1024 bytes, and not a recognized header size: {0}. Assume it's purely ROM data.", headerOffset);
headerOffset = 0; headerOffset = 0;
@ -87,6 +87,13 @@ namespace BizHawk.Client.Common
// note: this will be taking several hashes, of a potentially large amount of data.. yikes! // note: this will be taking several hashes, of a potentially large amount of data.. yikes!
GameInfo = Database.GetGameInfo(RomData, file.Name); GameInfo = Database.GetGameInfo(RomData, file.Name);
if (GameInfo.NotInDatabase && headerOffset==128 && file.Extension == ".A78")
{
// if the game is not in the DB, add the header back in so the core can use it
// for now only .A78 games, but probably should be for other systems as well
RomData = FileData;
}
CheckForPatchOptions(); CheckForPatchOptions();
if (patch != null) if (patch != null)

View File

@ -554,7 +554,7 @@ namespace BizHawk.Client.Common
switch (game.System) switch (game.System)
{ {
case "GEN": case "GEN":
var genesis = new GPGX(nextComm, null, disc, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>()); var genesis = new GPGX(nextComm, null, new[] { disc }, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>());
nextEmulator = genesis; nextEmulator = genesis;
break; break;
case "SAT": case "SAT":
@ -729,6 +729,15 @@ namespace BizHawk.Client.Common
nextEmulator = new Tst(nextComm, pcfxDiscs, nextEmulator = new Tst(nextComm, pcfxDiscs,
(Tst.Settings)GetCoreSettings<Tst>(), (Tst.SyncSettings)GetCoreSyncSettings<Tst>()); (Tst.Settings)GetCoreSettings<Tst>(), (Tst.SyncSettings)GetCoreSyncSettings<Tst>());
break; break;
case "GEN":
// We are assuming discs only, for now
var genDiscs = DiscsFromXml(xmlGame, "GEN", DiscType.MegaCD);
if (!genDiscs.Any())
{
return false;
}
nextEmulator = new GPGX(nextComm, null, genDiscs, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>());
break;
default: default:
return false; return false;
} }
@ -911,7 +920,6 @@ namespace BizHawk.Client.Common
case "GBC": case "GBC":
if (!Global.Config.GB_AsSGB) if (!Global.Config.GB_AsSGB)
{ {
//core = CoreInventory.Instance["GB", "Pizza Boy"];
core = CoreInventory.Instance["GB", "Gambatte"]; core = CoreInventory.Instance["GB", "Gambatte"];
} }
else else
@ -925,7 +933,7 @@ namespace BizHawk.Client.Common
} }
else else
{ {
core = CoreInventory.Instance["SGB", "Pizza Boy"]; core = CoreInventory.Instance["SGB", "SameBoy"];
} }
} }
break; break;
@ -940,7 +948,7 @@ namespace BizHawk.Client.Common
{ {
nextEmulator = Global.Config.A78_UseEmu7800 nextEmulator = Global.Config.A78_UseEmu7800
? nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath) ? nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath)
: nextEmulator = new A7800Hawk(nextComm, game, rom.RomData, gamedbpath); : nextEmulator = new A7800Hawk(nextComm, game, rom.RomData, gamedbpath, GetCoreSettings<A7800Hawk>(), GetCoreSyncSettings<A7800Hawk>());
} }
break; break;

View File

@ -49,7 +49,7 @@
public void Stop() public void Stop()
{ {
State = RunState.Disabled; State = RunState.Disabled;
if(NLua.Lua.WhichLua == "NLua") //if(NLua.Lua.WhichLua == "NLua")
Thread.GetTable("keepalives")[Thread] = null; Thread.GetTable("keepalives")[Thread] = null;
Thread = null; Thread = null;
} }

View File

@ -20,6 +20,7 @@ namespace BizHawk.Client.EmuHawk
public HashSet<int> _currAviWriterFrameList; public HashSet<int> _currAviWriterFrameList;
public int _autoDumpLength; public int _autoDumpLength;
public bool _autoCloseOnDump = false; public bool _autoCloseOnDump = false;
// chrome is never shown, even in windowed mode
public bool _chromeless = false; public bool _chromeless = false;
public bool startFullscreen = false; public bool startFullscreen = false;
public string luaScript = null; public string luaScript = null;

View File

@ -54,9 +54,10 @@ namespace BizHawk.Client.EmuHawk
public uint dwDrawStage; public uint dwDrawStage;
public IntPtr Hdc; public IntPtr Hdc;
public RECT Rect; public RECT Rect;
public int dwItemSpec; public IntPtr dwItemSpec;
public uint ItemState; public uint ItemState;
public int lItemlParam; private int _pad64bits;
public IntPtr lItemlParam;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
@ -596,7 +597,7 @@ namespace BizHawk.Client.EmuHawk
if (QueryItemBkColor != null) if (QueryItemBkColor != null)
{ {
var color = Color.FromArgb(cd.ClearTextBackground & 0xFF, (cd.ClearTextBackground >> 8) & 0xFF, (cd.ClearTextBackground >> 16) & 0xFF); var color = Color.FromArgb(cd.ClearTextBackground & 0xFF, (cd.ClearTextBackground >> 8) & 0xFF, (cd.ClearTextBackground >> 16) & 0xFF);
QueryItemBkColor(cd.Nmcd.dwItemSpec, cd.SubItem, ref color); QueryItemBkColor(cd.Nmcd.dwItemSpec.ToInt32(), cd.SubItem, ref color);
cd.ClearTextBackground = (color.B << 16) | (color.G << 8) | color.R; cd.ClearTextBackground = (color.B << 16) | (color.G << 8) | color.R;
Marshal.StructureToPtr(cd, m.LParam, false); Marshal.StructureToPtr(cd, m.LParam, false);
} }

View File

@ -176,7 +176,9 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions
public static DialogResult ShowHawkDialog(this CommonDialog form) public static DialogResult ShowHawkDialog(this CommonDialog form)
{ {
GlobalWin.Sound.StopSound(); GlobalWin.Sound.StopSound();
var result = form.ShowDialog(new Form() { TopMost = true }); var tempForm = new Form() { TopMost = true };
var result = form.ShowDialog(tempForm);
tempForm.Dispose();
GlobalWin.Sound.StartSound(); GlobalWin.Sound.StartSound();
return result; return result;
} }

View File

@ -180,8 +180,8 @@ namespace BizHawk.Client.EmuHawk
void InitializeButtons() void InitializeButtons()
{ {
const int dzp = 9000; const int dzp = 20000;
const int dzn = -9000; const int dzn = -20000;
const int dzt = 40; const int dzt = 40;
AddItem("A", () => (state.Gamepad.wButtons & (ushort)GamepadButtonFlags.A) != 0); AddItem("A", () => (state.Gamepad.wButtons & (ushort)GamepadButtonFlags.A) != 0);

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@ using BizHawk.Client.EmuHawk.ToolExtensions;
using BizHawk.Emulation.Cores.Computers.AppleII; using BizHawk.Emulation.Cores.Computers.AppleII;
using BizHawk.Client.ApiHawk; using BizHawk.Client.ApiHawk;
using BizHawk.Emulation.Cores.Computers.Commodore64; using BizHawk.Emulation.Cores.Computers.Commodore64;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
@ -1257,7 +1258,7 @@ namespace BizHawk.Client.EmuHawk
private void SGBCoreSubmenu_DropDownOpened(object sender, EventArgs e) private void SGBCoreSubmenu_DropDownOpened(object sender, EventArgs e)
{ {
SgbBsnesMenuItem.Checked = Global.Config.SGB_UseBsnes; SgbBsnesMenuItem.Checked = Global.Config.SGB_UseBsnes;
SgbPizzaBoyMenuItem.Checked = !Global.Config.SGB_UseBsnes; SgbSameBoyMenuItem.Checked = !Global.Config.SGB_UseBsnes;
} }
private void SgbCorePick_Click(object sender, EventArgs e) private void SgbCorePick_Click(object sender, EventArgs e)
@ -1270,7 +1271,6 @@ namespace BizHawk.Client.EmuHawk
} }
} }
private void GbInSgbMenuItem_Click(object sender, EventArgs e) private void GbInSgbMenuItem_Click(object sender, EventArgs e)
{ {
Global.Config.GB_AsSGB ^= true; Global.Config.GB_AsSGB ^= true;
@ -2001,9 +2001,16 @@ namespace BizHawk.Client.EmuHawk
} }
private void GBCoreSettingsMenuItem_Click(object sender, EventArgs e) private void GBCoreSettingsMenuItem_Click(object sender, EventArgs e)
{
if (Global.Emulator is Gameboy)
{ {
GBPrefs.DoGBPrefsDialog(this); GBPrefs.DoGBPrefsDialog(this);
} }
else // sameboy
{
GenericCoreConfig.DoDialog(this, "Gameboy Settings");
}
}
private void LoadGbInSgbMenuItem_Click(object sender, EventArgs e) private void LoadGbInSgbMenuItem_Click(object sender, EventArgs e)
{ {
@ -2430,7 +2437,7 @@ namespace BizHawk.Client.EmuHawk
showMenuVisible = true; // need to always be able to restore this as an emergency measure showMenuVisible = true; // need to always be able to restore this as an emergency measure
} }
if (_chromeless) if (argParse._chromeless)
{ {
showMenuVisible = true; // I decided this was always possible in chromeless mode, we'll see what they think showMenuVisible = true; // I decided this was always possible in chromeless mode, we'll see what they think
} }

View File

@ -33,6 +33,7 @@ using BizHawk.Emulation.Common.Base_Implementations;
using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.Nintendo.SNES9X;
using BizHawk.Emulation.Cores.Consoles.SNK; using BizHawk.Emulation.Cores.Consoles.SNK;
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive; using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
@ -153,7 +154,6 @@ namespace BizHawk.Client.EmuHawk
} }
}; };
ArgParser argParse = new ArgParser();
argParse.parseArguments(args); argParse.parseArguments(args);
Database.LoadDatabase(Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb.txt")); Database.LoadDatabase(Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb.txt"));
@ -299,9 +299,9 @@ namespace BizHawk.Client.EmuHawk
Global.MovieSession.ReadOnly = true; Global.MovieSession.ReadOnly = true;
// if user is dumping and didnt supply dump length, make it as long as the loaded movie // if user is dumping and didnt supply dump length, make it as long as the loaded movie
if (_autoDumpLength == 0) if (argParse._autoDumpLength == 0)
{ {
_autoDumpLength = movie.InputLogLength; argParse._autoDumpLength = movie.InputLogLength;
} }
// Copy pasta from drag & drop // Copy pasta from drag & drop
@ -1022,15 +1022,15 @@ namespace BizHawk.Client.EmuHawk
{ {
// TODO - maybe apply a hack tracked during fullscreen here to override it // TODO - maybe apply a hack tracked during fullscreen here to override it
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
MainMenuStrip.Visible = Global.Config.DispChrome_MenuFullscreen && !_chromeless; MainMenuStrip.Visible = Global.Config.DispChrome_MenuFullscreen && !argParse._chromeless;
MainStatusBar.Visible = Global.Config.DispChrome_StatusBarFullscreen && !_chromeless; MainStatusBar.Visible = Global.Config.DispChrome_StatusBarFullscreen && !argParse._chromeless;
} }
else else
{ {
MainStatusBar.Visible = Global.Config.DispChrome_StatusBarWindowed && !_chromeless; MainStatusBar.Visible = Global.Config.DispChrome_StatusBarWindowed && !argParse._chromeless;
MainMenuStrip.Visible = Global.Config.DispChrome_MenuWindowed && !_chromeless; MainMenuStrip.Visible = Global.Config.DispChrome_MenuWindowed && !argParse._chromeless;
MaximizeBox = MinimizeBox = Global.Config.DispChrome_CaptionWindowed && !_chromeless; MaximizeBox = MinimizeBox = Global.Config.DispChrome_CaptionWindowed && !argParse._chromeless;
if (Global.Config.DispChrome_FrameWindowed == 0 || _chromeless) if (Global.Config.DispChrome_FrameWindowed == 0 || argParse._chromeless)
{ {
FormBorderStyle = FormBorderStyle.None; FormBorderStyle = FormBorderStyle.None;
} }
@ -1356,7 +1356,6 @@ namespace BizHawk.Client.EmuHawk
// AVI/WAV state // AVI/WAV state
private IVideoWriter _currAviWriter; private IVideoWriter _currAviWriter;
private readonly HashSet<int> _currAviWriterFrameList;
private AutofireController _autofireNullControls; private AutofireController _autofireNullControls;
@ -1399,13 +1398,9 @@ namespace BizHawk.Client.EmuHawk
private Point _windowedLocation; private Point _windowedLocation;
private bool _needsFullscreenOnLoad; private bool _needsFullscreenOnLoad;
private int _autoDumpLength;
private readonly bool _autoCloseOnDump;
private int _lastOpenRomFilter; private int _lastOpenRomFilter;
// chrome is never shown, even in windowed mode private ArgParser argParse = new ArgParser();
private readonly bool _chromeless;
// Resources // Resources
private Bitmap _statusBarDiskLightOnImage; private Bitmap _statusBarDiskLightOnImage;
private Bitmap _statusBarDiskLightOffImage; private Bitmap _statusBarDiskLightOffImage;
@ -1472,7 +1467,7 @@ namespace BizHawk.Client.EmuHawk
} }
} }
if (!Global.Config.DispChrome_CaptionWindowed || _chromeless) if (!Global.Config.DispChrome_CaptionWindowed || argParse._chromeless)
{ {
str = ""; str = "";
} }
@ -1695,10 +1690,7 @@ namespace BizHawk.Client.EmuHawk
switch (system) switch (system)
{ {
case "GEN": case "GEN":
if (!(Emulator is PicoDrive)) // Currently PicoDrive doesn't support anything in this menu
{
GenesisSubMenu.Visible = true; GenesisSubMenu.Visible = true;
}
break; break;
case "TI83": case "TI83":
TI83SubMenu.Visible = true; TI83SubMenu.Visible = true;
@ -1750,6 +1742,10 @@ namespace BizHawk.Client.EmuHawk
{ {
sNESToolStripMenuItem.Visible = true; sNESToolStripMenuItem.Visible = true;
} }
else if (Emulator is Sameboy)
{
GBSubMenu.Visible = true;
}
break; break;
case "Coleco": case "Coleco":
ColecoSubMenu.Visible = true; ColecoSubMenu.Visible = true;
@ -3272,9 +3268,9 @@ namespace BizHawk.Client.EmuHawk
try try
{ {
// is this the best time to handle this? or deeper inside? // is this the best time to handle this? or deeper inside?
if (_currAviWriterFrameList != null) if (argParse._currAviWriterFrameList != null)
{ {
if (!_currAviWriterFrameList.Contains(Emulator.Frame)) if (!argParse._currAviWriterFrameList.Contains(Emulator.Frame))
{ {
goto HANDLE_AUTODUMP; goto HANDLE_AUTODUMP;
} }
@ -3357,13 +3353,13 @@ namespace BizHawk.Client.EmuHawk
} }
HANDLE_AUTODUMP: HANDLE_AUTODUMP:
if (_autoDumpLength > 0) if (argParse._autoDumpLength > 0)
{ {
_autoDumpLength--; argParse._autoDumpLength--;
if (_autoDumpLength == 0) // finish if (argParse._autoDumpLength == 0) // finish
{ {
StopAv(); StopAv();
if (_autoCloseOnDump) if (argParse._autoCloseOnDump)
{ {
_exit = true; _exit = true;
} }

View File

@ -31,13 +31,14 @@
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PCEControllerConfig)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PCEControllerConfig));
this.CancelBtn = new System.Windows.Forms.Button(); this.CancelBtn = new System.Windows.Forms.Button();
this.OkBtn = new System.Windows.Forms.Button(); this.OkBtn = new System.Windows.Forms.Button();
this.ControllerPropertyGrid = new System.Windows.Forms.PropertyGrid();
this.SuspendLayout(); this.SuspendLayout();
// //
// CancelBtn // CancelBtn
// //
this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.CancelBtn.Location = new System.Drawing.Point(235, 145); this.CancelBtn.Location = new System.Drawing.Point(235, 203);
this.CancelBtn.Name = "CancelBtn"; this.CancelBtn.Name = "CancelBtn";
this.CancelBtn.Size = new System.Drawing.Size(60, 23); this.CancelBtn.Size = new System.Drawing.Size(60, 23);
this.CancelBtn.TabIndex = 3; this.CancelBtn.TabIndex = 3;
@ -48,7 +49,7 @@
// OkBtn // OkBtn
// //
this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OkBtn.Location = new System.Drawing.Point(169, 145); this.OkBtn.Location = new System.Drawing.Point(169, 203);
this.OkBtn.Name = "OkBtn"; this.OkBtn.Name = "OkBtn";
this.OkBtn.Size = new System.Drawing.Size(60, 23); this.OkBtn.Size = new System.Drawing.Size(60, 23);
this.OkBtn.TabIndex = 2; this.OkBtn.TabIndex = 2;
@ -56,13 +57,23 @@
this.OkBtn.UseVisualStyleBackColor = true; this.OkBtn.UseVisualStyleBackColor = true;
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click); this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
// //
// ControllerPropertyGrid
//
this.ControllerPropertyGrid.Location = new System.Drawing.Point(12, 12);
this.ControllerPropertyGrid.Name = "ControllerPropertyGrid";
this.ControllerPropertyGrid.PropertySort = System.Windows.Forms.PropertySort.Alphabetical;
this.ControllerPropertyGrid.Size = new System.Drawing.Size(283, 181);
this.ControllerPropertyGrid.TabIndex = 4;
this.ControllerPropertyGrid.ToolbarVisible = false;
//
// PCEControllerConfig // PCEControllerConfig
// //
this.AcceptButton = this.OkBtn; this.AcceptButton = this.OkBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CancelBtn; this.CancelButton = this.CancelBtn;
this.ClientSize = new System.Drawing.Size(307, 180); this.ClientSize = new System.Drawing.Size(307, 238);
this.Controls.Add(this.ControllerPropertyGrid);
this.Controls.Add(this.CancelBtn); this.Controls.Add(this.CancelBtn);
this.Controls.Add(this.OkBtn); this.Controls.Add(this.OkBtn);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
@ -81,5 +92,6 @@
private System.Windows.Forms.Button CancelBtn; private System.Windows.Forms.Button CancelBtn;
private System.Windows.Forms.Button OkBtn; private System.Windows.Forms.Button OkBtn;
private System.Windows.Forms.PropertyGrid ControllerPropertyGrid;
} }
} }

View File

@ -1,6 +1,4 @@
using System; using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using BizHawk.Emulation.Cores.PCEngine; using BizHawk.Emulation.Cores.PCEngine;
@ -10,6 +8,8 @@ namespace BizHawk.Client.EmuHawk
{ {
public partial class PCEControllerConfig : Form public partial class PCEControllerConfig : Form
{ {
private PCEngine.PCESyncSettings _controllerSettings;
public PCEControllerConfig() public PCEControllerConfig()
{ {
InitializeComponent(); InitializeComponent();
@ -18,37 +18,13 @@ namespace BizHawk.Client.EmuHawk
private void PCEControllerConfig_Load(object sender, EventArgs e) private void PCEControllerConfig_Load(object sender, EventArgs e)
{ {
var pceSettings = ((PCEngine)Global.Emulator).GetSyncSettings(); var pceSettings = ((PCEngine)Global.Emulator).GetSyncSettings();
for (int i = 0; i < 5; i++) _controllerSettings = pceSettings; // Assumes only controller data is in sync settings! If there are ever more sync settings, this dialog should just become a general sync settings dialog (or both settings/sync settings)
{ ControllerPropertyGrid.SelectedObject = _controllerSettings;
Controls.Add(new Label
{
Text = "Controller " + (i + 1),
Location = new Point(15, 15 + (i * 25))
});
Controls.Add(new CheckBox
{
Text = "Connected",
Name = "Controller" + i,
Location = new Point(135, 15 + (i * 25)),
Checked = pceSettings.Controllers[i].IsConnected
});
}
} }
private void OkBtn_Click(object sender, EventArgs e) private void OkBtn_Click(object sender, EventArgs e)
{ {
var pceSettings = ((PCEngine)Global.Emulator).GetSyncSettings(); GlobalWin.MainForm.PutCoreSyncSettings(_controllerSettings);
Controls
.OfType<CheckBox>()
.OrderBy(c => c.Name)
.ToList()
.ForEach(c =>
{
var index = int.Parse(c.Name.Replace("Controller", ""));
pceSettings.Controllers[index].IsConnected = c.Checked;
});
GlobalWin.MainForm.PutCoreSyncSettings(pceSettings);
DialogResult = DialogResult.OK; DialogResult = DialogResult.OK;
Close(); Close();
} }

View File

@ -9,13 +9,15 @@ using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.WinFormExtensions;
using System.Collections.Generic; using System.Collections.Generic;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
public partial class GBGPUView : Form, IToolFormAutoConfig public partial class GBGPUView : Form, IToolFormAutoConfig
{ {
[RequiredService] [RequiredService]
public Gameboy Gb { get; private set; } public IGameboyCommon Gb { get; private set; }
// TODO: freeze semantics are a bit weird: details for a mouseover or freeze are taken from the current // TODO: freeze semantics are a bit weird: details for a mouseover or freeze are taken from the current
// state, not the state at the last callback (and so can be quite different when update is set to manual). // state, not the state at the last callback (and so can be quite different when update is set to manual).
@ -32,11 +34,8 @@ namespace BizHawk.Client.EmuHawk
// g' = 8.25g // g' = 8.25g
// b' = 8.25b // b' = 8.25b
// gambatte doesn't modify these memory locations unless you reconstruct, so we can store
private IntPtr _vram; private GPUMemoryAreas _memory;
private IntPtr _bgpal;
private IntPtr _sppal;
private IntPtr _oam;
private bool _cgb; // set once at start private bool _cgb; // set once at start
private int _lcdc; // set at each callback private int _lcdc; // set at each callback
@ -89,13 +88,9 @@ namespace BizHawk.Client.EmuHawk
_cgb = Gb.IsCGBMode(); _cgb = Gb.IsCGBMode();
_lcdc = 0; _lcdc = 0;
// TODO: can this be a required Emulator Service, and let the tool manage the logic of closing? _memory = Gb.GetGPU();
if (!Gb.GetGPUMemoryAreas(out _vram, out _bgpal, out _sppal, out _oam))
{ tilespal = _memory.Bgpal;
if (Visible)
Close();
}
tilespal = _bgpal;
if (_cgb) if (_cgb)
label4.Enabled = true; label4.Enabled = true;
@ -357,11 +352,19 @@ namespace BizHawk.Client.EmuHawk
#endregion #endregion
void ScanlineCallback(int lcdc) void ScanlineCallback(byte lcdc)
{ {
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
_lcdc = lcdc; _lcdc = lcdc;
// set alpha on all pixels // set alpha on all pixels
unsafe // TODO: RE: Spriteback, you can't muck with Sameboy in this way due to how SGB reads stuff...?
/*unsafe
{ {
int* p = (int*)_bgpal; int* p = (int*)_bgpal;
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
@ -372,7 +375,7 @@ namespace BizHawk.Client.EmuHawk
int c = Spriteback.ToArgb(); int c = Spriteback.ToArgb();
for (int i = 0; i < 32; i += 4) for (int i = 0; i < 32; i += 4)
p[i] = c; p[i] = c;
} }*/
// bg maps // bg maps
if (!_cgb) if (!_cgb)
@ -462,7 +465,7 @@ namespace BizHawk.Client.EmuHawk
} }
DrawOam(bmpViewOAM.BMP, _oam, _vram, _sppal, lcdc.Bit(2), _cgb); DrawOam(bmpViewOAM.BMP, _oam, _vram, _sppal, lcdc.Bit(2), _cgb);
bmpViewOAM.Refresh(); bmpViewOAM.Refresh();
}
// try to run the current mouseover, to refresh if the mouse is being held over a pane while the emulator runs // try to run the current mouseover, to refresh if the mouse is being held over a pane while the emulator runs
// this doesn't really work well; the update rate seems to be throttled // this doesn't really work well; the update rate seems to be throttled
MouseEventArgs e = new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0); MouseEventArgs e = new MouseEventArgs(MouseButtons.None, 0, Cursor.Position.X, Cursor.Position.Y, 0);
@ -514,7 +517,7 @@ namespace BizHawk.Client.EmuHawk
private void buttonRefresh_Click(object sender, EventArgs e) private void buttonRefresh_Click(object sender, EventArgs e)
{ {
if (cbscanline == -2 && Gb != null) if (cbscanline == -2)
Gb.SetScanlineCallback(ScanlineCallback, -2); Gb.SetScanlineCallback(ScanlineCallback, -2);
} }
@ -614,6 +617,13 @@ namespace BizHawk.Client.EmuHawk
private unsafe void PaletteMouseover(int x, int y, bool sprite) private unsafe void PaletteMouseover(int x, int y, bool sprite)
{ {
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
bmpViewDetails.ChangeBitmapSize(8, 10); bmpViewDetails.ChangeBitmapSize(8, 10);
if (bmpViewDetails.Height != 80) if (bmpViewDetails.Height != 80)
bmpViewDetails.Height = 80; bmpViewDetails.Height = 80;
@ -647,9 +657,17 @@ namespace BizHawk.Client.EmuHawk
labelDetails.Text = sb.ToString(); labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh(); bmpViewDetails.Refresh();
} }
}
unsafe void TileMouseover(int x, int y, bool secondbank) unsafe void TileMouseover(int x, int y, bool secondbank)
{ {
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
// todo: draw with a specific palette // todo: draw with a specific palette
bmpViewDetails.ChangeBitmapSize(8, 8); bmpViewDetails.ChangeBitmapSize(8, 8);
if (bmpViewDetails.Height != 64) if (bmpViewDetails.Height != 64)
@ -670,9 +688,17 @@ namespace BizHawk.Client.EmuHawk
labelDetails.Text = sb.ToString(); labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh(); bmpViewDetails.Refresh();
} }
}
unsafe void TilemapMouseover(int x, int y, bool win) unsafe void TilemapMouseover(int x, int y, bool win)
{ {
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
bmpViewDetails.ChangeBitmapSize(8, 8); bmpViewDetails.ChangeBitmapSize(8, 8);
if (bmpViewDetails.Height != 64) if (bmpViewDetails.Height != 64)
bmpViewDetails.Height = 64; bmpViewDetails.Height = 64;
@ -709,9 +735,17 @@ namespace BizHawk.Client.EmuHawk
labelDetails.Text = sb.ToString(); labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh(); bmpViewDetails.Refresh();
} }
}
unsafe void SpriteMouseover(int x, int y) unsafe void SpriteMouseover(int x, int y)
{ {
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
bool tall = _lcdc.Bit(2); bool tall = _lcdc.Bit(2);
x /= 8; x /= 8;
y /= 8; y /= 8;
@ -754,6 +788,7 @@ namespace BizHawk.Client.EmuHawk
labelDetails.Text = sb.ToString(); labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh(); bmpViewDetails.Refresh();
} }
}
private void bmpViewBG_MouseEnter(object sender, EventArgs e) private void bmpViewBG_MouseEnter(object sender, EventArgs e)
{ {
@ -882,9 +917,9 @@ namespace BizHawk.Client.EmuHawk
else if (e.Button == MouseButtons.Left) else if (e.Button == MouseButtons.Left)
{ {
if (sender == bmpViewBGPal) if (sender == bmpViewBGPal)
tilespal = _bgpal + e.X / 16 * 16; tilespal = _memory.Bgpal + e.X / 16 * 16;
else if (sender == bmpViewSPPal) else if (sender == bmpViewSPPal)
tilespal = _sppal + e.X / 16 * 16; tilespal = _memory.Sppal + e.X / 16 * 16;
} }
} }

View File

@ -18,7 +18,7 @@ namespace BizHawk.Client.EmuHawk
public EmuLuaLibrary() public EmuLuaLibrary()
{ {
Docs = new LuaDocumentation(); Docs = new LuaDocumentation();
if(NLua.Lua.WhichLua == "NLua") //if(NLua.Lua.WhichLua == "NLua")
_lua["keepalives"] = _lua.NewTable(); _lua["keepalives"] = _lua.NewTable();
} }
@ -178,7 +178,7 @@ namespace BizHawk.Client.EmuHawk
var content = File.ReadAllText(file); var content = File.ReadAllText(file);
var main = lua.LoadString(content, "main"); var main = lua.LoadString(content, "main");
lua.Push(main); // push main function on to stack for subsequent resuming lua.Push(main); // push main function on to stack for subsequent resuming
if (NLua.Lua.WhichLua == "NLua") //if (NLua.Lua.WhichLua == "NLua")
{ {
_lua.GetTable("keepalives")[lua] = 1; _lua.GetTable("keepalives")[lua] = 1;
//this not being run is the origin of a memory leak if you restart scripts too many times //this not being run is the origin of a memory leak if you restart scripts too many times
@ -191,7 +191,7 @@ namespace BizHawk.Client.EmuHawk
{ {
_currThread = _lua.NewThread(); _currThread = _lua.NewThread();
_currThread.DoString(command); _currThread.DoString(command);
if (NLua.Lua.WhichLua == "NLua") //if (NLua.Lua.WhichLua == "NLua")
_lua.Pop(); _lua.Pop();
} }

View File

@ -138,12 +138,12 @@
this.SystemDropDown.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.SystemDropDown.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.SystemDropDown.FormattingEnabled = true; this.SystemDropDown.FormattingEnabled = true;
this.SystemDropDown.Items.AddRange(new object[] { this.SystemDropDown.Items.AddRange(new object[] {
"GB",
"AppleII", "AppleII",
"PSX",
"C64", "C64",
"SAT", "GB",
"PCFX"}); "PCFX",
"PSX",
"SAT"});
this.SystemDropDown.Location = new System.Drawing.Point(425, 75); this.SystemDropDown.Location = new System.Drawing.Point(425, 75);
this.SystemDropDown.Name = "SystemDropDown"; this.SystemDropDown.Name = "SystemDropDown";
this.SystemDropDown.Size = new System.Drawing.Size(69, 21); this.SystemDropDown.Size = new System.Drawing.Size(69, 21);

View File

@ -78,7 +78,7 @@ namespace BizHawk.Client.EmuHawk
DenoteMarkersWithBGColor = true; DenoteMarkersWithBGColor = true;
} }
public RecentFiles RecentTas { get; } public RecentFiles RecentTas { get; set; }
public bool DrawInput { get; set; } public bool DrawInput { get; set; }
public bool AutoPause { get; set; } public bool AutoPause { get; set; }
public bool AutoRestoreLastPosition { get; set; } public bool AutoRestoreLastPosition { get; set; }

View File

@ -12,12 +12,13 @@ namespace BizHawk.Client.EmuHawk
{ {
private string UnpluggedControllerName => typeof(UnpluggedController).DisplayName(); private string UnpluggedControllerName => typeof(UnpluggedController).DisplayName();
private string StandardControllerName => typeof(StandardController).DisplayName(); private string StandardControllerName => typeof(StandardController).DisplayName();
private string ProLineControllerName => typeof(ProLineController).DisplayName();
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core) public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
{ {
var intvSyncSettings = ((A7800Hawk)core).GetSyncSettings().Clone(); var A78SyncSettings = ((A7800Hawk)core).GetSyncSettings().Clone();
var port1 = intvSyncSettings.Port1; var port1 = A78SyncSettings.Port1;
var port2 = intvSyncSettings.Port2; var port2 = A78SyncSettings.Port2;
if (port1 == StandardControllerName) if (port1 == StandardControllerName)
{ {
@ -29,6 +30,16 @@ namespace BizHawk.Client.EmuHawk
yield return JoystickController(2); yield return JoystickController(2);
} }
if (port1 == ProLineControllerName)
{
yield return ProLineController(1);
}
if (port2 == ProLineControllerName)
{
yield return ProLineController(2);
}
} }
private static PadSchema ProLineController(int controller) private static PadSchema ProLineController(int controller)

View File

@ -1,7 +1,10 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.PCEngine;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
@ -13,9 +16,34 @@ namespace BizHawk.Client.EmuHawk
{ {
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core) public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
{ {
for (var i = 0; i < core.ControllerDefinition.PlayerCount; i++) var ss = ((PCEngine)core).GetSyncSettings();
var padSchemas = new[]
{ {
yield return StandardController(i + 1); ss.Port1,
ss.Port2,
ss.Port3,
ss.Port4,
ss.Port5,
}
.Where(p => p != PceControllerType.Unplugged)
.Select((p, i) => GenerateSchemaForPort(p, i + 1))
.Where(s => s != null);
return padSchemas;
}
private static PadSchema GenerateSchemaForPort(PceControllerType type, int controller)
{
switch (type)
{
default:
MessageBox.Show($"{type} is not supported yet");
return null;
case PceControllerType.Unplugged:
return null;
case PceControllerType.GamePad:
return StandardController(controller);
} }
} }
@ -29,7 +57,7 @@ namespace BizHawk.Client.EmuHawk
{ {
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " Up", Name = $"P{controller} Up",
DisplayName = "", DisplayName = "",
Icon = Properties.Resources.BlueUp, Icon = Properties.Resources.BlueUp,
Location = new Point(14, 12), Location = new Point(14, 12),
@ -37,7 +65,7 @@ namespace BizHawk.Client.EmuHawk
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " Down", Name = $"P{controller} Down",
DisplayName = "", DisplayName = "",
Icon = Properties.Resources.BlueDown, Icon = Properties.Resources.BlueDown,
Location = new Point(14, 56), Location = new Point(14, 56),
@ -45,7 +73,7 @@ namespace BizHawk.Client.EmuHawk
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " Left", Name = $"P{controller} Left",
DisplayName = "", DisplayName = "",
Icon = Properties.Resources.Back, Icon = Properties.Resources.Back,
Location = new Point(2, 34), Location = new Point(2, 34),
@ -53,7 +81,7 @@ namespace BizHawk.Client.EmuHawk
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " Right", Name = $"P{controller} Right",
DisplayName = "", DisplayName = "",
Icon = Properties.Resources.Forward, Icon = Properties.Resources.Forward,
Location = new Point(24, 34), Location = new Point(24, 34),
@ -61,28 +89,28 @@ namespace BizHawk.Client.EmuHawk
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " B2", Name = $"P{controller} B2",
DisplayName = "II", DisplayName = "II",
Location = new Point(122, 34), Location = new Point(122, 34),
Type = PadSchema.PadInputType.Boolean Type = PadSchema.PadInputType.Boolean
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " B1", Name = $"P{controller} B1",
DisplayName = "I", DisplayName = "I",
Location = new Point(146, 34), Location = new Point(146, 34),
Type = PadSchema.PadInputType.Boolean Type = PadSchema.PadInputType.Boolean
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " Select", Name = $"P{controller} Select",
DisplayName = "s", DisplayName = "s",
Location = new Point(52, 34), Location = new Point(52, 34),
Type = PadSchema.PadInputType.Boolean Type = PadSchema.PadInputType.Boolean
}, },
new PadSchema.ButtonSchema new PadSchema.ButtonSchema
{ {
Name = "P" + controller + " Run", Name = $"P{controller} Run",
DisplayName = "R", DisplayName = "R",
Location = new Point(74, 34), Location = new Point(74, 34),
Type = PadSchema.PadInputType.Boolean Type = PadSchema.PadInputType.Boolean

View File

@ -72,7 +72,8 @@ namespace BizHawk.Emulation.Common
Option("SAT", "E", ss_100_j); Option("SAT", "E", ss_100_j);
Option("SAT", "E", ss_101_j); Option("SAT", "E", ss_101_j);
FirmwareAndOption("a67cd4f550751f8b91de2b8b74528ab4e0c11c77", 2 * 1024 * 1024, "SAT", "KOF95", "kof95.bin", "King of Fighters cartridge"); FirmwareAndOption("a67cd4f550751f8b91de2b8b74528ab4e0c11c77", 2 * 1024 * 1024, "SAT", "KOF95", "kof95.bin", "King of Fighters cartridge");
Firmware("SAT", "ULTRAMAN", "Ultraman cartridge"); //Firmware("SAT", "ULTRAMAN", "Ultraman cartridge");
FirmwareAndOption("56c1b93da6b660bf393fbf48ca47569000ef4047", 2 * 1024 * 1024, "SAT", "ULTRAMAN", "Ultraman.bin", "Ultraman cartridge");
var ti83_102 = File("CE08F6A808701FC6672230A790167EE485157561", 262144, "ti83_102.rom", "TI-83 Rom v1.02"); // ?? is this size correct? var ti83_102 = File("CE08F6A808701FC6672230A790167EE485157561", 262144, "ti83_102.rom", "TI-83 Rom v1.02"); // ?? is this size correct?
var ti83_103 = File("8399E384804D8D29866CAA4C8763D7A61946A467", 262144, "ti83_103.rom", "TI-83 Rom v1.03"); // ?? is this size correct? var ti83_103 = File("8399E384804D8D29866CAA4C8763D7A61946A467", 262144, "ti83_103.rom", "TI-83 Rom v1.03"); // ?? is this size correct?

View File

@ -357,6 +357,10 @@
<Compile Include="Consoles\Atari\A7800Hawk\A7800HawkControllerDeck.cs" /> <Compile Include="Consoles\Atari\A7800Hawk\A7800HawkControllerDeck.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\A7800HawkControllers.cs" /> <Compile Include="Consoles\Atari\A7800Hawk\A7800HawkControllers.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperDefault.cs" /> <Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperDefault.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperSG.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperSGE.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperF18.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperRampage.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperBase.cs" /> <Compile Include="Consoles\Atari\A7800Hawk\Mappers\MapperBase.cs" />
<Compile Include="Consoles\Atari\A7800Hawk\MemoryMap.cs"> <Compile Include="Consoles\Atari\A7800Hawk\MemoryMap.cs">
<DependentUpon>A7800Hawk.cs</DependentUpon> <DependentUpon>A7800Hawk.cs</DependentUpon>
@ -537,8 +541,8 @@
<Compile Include="Consoles\Nintendo\Gameboy\GBDisassembler.cs" /> <Compile Include="Consoles\Nintendo\Gameboy\GBDisassembler.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\IGameboyCommon.cs" /> <Compile Include="Consoles\Nintendo\Gameboy\IGameboyCommon.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" /> <Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\LibPizza.cs" /> <Compile Include="Consoles\Nintendo\Gameboy\LibSameboy.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\Pizza.cs" /> <Compile Include="Consoles\Nintendo\Gameboy\Sameboy.cs" />
<Compile Include="Consoles\Nintendo\GBA\ArmV4Disassembler.cs" /> <Compile Include="Consoles\Nintendo\GBA\ArmV4Disassembler.cs" />
<Compile Include="Consoles\Nintendo\GBA\GBA.cs" /> <Compile Include="Consoles\Nintendo\GBA\GBA.cs" />
<Compile Include="Consoles\Nintendo\GBA\IGBAGPUViewable.cs" /> <Compile Include="Consoles\Nintendo\GBA\IGBAGPUViewable.cs" />
@ -1005,6 +1009,7 @@
<Compile Include="Consoles\PC Engine\ADPCM.cs" /> <Compile Include="Consoles\PC Engine\ADPCM.cs" />
<Compile Include="Consoles\PC Engine\MemoryMap.TurboCD.cs" /> <Compile Include="Consoles\PC Engine\MemoryMap.TurboCD.cs" />
<Compile Include="Consoles\PC Engine\MemoryMap.Populous.cs" /> <Compile Include="Consoles\PC Engine\MemoryMap.Populous.cs" />
<Compile Include="Consoles\PC Engine\PceControllerDeck.cs" />
<Compile Include="Consoles\PC Engine\PCEngine.ArcadeCard.cs" /> <Compile Include="Consoles\PC Engine\PCEngine.ArcadeCard.cs" />
<Compile Include="Consoles\PC Engine\PCEngine.ICodeDataLogger.cs"> <Compile Include="Consoles\PC Engine\PCEngine.ICodeDataLogger.cs">
<DependentUpon>PCEngine.cs</DependentUpon> <DependentUpon>PCEngine.cs</DependentUpon>
@ -1309,6 +1314,8 @@
<None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" /> <None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" />
<None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" /> <None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" />
<None Include="Consoles\Nintendo\NES\Docs\nesasm.pdf" /> <None Include="Consoles\Nintendo\NES\Docs\nesasm.pdf" />
<None Include="Resources\cgb_boot.bin.gz" />
<None Include="Resources\dmg_boot.bin.gz" />
<None Include="Resources\sgb-cart-present.spc.gz" /> <None Include="Resources\sgb-cart-present.spc.gz" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

View File

@ -13,6 +13,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
//Maria related variables //Maria related variables
public int cycle; public int cycle;
public int cpu_cycle; public int cpu_cycle;
public int m6532_cycle;
public bool cpu_is_haltable; public bool cpu_is_haltable;
public bool cpu_is_halted; public bool cpu_is_halted;
public bool cpu_halt_pending; public bool cpu_halt_pending;
@ -23,7 +24,15 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public byte p2_state; public byte p2_state;
public byte p1_fire; public byte p1_fire;
public byte p2_fire; public byte p2_fire;
public byte p1_fire_2x;
public byte p2_fire_2x;
public byte con_state; public byte con_state;
public bool left_toggle;
public bool right_toggle;
public bool left_was_pressed;
public bool right_was_pressed;
public bool p1_is_2button;
public bool p2_is_2button;
// there are 4 maria cycles in a CPU cycle (fast access, both NTSC and PAL) // there are 4 maria cycles in a CPU cycle (fast access, both NTSC and PAL)
// if the 6532 or TIA are accessed (PC goes to one of those addresses) the next access will be slower by 1/2 a CPU cycle // if the 6532 or TIA are accessed (PC goes to one of those addresses) the next access will be slower by 1/2 a CPU cycle
@ -32,6 +41,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public void FrameAdvance(IController controller, bool render, bool rendersound) public void FrameAdvance(IController controller, bool render, bool rendersound)
{ {
Console.WriteLine("-----------------------FRAME-----------------------");
if (_tracer.Enabled) if (_tracer.Enabled)
{ {
cpu.TraceCallback = s => _tracer.Put(s); cpu.TraceCallback = s => _tracer.Put(s);
@ -75,6 +85,14 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
tia.Execute(0); tia.Execute(0);
} }
// tick the m6532 timer, which is still active although not recommended to use
m6532_cycle++;
if (m6532_cycle== 4)
{
m6532.Timer.Tick();
m6532_cycle = 0;
}
if (cpu_cycle <= (2 + (slow_access ? 1 : 0))) if (cpu_cycle <= (2 + (slow_access ? 1 : 0)))
{ {
cpu_is_haltable = true; cpu_is_haltable = true;
@ -149,6 +167,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
p2_state = _controllerDeck.ReadPort2(controller); p2_state = _controllerDeck.ReadPort2(controller);
p1_fire = _controllerDeck.ReadFire1(controller); p1_fire = _controllerDeck.ReadFire1(controller);
p2_fire = _controllerDeck.ReadFire2(controller); p2_fire = _controllerDeck.ReadFire2(controller);
p1_fire_2x = _controllerDeck.ReadFire1_2x(controller);
p2_fire_2x = _controllerDeck.ReadFire2_2x(controller);
p1_is_2button = _controllerDeck.Is_2_button1(controller);
p2_is_2button = _controllerDeck.Is_2_button2(controller);
} }
public void GetConsoleState(IController controller) public void GetConsoleState(IController controller)
@ -157,12 +179,34 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
if (controller.IsPressed("Right Difficulty")) if (controller.IsPressed("Right Difficulty"))
{ {
result |= (1 << 7); if (!right_was_pressed)
{
right_toggle = !right_toggle;
} }
right_was_pressed = true;
result |= (byte)((right_toggle ? 1 : 0) << 7);
}
else
{
right_was_pressed = false;
result |= (byte)((right_toggle ? 1 : 0) << 7);
}
if (controller.IsPressed("Left Difficulty")) if (controller.IsPressed("Left Difficulty"))
{ {
result |= (1 << 6); if (!left_was_pressed)
{
left_toggle = !left_toggle;
} }
left_was_pressed = true;
result |= (byte)((left_toggle ? 1 : 0) << 6);
}
else
{
left_was_pressed = false;
result |= (byte)((left_toggle ? 1 : 0) << 6);
}
if (!controller.IsPressed("Pause")) if (!controller.IsPressed("Pause"))
{ {
result |= (1 << 3); result |= (1 << 3);

View File

@ -23,10 +23,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
1), 1),
new MemoryDomainDelegate( new MemoryDomainDelegate(
"TIA Registers", "TIA Registers",
TIA_regs.Length, 0x20,
MemoryDomain.Endian.Little, MemoryDomain.Endian.Little,
addr => TIA_regs[addr], addr => tia.ReadMemory((ushort)addr,true),
(addr, value) => TIA_regs[addr] = value, (addr, value) => tia.WriteMemory((ushort)addr, value, true),
1), 1),
new MemoryDomainDelegate( new MemoryDomainDelegate(
"Maria Registers", "Maria Registers",
@ -46,16 +46,16 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
"Ram Block 0", "Ram Block 0",
0xB0, 0xB0,
MemoryDomain.Endian.Little, MemoryDomain.Endian.Little,
addr => RAM[addr-0x840], addr => RAM[addr+0x840],
(addr, value) => RAM[addr-0x840] = value, (addr, value) => RAM[addr+0x840] = value,
1 1
), ),
new MemoryDomainDelegate( new MemoryDomainDelegate(
"Ram Block 1", "Ram Block 1",
0xB0, 0xB0,
MemoryDomain.Endian.Little, MemoryDomain.Endian.Little,
addr => RAM[addr-0x940], addr => RAM[addr+0x940],
(addr, value) => RAM[addr-0x940] = value, (addr, value) => RAM[addr+0x940] = value,
1 1
), ),
new MemoryDomainDelegate( new MemoryDomainDelegate(

View File

@ -51,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
tia.SyncState(ser); tia.SyncState(ser);
maria.SyncState(ser); maria.SyncState(ser);
m6532.SyncState(ser); m6532.SyncState(ser);
mapper.SyncState(ser);
ser.BeginSection("Atari7800"); ser.BeginSection("Atari7800");
ser.Sync("core", ref core, false); ser.Sync("core", ref core, false);
@ -62,7 +63,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ser.Sync("A7800_control_register", ref A7800_control_register); ser.Sync("A7800_control_register", ref A7800_control_register);
ser.Sync("_isPAL", ref _isPAL); ser.Sync("_isPAL", ref _isPAL);
ser.Sync("TIA_regs", ref TIA_regs, false);
ser.Sync("Maria_regs", ref Maria_regs, false); ser.Sync("Maria_regs", ref Maria_regs, false);
ser.Sync("RAM", ref RAM, false); ser.Sync("RAM", ref RAM, false);
ser.Sync("RAM_6532", ref RAM_6532, false); ser.Sync("RAM_6532", ref RAM_6532, false);
@ -70,13 +70,21 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ser.Sync("cycle", ref cycle); ser.Sync("cycle", ref cycle);
ser.Sync("cpu_cycle", ref cpu_cycle); ser.Sync("cpu_cycle", ref cpu_cycle);
ser.Sync("m6532_cycle", ref m6532_cycle);
ser.Sync("cpu_is_haltable", ref cpu_is_haltable); ser.Sync("cpu_is_haltable", ref cpu_is_haltable);
ser.Sync("cpu_is_halted", ref cpu_is_halted); ser.Sync("cpu_is_halted", ref cpu_is_halted);
ser.Sync("cpu_halt_pending", ref cpu_halt_pending); ser.Sync("cpu_halt_pending", ref cpu_halt_pending);
ser.Sync("cpu_resume_pending", ref cpu_resume_pending); ser.Sync("cpu_resume_pending", ref cpu_resume_pending);
ser.Sync("slow_access", ref slow_access); ser.Sync("slow_access", ref slow_access);
ser.Sync("small flag", ref small_flag);
ser.Sync("pal kara", ref PAL_Kara);
ser.Sync("Cart RAM", ref cart_RAM);
ser.Sync("pokey", ref pokey);
ser.Sync("left_toggle", ref left_toggle);
ser.Sync("right_toggle", ref right_toggle);
ser.Sync("left_was_pressed", ref left_was_pressed);
ser.Sync("right_was_pressed", ref right_was_pressed);
ser.EndSection(); ser.EndSection();
} }

View File

@ -3,6 +3,7 @@
using BizHawk.Common.BufferExtensions; using BizHawk.Common.BufferExtensions;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Components.M6502; using BizHawk.Emulation.Cores.Components.M6502;
using BizHawk.Common.NumberExtensions;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
@ -22,7 +23,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public byte A7800_control_register; public byte A7800_control_register;
// memory domains // memory domains
public byte[] TIA_regs = new byte[0x20];
public byte[] Maria_regs = new byte[0x20]; public byte[] Maria_regs = new byte[0x20];
public byte[] RAM = new byte[0x1000]; public byte[] RAM = new byte[0x1000];
public byte[] RAM_6532 = new byte[0x80]; public byte[] RAM_6532 = new byte[0x80];
@ -37,16 +37,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public string s_mapper; public string s_mapper;
public MapperBase mapper; public MapperBase mapper;
public bool small_flag = false;
public bool PAL_Kara = false;
public int cart_RAM = 0;
public bool pokey = false;
private readonly ITraceable _tracer; private readonly ITraceable _tracer;
public MOS6502X cpu; public MOS6502X cpu;
public Maria maria; public Maria maria;
private bool _isPAL; public bool _isPAL;
public M6532 m6532; public M6532 m6532;
public TIA tia; public TIA tia;
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn) public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn, object settings, object syncSettings)
{ {
var ser = new BasicServiceProvider(this); var ser = new BasicServiceProvider(this);
@ -70,16 +74,24 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
CoreComm = comm; CoreComm = comm;
_settings = (A7800Settings)settings ?? new A7800Settings();
_syncSettings = (A7800SyncSettings)syncSettings ?? new A7800SyncSettings();
_controllerDeck = new A7800HawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2); _controllerDeck = new A7800HawkControllerDeck(_syncSettings.Port1, _syncSettings.Port2);
byte[] highscoreBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS."); byte[] highscoreBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS.");
byte[] palBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available."); byte[] palBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available.");
byte[] ntscBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_NTSC", false, "The game will not run if the correct region BIOS is not available."); byte[] ntscBios = comm.CoreFileProvider.GetFirmware("A78", "Bios_NTSC", false, "The game will not run if the correct region BIOS is not available.");
byte[] header = new byte[128];
bool is_header = false;
if (rom.Length % 1024 == 128) if (rom.Length % 1024 == 128)
{ {
Console.WriteLine("Trimming 128 byte .a78 header..."); Console.WriteLine("128 byte header detected");
byte[] newrom = new byte[rom.Length - 128]; byte[] newrom = new byte[rom.Length - 128];
is_header = true;
Buffer.BlockCopy(rom, 0, header, 0, 128);
Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length); Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length);
rom = newrom; rom = newrom;
} }
@ -107,11 +119,77 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
s_mapper = dict["board"]; s_mapper = dict["board"];
} }
else else
{
throw new Exception("No Board selected for this game"); throw new Exception("No Board selected for this game");
} }
// check if the game uses pokey or RAM
if (dict.ContainsKey("RAM"))
{
int.TryParse(dict["RAM"], out cart_RAM);
Console.WriteLine(cart_RAM);
}
if (dict.ContainsKey("Pokey"))
{
bool.TryParse(dict["Pokey"], out pokey);
}
// some games will not function with the high score bios
// if such a game is being played, tell the user and disable it
if (dict.ContainsKey("No_HS"))
{
bool no_hs;
bool.TryParse(dict["No_HS"], out no_hs);
if (no_hs)
{
Console.WriteLine("This game is incompatible with the High Score BIOS, disabling it");
highscoreBios = null;
}
}
}
else if (is_header)
{
Console.WriteLine("ROM not in DB, inferring mapper info from header");
byte cart_1 = header[0x35];
byte cart_2 = header[0x36];
_isPAL = (header[0x39] > 0) ? true : false;
if (cart_2.Bit(1))
{
if (cart_2.Bit(3))
{
s_mapper = "2";
}
else else
{ {
throw new Exception("ROM not in gamedb"); s_mapper = "1";
}
}
else
{
s_mapper = "0";
}
}
else
{
throw new Exception("ROM not in gamedb and has no header");
}
// some games that use the Super Game mapper only have 4 banks, so let's set a flag to limit bank size
if (rom.Length < 0x14000)
{
small_flag = true;
// additionally, PAL Karateka has bank 6 (actually 2) at 0x4000
if (rom.HashMD5()=="5E0A1E832BBCEA6FACB832FDE23A440A")
{
PAL_Kara = true;
}
} }
Reset_Mapper(s_mapper); Reset_Mapper(s_mapper);
@ -131,6 +209,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
maria._frameHz = 50; maria._frameHz = 50;
maria._screen_width = 320; maria._screen_width = 320;
maria._screen_height = 313; maria._screen_height = 313;
maria._vblanklines = 20;
maria._palette = PALPalette; maria._palette = PALPalette;
} }
else else
@ -138,6 +217,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
maria._frameHz = 60; maria._frameHz = 60;
maria._screen_width = 320; maria._screen_width = 320;
maria._screen_height = 263; maria._screen_height = 263;
maria._vblanklines = 20;
maria._palette = NTSCPalette; maria._palette = NTSCPalette;
} }
@ -171,7 +251,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
maria.Reset(); maria.Reset();
m6532.Reset(); m6532.Reset();
TIA_regs = new byte[0x20];
Maria_regs = new byte[0x20]; Maria_regs = new byte[0x20];
RAM = new byte[0x1000]; RAM = new byte[0x1000];
@ -189,6 +268,22 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
mapper = new MapperDefault(); mapper = new MapperDefault();
} }
if (m == "1")
{
mapper = new MapperSG();
}
if (m == "2")
{
mapper = new MapperSGE();
}
if (m == "3")
{
mapper = new MapperF18();
}
if (m == "4")
{
mapper = new MapperRampage();
}
mapper.Core = this; mapper.Core = this;
} }
@ -197,93 +292,96 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
* MariaTables.cs * MariaTables.cs
* *
* Palette tables for the Maria class. * Palette tables for the Maria class.
* All derived from Dan Boris' 7800/MAME code. * PAL derived from Dan Boris' 7800/MAME code.
*
* PAL Table: Copyright © 2004 Mike Murphy
*
* NTSC Table Source: http://atariage.com/forums/topic/95498-7800-color-palette-in-mess/?p=1174461
* *
* Copyright © 2004 Mike Murphy
* *
*/ */
public static readonly int[] NTSCPalette = public static readonly int[] NTSCPalette =
{ {
0x000000, 0x1c1c1c, 0x393939, 0x595959, // Grey 0x000000, 0x2e2e2e, 0x3c3c3c, 0x595959,
0x797979, 0x929292, 0xababab, 0xbcbcbc, 0x777777, 0x838383, 0xa0a0a0, 0xb7b7b7,
0xcdcdcd, 0xd9d9d9, 0xe6e6e6, 0xececec, 0xcdcdcd, 0xd8d8d8, 0xdddddd, 0xe0e0e0,
0xf2f2f2, 0xf8f8f8, 0xffffff, 0xffffff, 0xeaeaea, 0xf0f0f0, 0xf6f6f6, 0xffffff,
0x391701, 0x5e2304, 0x833008, 0xa54716, // Gold 0x412000, 0x542800, 0x763706, 0x984f0f,
0xc85f24, 0xe37820, 0xff911d, 0xffab1d, 0xbb6818, 0xd78016, 0xff911d, 0xffab1d,
0xffc51d, 0xffce34, 0xffd84c, 0xffe651, 0xffc51d, 0xffd03b, 0xffd84c, 0xffe651,
0xfff456, 0xfff977, 0xffff98, 0xffff98, 0xfff456, 0xfff977, 0xffff98, 0xffffab,
0x451904, 0x721e11, 0x9f241e, 0xb33a20, // Orange 0x451904, 0x721e11, 0x9f241e, 0xb33a20,
0xc85122, 0xe36920, 0xff811e, 0xff8c25, 0xc85122, 0xe36920, 0xfc811e, 0xff8c25,
0xff982c, 0xffae38, 0xffc545, 0xffc559, 0xff982c, 0xffae38, 0xffc455, 0xffc559,
0xffc66d, 0xffd587, 0xffe4a1, 0xffe4a1, 0xffc66d, 0xffd587, 0xffe4a1, 0xffe6ab,
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119, // Red Orange 0x5f1f0e, 0x7a240d, 0x9c2c0f, 0xb02f0e,
0xbf3624, 0xd34e2a, 0xe7623e, 0xf36e4a,
0xfd7854, 0xff8a6a, 0xff987c, 0xffa48b,
0xffb39e, 0xffc2b2, 0xffd0c3, 0xffdad0,
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119,
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161, 0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
0xff706e, 0xff7f7e, 0xff8f8f, 0xff9d9e, 0xff7063, 0xff7f7e, 0xff8f8f, 0xff9d9e,
0xffabad, 0xffb9bd, 0xffc7ce, 0xffc7ce, 0xffabad, 0xffb9bd, 0xffc7ce, 0xffcade,
0x050568, 0x3b136d, 0x712272, 0x8b2a8c, // Pink 0x490136, 0x66014b, 0x80035f, 0x951874,
0xa532a6, 0xb938ba, 0xcd3ecf, 0xdb47dd, 0xaa2d89, 0xba3d99, 0xca4da9, 0xd75ab6,
0xea51eb, 0xf45ff5, 0xfe6dff, 0xfe7afd, 0xe467c3, 0xef72ce, 0xfb7eda, 0xff8de1,
0xff87fb, 0xff95fd, 0xffa4ff, 0xffa4ff, 0xff9de5, 0xffa5e7, 0xffafea, 0xffb8ec,
0x280479, 0x400984, 0x590f90, 0x70249d, // Purple 0x48036c, 0x5c0488, 0x650d91, 0x7b23a7,
0x8839aa, 0xa441c3, 0xc04adc, 0xd054ed, 0x933bbf, 0x9d45c9, 0xa74fd3, 0xb25ade,
0xe05eff, 0xe96dff, 0xf27cff, 0xf88aff, 0xbd65e9, 0xc56df1, 0xce76fa, 0xd583ff,
0xff98ff, 0xfea1ff, 0xfeabff, 0xfeabff, 0xda90ff, 0xde9cff, 0xe2a9ff, 0xe6b6ff,
0x35088a, 0x420aad, 0x500cd0, 0x6428d0, // Purple Blue 0x051e81, 0x0626a5, 0x082fca, 0x263dd4,
0x7945d0, 0x8d4bd4, 0xa251d9, 0xb058ec, 0x444cde, 0x4f5aec, 0x5a68ff, 0x6575ff,
0xbe60ff, 0xc56bff, 0xcc77ff, 0xd183ff,
0xd790ff, 0xdb9dff, 0xdfaaff, 0xdfaaff,
0x051e81, 0x0626a5, 0x082fca, 0x263dd4, // Blue1
0x444cde, 0x4f5aee, 0x5a68ff, 0x6575ff,
0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff, 0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff,
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xc0cbff, 0x9fb2ff, 0xafbeff, 0xc0cbff, 0xcdd3ff,
0x0c048b, 0x2218a0, 0x382db5, 0x483ec7, // Blue2 0x0b0779, 0x201c8e, 0x3531a3, 0x4642b4,
0x584fda, 0x6159ec, 0x6b64ff, 0x7a74ff, 0x5753c5, 0x615dcf, 0x6d69db, 0x7b77e9,
0x8a84ff, 0x918eff, 0x9998ff, 0xa5a3ff, 0x8985f7, 0x918dff, 0x9c98ff, 0xa7a4ff,
0xb1aeff, 0xb8b8ff, 0xc0c2ff, 0xc0c2ff, 0xb2afff, 0xbbb8ff, 0xc3c1ff, 0xd3d1ff,
0x1d295a, 0x1d3876, 0x1d4892, 0x1c5cac, // Light Blue 0x1d295a, 0x1d3876, 0x1d4892, 0x1d5cac,
0x1c71c6, 0x3286cf, 0x489bd9, 0x4ea8ec, 0x1d71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff, 0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff,
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xc3e9ff, 0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xcfedff,
0x2f4302, 0x395202, 0x446103, 0x417a12, // Turquoise 0x014b59, 0x015d6e, 0x016f84, 0x01849c,
0x3e9421, 0x4a9f2e, 0x57ab3b, 0x5cbd55, 0x0199b5, 0x01abca, 0x01bcde, 0x01d0f5,
0x61d070, 0x69e27a, 0x72f584, 0x7cfa8d, 0x1adcff, 0x3ee1ff, 0x64e7ff, 0x76eaff,
0x87ff97, 0x9affa6, 0xadffb6, 0xadffb6, 0x8bedff, 0x9aefff, 0xb1f3ff, 0xc7f6ff,
0x0a4108, 0x0d540a, 0x10680d, 0x137d0f, // Green Blue 0x004800, 0x005400, 0x036b03, 0x0e760e,
0x169212, 0x19a514, 0x1cb917, 0x1ec919, 0x188018, 0x279227, 0x36a436, 0x4eb94e,
0x21d91b, 0x47e42d, 0x6ef040, 0x78f74d, 0x51cd51, 0x72da72, 0x7ce47c, 0x85ed85,
0x83ff5b, 0x9aff7a, 0xb2ff9a, 0xb2ff9a, 0xa2ffa2, 0xb5ffb5, 0xc8ffc8, 0xd0ffd0,
0x04410b, 0x05530e, 0x066611, 0x077714, // Green 0x164000, 0x1c5300, 0x236600, 0x287800,
0x088817, 0x099b1a, 0x0baf1d, 0x48c41f, 0x2e8c00, 0x3a980c, 0x47a519, 0x51af23,
0x86d922, 0x8fe924, 0x99f927, 0xa8fc41, 0x5cba2e, 0x71cf43, 0x85e357, 0x8deb5f,
0xb7ff5b, 0xc9ff6e, 0xdcff81, 0xdcff81, 0x97f569, 0xa4ff97, 0xb9ff97, 0xb9ff97,
0x02350f, 0x073f15, 0x0c4a1c, 0x2d5f1e, // Yellow Green 0x2c3500, 0x384400, 0x445200, 0x495600,
0x4f7420, 0x598324, 0x649228, 0x82a12e, 0x607100, 0x6c7f00, 0x798d0a, 0x8b9f1c,
0xa1b034, 0xa9c13a, 0xb2d241, 0xc4d945, 0x9eb22f, 0xabbf3c, 0xb8cc49, 0xc2d653,
0xd6e149, 0xe4f04e, 0xf2ff53, 0xf2ff53, 0xcde153, 0xdbef6c, 0xe8fc79, 0xf2ffab,
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green 0x463a09, 0x4d3f09, 0x544509, 0x6c5809,
0x806931, 0x978135, 0xaf993a, 0xc2a73e, 0x907609, 0xab8b0a, 0xc1a120, 0xd0b02f,
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836, 0xdebe3d, 0xe6c645, 0xedcd4c, 0xf6da65,
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d, 0xfde67d, 0xfff2a2, 0xfff9c5, 0xfff9d4,
0x401a02, 0x581f05, 0x702408, 0x8d3a13, // Light Orange 0x401a02, 0x581f05, 0x702408, 0x8d3a13,
0xab511f, 0xb56427, 0xbf7730, 0xd0853a, 0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c, 0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c,
0xffc160, 0xffc671, 0xffcb83, 0xffcb83 0xffc160, 0xffc671, 0xffcb83, 0xffd498
}; };
public static readonly int[] PALPalette = public static readonly int[] PALPalette =

View File

@ -70,6 +70,26 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
return Port2.ReadFire(c); return Port2.ReadFire(c);
} }
public byte ReadFire1_2x(IController c)
{
return Port1.ReadFire2x(c);
}
public byte ReadFire2_2x(IController c)
{
return Port2.ReadFire2x(c);
}
public bool Is_2_button1(IController c)
{
return Port1.Is_2_button(c);
}
public bool Is_2_button2(IController c)
{
return Port2.Is_2_button(c);
}
public ControllerDefinition Definition { get; } public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser) public void SyncState(Serializer ser)

View File

@ -9,7 +9,7 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
/// <summary> /// <summary>
/// Represents a controller plugged into a controller port on the intellivision /// Represents a controller plugged into a controller port on the A7800
/// </summary> /// </summary>
public interface IPort public interface IPort
{ {
@ -17,6 +17,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
byte ReadFire(IController c); byte ReadFire(IController c);
byte ReadFire2x(IController c);
bool Is_2_button(IController c);
ControllerDefinition Definition { get; } ControllerDefinition Definition { get; }
void SyncState(Serializer ser); void SyncState(Serializer ser);
@ -42,10 +46,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
} }
public byte ReadFire(IController c) public byte ReadFire(IController c)
{
return 0x80;
}
public byte ReadFire2x(IController c)
{ {
return 0; return 0;
} }
public bool Is_2_button(IController c)
{
return false;
}
public ControllerDefinition Definition { get; } public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
@ -101,8 +115,17 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
return result; return result;
} }
public ControllerDefinition Definition { get; } public byte ReadFire2x(IController c)
{
return 0; // only applicable for 2 button mode
}
public bool Is_2_button(IController c)
{
return false;
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
{ {
@ -122,4 +145,89 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
0x0, // Right 0x0, // Right
}; };
} }
[DisplayName("ProLine Controller")]
public class ProLineController : IPort
{
public ProLineController(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition
{
BoolButtons = BaseDefinition
.Select(b => "P" + PortNum + " " + b)
.ToList()
};
}
public int PortNum { get; }
public byte Read(IController c)
{
byte result = 0xF;
for (int i = 0; i < 4; i++)
{
if (c.IsPressed(Definition.BoolButtons[i]))
{
result -= (byte)(1 << i);
}
}
if (PortNum == 1)
{
result = (byte)(result << 4);
}
return result;
}
public byte ReadFire(IController c)
{
byte result = 0x80;
if (c.IsPressed(Definition.BoolButtons[4]) || c.IsPressed(Definition.BoolButtons[5]))
{
result = 0x00; // zero means fire is pressed
}
return result;
}
public byte ReadFire2x(IController c)
{
byte result = 0;
if (c.IsPressed(Definition.BoolButtons[4]))
{
result = 0x80;
}
if (c.IsPressed(Definition.BoolButtons[5]))
{
result |= 0x40;
}
return result;
}
public bool Is_2_button(IController c)
{
return true;
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
{
// Nothing todo, I think
}
private static readonly string[] BaseDefinition =
{
"U", "D", "L", "R", "Fire", "Fire2"
};
private static byte[] HandControllerButtons =
{
0x0, // UP
0x0, // Down
0x0, // Left
0x0, // Right
};
}
} }

View File

@ -1,4 +1,5 @@
using BizHawk.Common; using BizHawk.Common;
using System;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
@ -8,9 +9,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public A7800Hawk Core { get; set; } public A7800Hawk Core { get; set; }
private byte _ddRa = 0x00; public byte _ddRa = 0x00;
private byte _ddRb = 0x00; public byte _ddRb = 0x00;
private byte _outputA = 0x00; public byte _outputA = 0x00;
public byte _outputB = 0x00;
public TimerData Timer; public TimerData Timer;
@ -52,9 +54,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
if (registerAddr == 0x02) if (registerAddr == 0x02)
{ {
Core._islag = false;
// Read Output reg B // Read Output reg B
byte temp = Core.con_state; byte temp = Core.con_state;
temp = (byte)(temp & ~_ddRb); temp = (byte)(temp & ~_ddRb);
temp = (byte)(temp + (_outputB & _ddRb));
return temp; return temp;
} }
@ -166,7 +171,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
else if (registerAddr == 0x02) else if (registerAddr == 0x02)
{ {
// Write Output reg B // Write Output reg B
// But is read only _outputB = value;
} }
else if (registerAddr == 0x03) else if (registerAddr == 0x03)
{ {
@ -187,6 +192,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
_ddRa = 0x00; _ddRa = 0x00;
_ddRb = 0x00; _ddRb = 0x00;
_outputA = 0x00; _outputA = 0x00;
_outputB = 0x00;
} }
public void SyncState(Serializer ser) public void SyncState(Serializer ser)
@ -195,6 +201,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ser.Sync("ddra", ref _ddRa); ser.Sync("ddra", ref _ddRa);
ser.Sync("ddrb", ref _ddRb); ser.Sync("ddrb", ref _ddRb);
ser.Sync("OutputA", ref _outputA); ser.Sync("OutputA", ref _outputA);
ser.Sync("OutputB", ref _outputB);
Timer.SyncState(ser); Timer.SyncState(ser);
ser.EndSection(); ser.EndSection();
} }

View File

@ -38,9 +38,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
return Core._rom[Core._rom.Length - (0x10000 - addr)]; return Core._rom[Core._rom.Length - (0x10000 - addr)];
} }
else if (addr >= 0xF000 && !Core.A7800_control_register.Bit(2)) else if (addr >= (0x10000-Core._bios.Length) && !Core.A7800_control_register.Bit(2))
{ {
return Core._bios[addr - 0xF000]; return Core._bios[addr - (0x10000 - Core._bios.Length)];
} }
else else
{ {

View File

@ -0,0 +1,107 @@
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using System;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
// Mapper only used by F-18 Hornet
public class MapperF18 : MapperBase
{
public byte bank = 0;
public override byte ReadMemory(ushort addr)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
return Core._hsram[addr - 0x1000];
}
return 0xFF;
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
return Core._hsbios[addr - 0x3000];
}
else
{
return Core.RAM[0x800 + addr & 0x7FF];
}
}
else
{
// cartridge and other OPSYS
if (addr >= (0x10000 - Core._bios.Length) && !Core.A7800_control_register.Bit(2))
{
return Core._bios[addr - (0x10000 - Core._bios.Length)];
}
else
{
if (addr >= 0x8000)
{
// top 32k is fixed
return Core._rom[Core._rom.Length - (0x10000 - addr)];
}
else
{
// return whichever extra 16k bank is swapped in
int temp_addr = addr - 0x4000;
return Core._rom[temp_addr + bank * 0x4000];
}
}
}
}
public override byte PeekMemory(ushort addr)
{
return ReadMemory(addr);
}
public override void WriteMemory(ushort addr, byte value)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
Core._hsram[addr - 0x1000] = value;
}
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
}
else
{
Core.RAM[0x800 + addr & 0x7FF] = value;
}
}
else
{
// cartridge and other OPSYS
if (addr == 0x8000) // might be other addresses, but only 0x8000 is used
{
bank = (byte)(value & 3);
bank -= 1;
}
}
}
public override void PokeMemory(ushort addr, byte value)
{
WriteMemory(addr, value);
}
public override void SyncState(Serializer ser)
{
ser.Sync("Bank", ref bank);
}
}
}

View File

@ -0,0 +1,133 @@
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using System;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
// Mapper only used by Rampage and Double Dragon
public class MapperRampage : MapperBase
{
public byte bank = 0;
public override byte ReadMemory(ushort addr)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
return Core._hsram[addr - 0x1000];
}
return 0xFF;
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
return Core._hsbios[addr - 0x3000];
}
else
{
return Core.RAM[0x800 + addr & 0x7FF];
}
}
else
{
// cartridge and other OPSYS
if (addr >= (0x10000 - Core._bios.Length) && !Core.A7800_control_register.Bit(2))
{
return Core._bios[addr - (0x10000 - Core._bios.Length)];
}
else
{
/*
$4000 -$5fff second 8kb of bank 6
$6000 -$7fff first 8kb of bank 6
$8000 -$9fff second 8kb of bank 7
$e000 -$ffff first 8kb of bank 7
$a000-$dfff Banked
*/
if (addr >= 0x4000 && addr < 0x6000)
{
int temp_addr = addr - 0x4000;
return Core._rom[6 * 0x4000 + 0x2000 + temp_addr];
}
else if (addr >= 0x6000 && addr < 0x8000)
{
int temp_addr = addr - 0x6000;
return Core._rom[6 * 0x4000 + temp_addr];
}
else if (addr >= 0x8000 && addr < 0xA000)
{
int temp_addr = addr - 0x8000;
return Core._rom[7 * 0x4000 + 0x2000 + temp_addr];
}
else if (addr >= 0xA000 && addr < 0xE000)
{
int temp_addr = addr - 0xA000;
return Core._rom[bank * 0x4000 + temp_addr];
}
else
{
int temp_addr = addr - 0xE000;
return Core._rom[7 * 0x4000 + temp_addr];
}
}
}
}
public override byte PeekMemory(ushort addr)
{
return ReadMemory(addr);
}
public override void WriteMemory(ushort addr, byte value)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
Core._hsram[addr - 0x1000] = value;
}
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
}
else
{
Core.RAM[0x800 + addr & 0x7FF] = value;
}
}
else
{
// cartridge and other OPSYS
if (addr >= 0xFF80 && addr < 0xFF88) // might be other addresses, but only these are used
{
bank = (byte)(addr & 7);
}
}
}
public override void PokeMemory(ushort addr, byte value)
{
WriteMemory(addr, value);
}
public override void SyncState(Serializer ser)
{
ser.Sync("Bank", ref bank);
}
}
}

View File

@ -0,0 +1,170 @@
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using System;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
// Default Bank Switching Mapper used by most games
public class MapperSG : MapperBase
{
public byte bank = 0;
public byte[] RAM = new byte[0x4000];
public override byte ReadMemory(ushort addr)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
return Core._hsram[addr - 0x1000];
}
return 0xFF;
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
return Core._hsbios[addr - 0x3000];
}
else
{
return Core.RAM[0x800 + addr & 0x7FF];
}
}
else
{
// cartridge and other OPSYS
if (addr >= (0x10000 - Core._bios.Length) && !Core.A7800_control_register.Bit(2))
{
return Core._bios[addr - (0x10000 - Core._bios.Length)];
}
else
{
if (addr >= 0xC000)
{
// bank 7 is fixed
return Core._rom[Core._rom.Length - (0x10000 - addr)];
}
else if (addr >= 0x8000)
{
// return whatever bank is there
int temp_addr = addr - 0x8000;
return Core._rom[temp_addr + bank * 0x4000];
}
else
{
if (Core.cart_RAM == 0 && !Core.pokey)
{
// return bank 6
int temp_addr = addr - 0x4000;
if (!Core.small_flag)
{
return Core._rom[temp_addr + 6 * 0x4000];
}
else
{
if (Core.PAL_Kara)
{
return Core._rom[temp_addr + 2 * 0x4000];
}
else
{
// Should never get here, but in case we do just return FF
return 0xFF;
}
}
}
else if (Core.cart_RAM > 0)
{
// return RAM
if (Core.cart_RAM==8 && addr >= 0x6000)
{
return RAM[addr - 0x6000];
}
else if (Core.cart_RAM==16)
{
return RAM[addr - 0x4000];
}
else
{
// this would coorespond to reading from 0x4000-0x5FFF with only 8k of RAM
// Let's just return FF for now
return 0xFF;
}
}
else
{
// pokey
return 0xFF;
}
}
}
}
}
public override byte PeekMemory(ushort addr)
{
return ReadMemory(addr);
}
public override void WriteMemory(ushort addr, byte value)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
Core._hsram[addr - 0x1000] = value;
}
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
}
else
{
Core.RAM[0x800 + addr & 0x7FF] = value;
}
}
else
{
// cartridge and other OPSYS
if (addr>=0x8000)
{
bank = (byte)(value & (Core.small_flag ? 0x3 : 0x7));
}
else if (Core.pokey)
{
}
else if (Core.cart_RAM > 0)
{
if (Core.cart_RAM==8 && addr >= 0x6000)
{
RAM[addr - 0x6000] = value;
}
else if (Core.cart_RAM==16)
{
RAM[addr - 0x4000] = value;
}
}
}
}
public override void PokeMemory(ushort addr, byte value)
{
WriteMemory(addr, value);
}
public override void SyncState(Serializer ser)
{
ser.Sync("Bank", ref bank);
ser.Sync("RAM", ref RAM, false);
}
}
}

View File

@ -0,0 +1,113 @@
using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
using System;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
// Super Game mapper but with extra ROM at the start of the file
// Have to add 1 to bank number to get correct bank value
public class MapperSGE : MapperBase
{
public byte bank = 0;
public override byte ReadMemory(ushort addr)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
return Core._hsram[addr - 0x1000];
}
return 0xFF;
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
return Core._hsbios[addr - 0x3000];
}
else
{
return Core.RAM[0x800 + addr & 0x7FF];
}
}
else
{
// cartridge and other OPSYS
if (addr >= (0x10000 - Core._bios.Length) && !Core.A7800_control_register.Bit(2))
{
return Core._bios[addr - (0x10000 - Core._bios.Length)];
}
else
{
if (addr >=0xC000)
{
// bank 7 is fixed
return Core._rom[Core._rom.Length - (0x10000 - addr)];
}
else if (addr >= 0x8000)
{
// return whatever bank is there
// but remember we need to add 1 to adjust for the extra bank at the beginning
int temp_addr = addr - 0x8000;
return Core._rom[temp_addr + (bank + 1) * 0x4000];
}
else
{
// return the 16k extra ROM (located at beginning of file)
int temp_addr = addr - 0x4000;
return Core._rom[temp_addr];
}
}
}
}
public override byte PeekMemory(ushort addr)
{
return ReadMemory(addr);
}
public override void WriteMemory(ushort addr, byte value)
{
if (addr >= 0x1000 && addr < 0x1800)
{
//could be hsbios RAM here
if (Core._hsbios != null)
{
Core._hsram[addr - 0x1000] = value;
}
}
else if (addr < 0x4000)
{
// could be either RAM mirror or ROM
if (addr >= 0x3000 && Core._hsbios != null)
{
}
else
{
Core.RAM[0x800 + addr & 0x7FF] = value;
}
}
else
{
// cartridge and other OPSYS
if (addr>=0x8000)
{
bank = (byte)(value & 0x7);
}
}
}
public override void PokeMemory(ushort addr, byte value)
{
WriteMemory(addr, value);
}
public override void SyncState(Serializer ser)
{
ser.Sync("Bank", ref bank);
}
}
}

View File

@ -1,5 +1,4 @@
using System; using System;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Common.NumberExtensions; using BizHawk.Common.NumberExtensions;
using BizHawk.Common; using BizHawk.Common;
@ -24,17 +23,21 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public byte[] obj; // up to 32 bytes can compose one object public byte[] obj; // up to 32 bytes can compose one object
} }
// technically there is no limit on he number of graphics objects, but since dma is automatically killed // technically there is no limit on the number of graphics objects, but since dma is automatically killed
// at the end of a scanline, we have an effective limit // at the end of a scanline, we have an effective limit
GFX_Object[] GFX_Objects = new GFX_Object[128]; GFX_Object[,] GFX_Objects = new GFX_Object[2,128];
int GFX_index = 0;
public int _frameHz = 60; public int _frameHz = 60;
public int _screen_width = 320; public int _screen_width = 320;
public int _screen_height = 263; public int _screen_height = 263;
public int _vblanklines = 20;
public int[] _vidbuffer; public int[] _vidbuffer;
public int[] _palette; public int[] _palette;
public int[] scanline_buffer = new int[320]; public int[] scanline_buffer = new int[320];
public int[] bg_temp = new int[320]; // since BG color can be changed midscanline, we need to account for this here.
public int[] GetVideoBuffer() public int[] GetVideoBuffer()
{ {
@ -42,9 +45,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
} }
public int VirtualWidth => 320; public int VirtualWidth => 320;
public int VirtualHeight => _screen_height; public int VirtualHeight => _screen_height - _vblanklines;
public int BufferWidth => 320; public int BufferWidth => 320;
public int BufferHeight => _screen_height; public int BufferHeight => _screen_height - _vblanklines;
public int BackgroundColor => unchecked((int)0xff000000); public int BackgroundColor => unchecked((int)0xff000000);
public int VsyncNumerator => _frameHz; public int VsyncNumerator => _frameHz;
public int VsyncDenominator => 1; public int VsyncDenominator => 1;
@ -71,7 +74,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public int header_read_time = 8; // default for 4 byte headers (10 for 5 bytes ones) public int header_read_time = 8; // default for 4 byte headers (10 for 5 bytes ones)
public int graphics_read_time = 3; // depends on content of graphics header public int graphics_read_time = 3; // depends on content of graphics header
public int DMA_phase_next; public int DMA_phase_next;
public int base_scanline;
public ushort display_zone_pointer; public ushort display_zone_pointer;
public int display_zone_counter; public int display_zone_counter;
@ -82,26 +84,26 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public bool current_DLL_H16; public bool current_DLL_H16;
public bool current_DLL_H8; public bool current_DLL_H8;
public int header_counter; public bool overrun_dma;
public int header_counter_max;
public int header_pointer; // since headers could be 4 or 5 bytes, we need a seperate pointer
// write mode is actually persistent but exists outside of the regs
public bool global_write_mode; public bool global_write_mode;
public int header_counter;
public int[] header_counter_max = new int [2];
public int header_pointer; // since headers could be 4 or 5 bytes, we need a seperate pointer
// each frame contains 263 scanlines // each frame contains 263 scanlines
// each scanline consists of 113.5 CPU cycles (fast access) which equates to 454 Maria cycles // each scanline consists of 113.5 CPU cycles (fast access) which equates to 454 Maria cycles
// In total there are 29850.5 CPU cycles (fast access) in a frame // In total there are 29850.5 CPU cycles (fast access) in a frame
public void RunFrame() public void RunFrame()
{ {
scanline = 0; scanline = 0;
global_write_mode = false;
Core.Maria_regs[8] = 0x80; // indicates VBlank state Core.Maria_regs[8] = 0x80; // indicates VBlank state
// we start off in VBlank for 20 scanlines // we start off in VBlank for 20 scanlines
// at the end of vblank is a DMA to set up the display for the start of drawing // at the end of vblank is a DMA to set up the display for the start of drawing
// this is free time for the CPU to set up display lists // this is free time for the CPU to set up display lists
while (scanline < 19) while (scanline < 20)
{ {
Core.RunCPUCycle(); Core.RunCPUCycle();
cycle++; cycle++;
@ -120,14 +122,11 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
// Since long shut down loads up the next zone, this basically loads up the DLL for the first zone // Since long shut down loads up the next zone, this basically loads up the DLL for the first zone
sl_DMA_complete = false; sl_DMA_complete = false;
do_dma = false; do_dma = false;
Core.Maria_regs[8] = 0; // we have now left VBLank
for (int i=0; i<454;i++) for (int i=0; i<454;i++)
{ {
if (i<28) if(i==28 && Core.Maria_regs[0x1C].Bit(6) && !Core.Maria_regs[0x1C].Bit(5))
{
// DMA doesn't start until 7 CPU cycles into a scanline
}
else if (i==28 && Core.Maria_regs[0x1C].Bit(6) && !Core.Maria_regs[0x1C].Bit(5))
{ {
Core.cpu_halt_pending = true; Core.cpu_halt_pending = true;
DMA_phase = DMA_START_UP; DMA_phase = DMA_START_UP;
@ -161,26 +160,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
scanline++; scanline++;
cycle = 0; cycle = 0;
do_dma = false; do_dma = false;
Core.Maria_regs[8] = 0; // we have now left VBLank
base_scanline = 0;
sl_DMA_complete = false; sl_DMA_complete = false;
Core.cpu.RDY = true; Core.cpu.RDY = true;
// Now proceed with the remaining scanlines // Now proceed with the remaining scanlines
// the first one is a pre-render line, since we didn't actually put any data into the buffer yet // the first one is a pre-render line, since we didn't actually put any data into the buffer yet
while (scanline < 263) while (scanline < _screen_height)
{ {
if (cycle == 28 && Core.Maria_regs[0x1C].Bit(6) && !Core.Maria_regs[0x1C].Bit(5))
if (cycle < 28)
{
// DMA doesn't start until 7 CPU cycles into a scanline
}
else if (cycle == 28 && Core.Maria_regs[0x1C].Bit(6) && !Core.Maria_regs[0x1C].Bit(5))
{ {
Core.cpu_halt_pending = true; Core.cpu_halt_pending = true;
DMA_phase = DMA_START_UP; DMA_phase = DMA_START_UP;
DMA_phase_counter = 0; DMA_phase_counter = 0;
do_dma = true; do_dma = true;
sl_DMA_complete = false;
} }
else if (!sl_DMA_complete && do_dma) else if (!sl_DMA_complete && do_dma)
{ {
@ -194,6 +187,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
current_DLL_DLI = false; current_DLL_DLI = false;
} }
if (overrun_dma && sl_DMA_complete)
{
if (GFX_index == 1)
{
GFX_index = 0;
}
else
{
GFX_index = 1;
}
overrun_dma = false;
}
if (DLI_countdown > 0) if (DLI_countdown > 0)
{ {
DLI_countdown--; DLI_countdown--;
@ -203,6 +210,28 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
} }
} }
if (cycle > 133)
{
bg_temp[cycle - 134] = Core.Maria_regs[0];
}
if (cycle == 453 && !sl_DMA_complete && do_dma && (DMA_phase == DMA_GRAPHICS || DMA_phase == DMA_HEADER))
{
overrun_dma = true;
//Console.WriteLine(scanline);
if (current_DLL_offset == 0)
{
DMA_phase = DMA_SHUTDOWN_LAST;
}
else
{
DMA_phase = DMA_SHUTDOWN_OTHER;
}
DMA_phase_counter = 0;
}
Core.RunCPUCycle(); Core.RunCPUCycle();
cycle++; cycle++;
@ -214,14 +243,23 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
// add the current graphics to the buffer // add the current graphics to the buffer
draw_scanline(scanline - 21); draw_scanline(scanline - 21);
} }
//Console.Write("Scanline");
//Console.WriteLine(scanline - 21);
scanline++; scanline++;
cycle = 0; cycle = 0;
Core.tia._hsyncCnt = 0; Core.tia._hsyncCnt = 0;
Core.cpu.RDY = true; Core.cpu.RDY = true;
do_dma = false;
sl_DMA_complete = false; // swap sacnline buffers
if (!overrun_dma)
{
if (GFX_index == 1)
{
GFX_index = 0;
}
else
{
GFX_index = 1;
}
}
} }
} }
} }
@ -261,7 +299,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
if (DMA_phase_counter==1) if (DMA_phase_counter==1)
{ {
header_counter++; header_counter++;
GFX_Objects[header_counter].addr = ReadMemory((ushort)(current_DLL_addr + header_pointer)); GFX_Objects[GFX_index, header_counter].addr = ReadMemory((ushort)(current_DLL_addr + header_pointer));
header_pointer++; header_pointer++;
byte temp = ReadMemory((ushort)(current_DLL_addr + header_pointer)); byte temp = ReadMemory((ushort)(current_DLL_addr + header_pointer));
// if there is no width, then we must have an extended header // if there is no width, then we must have an extended header
@ -286,12 +324,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
else else
{ {
// we are in 5 Byte header mode (i.e. using the character map) // we are in 5 Byte header mode (i.e. using the character map)
GFX_Objects[header_counter].write_mode = temp.Bit(7); GFX_Objects[GFX_index, header_counter].write_mode = temp.Bit(7);
global_write_mode = temp.Bit(7); global_write_mode = temp.Bit(7);
GFX_Objects[header_counter].ind_mode = temp.Bit(5); GFX_Objects[GFX_index, header_counter].ind_mode = temp.Bit(5);
header_pointer++; header_pointer++;
temp = (byte)(ReadMemory((ushort)(current_DLL_addr + header_pointer))); temp = (byte)(ReadMemory((ushort)(current_DLL_addr + header_pointer)));
GFX_Objects[header_counter].addr |= (ushort)(temp << 8); GFX_Objects[GFX_index, header_counter].addr |= (ushort)(temp << 8);
header_pointer++; header_pointer++;
temp = ReadMemory((ushort)(current_DLL_addr + header_pointer)); temp = ReadMemory((ushort)(current_DLL_addr + header_pointer));
int temp_w = (temp & 0x1F); // this is the 2's complement of width (for reasons that escape me) int temp_w = (temp & 0x1F); // this is the 2's complement of width (for reasons that escape me)
@ -299,18 +337,18 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
if (temp_w == 0) if (temp_w == 0)
{ {
// important note here. In 5 byte mode, width 0 actually counts as 32 // important note here. In 5 byte mode, width 0 actually counts as 32
GFX_Objects[header_counter].width = 32; GFX_Objects[GFX_index, header_counter].width = 32;
} }
else else
{ {
temp_w = (temp_w - 1); temp_w = (temp_w - 1);
temp_w = (0x1F - temp_w); temp_w = (0x1F - temp_w);
GFX_Objects[header_counter].width = (byte)(temp_w & 0x1F); GFX_Objects[GFX_index, header_counter].width = (byte)(temp_w & 0x1F);
} }
GFX_Objects[header_counter].palette = (byte)((temp & 0xE0) >> 5); GFX_Objects[GFX_index, header_counter].palette = (byte)((temp & 0xE0) >> 5);
header_pointer++; header_pointer++;
GFX_Objects[header_counter].h_pos = ReadMemory((ushort)(current_DLL_addr + header_pointer)); GFX_Objects[GFX_index, header_counter].h_pos = ReadMemory((ushort)(current_DLL_addr + header_pointer));
header_pointer++; header_pointer++;
DMA_phase_next = DMA_GRAPHICS; DMA_phase_next = DMA_GRAPHICS;
@ -323,21 +361,21 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
int temp_w = (temp & 0x1F); // this is the 2's complement of width (for reasons that escape me) int temp_w = (temp & 0x1F); // this is the 2's complement of width (for reasons that escape me)
temp_w = (temp_w - 1); temp_w = (temp_w - 1);
temp_w = (0x1F - temp_w); temp_w = (0x1F - temp_w);
GFX_Objects[header_counter].width = (byte)(temp_w & 0x1F); GFX_Objects[GFX_index, header_counter].width = (byte)(temp_w & 0x1F);
GFX_Objects[header_counter].palette = (byte)((temp & 0xE0) >> 5); GFX_Objects[GFX_index, header_counter].palette = (byte)((temp & 0xE0) >> 5);
header_pointer++; header_pointer++;
temp = (byte)(ReadMemory((ushort)(current_DLL_addr + header_pointer))); temp = (byte)(ReadMemory((ushort)(current_DLL_addr + header_pointer)));
GFX_Objects[header_counter].addr |= (ushort)(temp << 8); GFX_Objects[GFX_index, header_counter].addr |= (ushort)(temp << 8);
header_pointer++; header_pointer++;
GFX_Objects[header_counter].h_pos = ReadMemory((ushort)(current_DLL_addr + header_pointer)); GFX_Objects[GFX_index, header_counter].h_pos = ReadMemory((ushort)(current_DLL_addr + header_pointer));
header_pointer++; header_pointer++;
DMA_phase_next = DMA_GRAPHICS; DMA_phase_next = DMA_GRAPHICS;
GFX_Objects[header_counter].write_mode = global_write_mode; GFX_Objects[GFX_index, header_counter].write_mode = global_write_mode;
GFX_Objects[header_counter].ind_mode = false; GFX_Objects[GFX_index, header_counter].ind_mode = false;
header_read_time = 8; header_read_time = 8;
} }
@ -358,37 +396,38 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ushort addr_t = 0; ushort addr_t = 0;
// in 5 byte mode, we first have to check if we are in direct or indirect mode // in 5 byte mode, we first have to check if we are in direct or indirect mode
if (GFX_Objects[header_counter].ind_mode) if (GFX_Objects[GFX_index, header_counter].ind_mode)
{ {
int ch_size = 0; int ch_size = 0;
if (Core.Maria_regs[0x1C].Bit(4)) if (Core.Maria_regs[0x1C].Bit(4))
{ {
graphics_read_time = 9 * GFX_Objects[header_counter].width + 3; graphics_read_time = 9 * GFX_Objects[GFX_index, header_counter].width;
ch_size = 2; ch_size = 2;
GFX_Objects[GFX_index, header_counter].width *= 2;
} }
else else
{ {
graphics_read_time = 6 * GFX_Objects[header_counter].width + 3; graphics_read_time = 6 * GFX_Objects[GFX_index, header_counter].width;
ch_size = 1; ch_size = 1;
} }
// the address here is specified by CHAR_BASE maria registers // the address here is specified by CHAR_BASE maria registers
// ushort addr = (ushort)(GFX_Objects[header_counter].addr & 0xFF); // ushort addr = (ushort)(GFX_Objects[header_counter].addr & 0xFF);
for (int i = 0; i < GFX_Objects[header_counter].width; i++) for (int i = 0; i < GFX_Objects[GFX_index, header_counter].width; i++)
{ {
addr_t = ReadMemory((ushort)(GFX_Objects[header_counter].addr + i)); addr_t = ReadMemory((ushort)(GFX_Objects[GFX_index, header_counter].addr + i));
addr_t |= (ushort)((Core.Maria_regs[0x14] + current_DLL_offset) << 8); addr_t |= (ushort)((Core.Maria_regs[0x14] + current_DLL_offset) << 8);
if ((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11))) if (((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11))) && (addr_t >= 0x8000))
{ {
if (i * ch_size < 32) if (i * ch_size < 128)
{ {
GFX_Objects[header_counter].obj[i * ch_size] = 0; GFX_Objects[GFX_index, header_counter].obj[i * ch_size] = 0;
} }
if ((i * ch_size + 1 < 32) && (ch_size == 2)) if ((i * ch_size + 1 < 128) && (ch_size == 2))
{ {
GFX_Objects[header_counter].obj[i * ch_size + 1] = 0; GFX_Objects[GFX_index, header_counter].obj[i * ch_size + 1] = 0;
} }
if (ch_size == 1) if (ch_size == 1)
{ {
@ -402,32 +441,33 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
} }
else else
{ {
if (i * ch_size < 32) if (i * ch_size < 128)
{ {
GFX_Objects[header_counter].obj[i * ch_size] = ReadMemory(addr_t); GFX_Objects[GFX_index, header_counter].obj[i * ch_size] = ReadMemory(addr_t);
} }
if ((i * ch_size + 1 < 32) && (ch_size == 2)) if (((i * ch_size + 1) < 128) && (ch_size == 2))
{ {
GFX_Objects[header_counter].obj[i * ch_size + 1] = ReadMemory(addr_t); GFX_Objects[GFX_index, header_counter].obj[i * ch_size + 1] = ReadMemory((ushort)(addr_t + 1));
} }
} }
} }
} }
else else
{ {
graphics_read_time = 3 * GFX_Objects[header_counter].width; graphics_read_time = 3 * GFX_Objects[GFX_index, header_counter].width;
for (int i = 0; i < GFX_Objects[header_counter].width; i++) for (int i = 0; i < GFX_Objects[GFX_index, header_counter].width; i++)
{ {
addr_t = (ushort)(GFX_Objects[header_counter].addr + (current_DLL_offset << 8) + i); addr_t = (ushort)(GFX_Objects[GFX_index, header_counter].addr + (current_DLL_offset << 8) + i);
if ((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11)))
if (((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11))) && (addr_t >= 0x8000))
{ {
GFX_Objects[header_counter].obj[i] = 0; GFX_Objects[GFX_index, header_counter].obj[i] = 0;
graphics_read_time -= 3; graphics_read_time -= 3;
} }
else else
{ {
GFX_Objects[header_counter].obj[i] = ReadMemory(addr_t); GFX_Objects[GFX_index, header_counter].obj[i] = ReadMemory(addr_t);
} }
} }
} }
@ -448,7 +488,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
Core.cpu_resume_pending = true; Core.cpu_resume_pending = true;
sl_DMA_complete = true; sl_DMA_complete = true;
current_DLL_offset -= 1; // this is reduced by one for each scanline, which changes where graphics are fetched current_DLL_offset -= 1; // this is reduced by one for each scanline, which changes where graphics are fetched
header_counter_max = header_counter; header_counter_max[GFX_index] = header_counter;
header_counter = -1; header_counter = -1;
header_pointer = 0; header_pointer = 0;
return; return;
@ -471,10 +511,11 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
current_DLL_offset = (byte)(temp & 0xF); current_DLL_offset = (byte)(temp & 0xF);
current_DLL_DLI = temp.Bit(7); current_DLL_DLI = temp.Bit(7);
current_DLL_H16 = temp.Bit(6); current_DLL_H16 = temp.Bit(6);
current_DLL_H8 = temp.Bit(5); current_DLL_H8 = temp.Bit(5);
header_counter_max = header_counter; header_counter_max[GFX_index] = header_counter;
header_counter = -1; header_counter = -1;
header_pointer = 0; header_pointer = 0;
} }
@ -490,32 +531,177 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
int local_palette; int local_palette;
int index; int index;
int color; int color;
int local_GFX_index;
local_GFX_index = (GFX_index == 1) ? 0 : 1; // whatever the current index is, we use the opposite
int disp_mode = Core.Maria_regs[0x1C] & 0x3; int disp_mode = Core.Maria_regs[0x1C] & 0x3;
int temp_bg = Core.Maria_regs[0];
for (int i = 0; i < 320; i++) for (int i = 0; i < 320; i++)
{ {
scanline_buffer[i] = _palette[temp_bg]; scanline_buffer[i] = _palette[bg_temp[i]];
} }
for (int i = 0; i < header_counter_max; i++) for (int i = 0; i < header_counter_max[local_GFX_index]; i++)
{ {
local_start = GFX_Objects[i].h_pos; local_start = GFX_Objects[local_GFX_index, i].h_pos;
local_palette = GFX_Objects[i].palette; local_palette = GFX_Objects[local_GFX_index, i].palette;
// the two different rendering paths are basically controlled by write mode // the two different rendering paths are basically controlled by write mode
if (GFX_Objects[i].write_mode) if (GFX_Objects[local_GFX_index, i].write_mode)
{ {
if (disp_mode == 0)
{
local_width = GFX_Objects[local_GFX_index, i].width;
for (int j = 0; j < local_width; j++)
{
for (int k = 3; k >= 0; k--)
{
index = local_start * 2 + j * 4 + (3 - k);
if (index > 511)
{
index -= 512;
}
if (index < 320)
{
color = GFX_Objects[local_GFX_index, i].obj[j];
// this is now the color index (0-3) we choose from the palette
if (k >= 2)
{
color = (((color >> 2) & 0x3) << 2) + ((color >> 6) & 0x3);
}
else
{
color = ((color & 0x3) << 2) + ((color >> 4) & 0x3);
}
if ((color != 0) && (color != 4) && (color != 8) && (color != 12)) // transparent
{
color = ((local_palette & 4) << 2) + color;
color = Core.Maria_regs[color];
scanline_buffer[index] = _palette[color];
}
}
}
}
}
else if (disp_mode == 2) // note: 1 is not used
{
local_width = GFX_Objects[local_GFX_index, i].width;
for (int j = 0; j < local_width; j++)
{
for (int k = 7; k >= 0; k--)
{
index = local_start * 4 + j * 8 + (7 - k);
if (index > 511)
{
index -= 512;
}
if (index < 320)
{
color = GFX_Objects[local_GFX_index, i].obj[j];
// this is now the color index (0-3) we choose from the palette
if (k >= 6)
{
color = ((color >> 6) & 0x2) + ((color >> 3) & 0x1);
}
else if (k >= 4)
{
color = ((color >> 5) & 0x2) + ((color >> 2) & 0x1);
}
else if (k >= 2)
{
color = ((color >> 4) & 0x2) + ((color >> 1) & 0x1);
}
else
{
color = ((color >> 3) & 0x2) + (color & 0x1);
}
if (color != 0) // transparent
{
color = ((local_palette & 4) << 2) + color;
color = Core.Maria_regs[color];
scanline_buffer[index] = _palette[color];
}
}
}
}
}
else
{
local_width = GFX_Objects[local_GFX_index, i].width;
for (int j = 0; j < local_width; j++)
{
for (int k = 3; k >= 0; k--)
{
index = local_start * 2 + j * 4 + (3 - k);
if (index > 511)
{
index -= 512;
}
if (index < 320)
{
color = GFX_Objects[local_GFX_index, i].obj[j];
int temp_color = color;
// this is now the color index (0-3) we choose from the palette
if (k >= 3)
{
color = ((color >> 7) & 0x1);
temp_color = (local_palette & 4) + ((temp_color >> 2) & 3);
}
else if (k >= 2)
{
color = ((color >> 6) & 0x1);
temp_color = (local_palette & 4) + ((temp_color >> 2) & 3);
}
else if (k >= 1)
{
color = ((color >> 5) & 0x1);
temp_color = (local_palette & 4) + (temp_color & 3);
}
else
{
color = ((color >> 4) & 0x1);
temp_color = (local_palette & 4) + (temp_color & 3);
}
if (color != 0) // transparent
{
color = (temp_color << 2) + 2;
color = Core.Maria_regs[color];
scanline_buffer[index] = _palette[color];
}
}
}
}
}
} }
else else
{ {
if (disp_mode == 0) if (disp_mode == 0)
{ {
local_width = GFX_Objects[i].width; local_width = GFX_Objects[local_GFX_index, i].width;
for (int j = 0; j < local_width; j++) for (int j = 0; j < local_width; j++)
{ {
@ -523,16 +709,19 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
index = local_start * 2 + j * 8 + (7 - k); index = local_start * 2 + j * 8 + (7 - k);
if (index > 511) index -= 512; if (index > 511)
{
index -= 512;
}
if (index < 320) if (index < 320)
{ {
color = GFX_Objects[i].obj[j]; color = GFX_Objects[local_GFX_index, i].obj[j];
// this is now the color index (0-3) we choose from the palette // this is now the color index (0-3) we choose from the palette
if (k >= 6) if (k >= 6)
{ {
color = (color >> 6) & 0x3; color = (color >> 6) & 0x3;
} }
else if (k >= 4) else if (k >= 4)
{ {
@ -552,8 +741,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
color = Core.Maria_regs[local_palette * 4 + color]; color = Core.Maria_regs[local_palette * 4 + color];
// the top 4 bits from this are the color, the bottom 4 are the luminosity
// this is already conveniently arranged in the palette
scanline_buffer[index] = _palette[color]; scanline_buffer[index] = _palette[color];
} }
} }
@ -562,53 +749,47 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
} }
else if (disp_mode == 2) // note: 1 is not used else if (disp_mode == 2) // note: 1 is not used
{ {
local_width = GFX_Objects[i].width; local_width = GFX_Objects[local_GFX_index, i].width;
// here the palette is determined by palette bit 2 only // here the palette is determined by palette bit 2 only
// hence only palette 0 or 4 is available // hence only palette 0 or 4 is available
local_palette = GFX_Objects[i].palette & 0x4; local_palette = GFX_Objects[local_GFX_index, i].palette & 0x4;
int temp_c0 = GFX_Objects[i].palette & 0x1; int temp_c0 = GFX_Objects[local_GFX_index, i].palette & 0x1;
int temp_c1 = GFX_Objects[i].palette & 0x2; int temp_c1 = GFX_Objects[local_GFX_index, i].palette & 0x2;
for (int j = 0; j < local_width; j++) for (int j = 0; j < local_width; j++)
{ {
for (int k = 7; k >= 0; k--) for (int k = 7; k >= 0; k--)
{ {
color = (GFX_Objects[i].obj[j] >> k) & 1; color = (GFX_Objects[local_GFX_index, i].obj[j] >> k) & 1;
color = (color << 1) | ((k % 2 == 0) ? temp_c0 : temp_c1); color = (color << 1) | ((k % 2 == 0) ? temp_c0 : temp_c1);
index = local_start * 2 + j * 8 + (7 - k); index = local_start * 2 + j * 8 + (7 - k);
if (index > 511) index -= 512; if (index > 511) index -= 512;
if (index < 320) if (index < 320)
{ {
color = Core.Maria_regs[local_palette + color]; color = Core.Maria_regs[local_palette + color];
// the top 4 bits from this are the color, the bottom 4 are the luminosity
// this is already conveniently arranged in the palette
scanline_buffer[index] = _palette[color]; scanline_buffer[index] = _palette[color];
} }
} }
} }
} }
else else
{ {
local_width = GFX_Objects[i].width; local_width = GFX_Objects[local_GFX_index, i].width;
for (int j = 0; j < local_width; j++) for (int j = 0; j < local_width; j++)
{ {
for (int k = 7; k >= 0; k--) for (int k = 7; k >= 0; k--)
{ {
color = (GFX_Objects[i].obj[j] >> k) & 1; color = (GFX_Objects[local_GFX_index, i].obj[j] >> k) & 1;
index = local_start * 2 + j * 8 + (7 - k); index = local_start * 2 + j * 8 + (7 - k);
if (index > 511) index -= 512; if (index > 511) index -= 512;
if (index < 320 && color == 1) if (index < 320 && color == 1)
{ {
color = Core.Maria_regs[local_palette * 4 + 2]; // automatically use index 2 here color = Core.Maria_regs[local_palette * 4 + 2]; // automatically use index 2 here
// the top 4 bits from this are the color, the bottom 4 are the luminosity
// this is already conveniently arranged in the palette
scanline_buffer[index] = _palette[color]; scanline_buffer[index] = _palette[color];
} }
} }
@ -628,9 +809,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
_vidbuffer = new int[VirtualWidth * VirtualHeight]; _vidbuffer = new int[VirtualWidth * VirtualHeight];
for (int j = 0; j < 2; j++)
{
for (int i = 0; i < 128; i++) for (int i = 0; i < 128; i++)
{ {
GFX_Objects[i].obj = new byte[32]; GFX_Objects[j, i].obj = new byte[128];
}
} }
} }
@ -641,7 +825,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
ser.BeginSection("Maria"); ser.BeginSection("Maria");
ser.Sync("global write mode", ref global_write_mode); ser.Sync("GFX_index", ref GFX_index);
ser.EndSection(); ser.EndSection();
} }

View File

@ -35,7 +35,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
else else
{ {
return tia.ReadMemory((ushort)(addr & 0x1F), false); return tia.ReadMemory((ushort)(addr & 0x1F), false);
//return TIA_regs[addr & 0x1F]; // TODO: what to return here?
} }
} }
else if ((addr & 0xFCE0) == 0x20) else if ((addr & 0xFCE0) == 0x20)
@ -110,7 +109,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
} }
else else
{ {
TIA_regs[addr & 0x1F] = value;
tia.WriteMemory((ushort)(addr & 0x1F), value, false); tia.WriteMemory((ushort)(addr & 0x1F), value, false);
} }
} }
@ -120,12 +118,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{ {
// register 8 is read only and controlled by Maria // register 8 is read only and controlled by Maria
var temp = addr & 0x1F; var temp = addr & 0x1F;
if (temp != 8) if (temp != 8)
Maria_regs[temp] = value; Maria_regs[temp] = value;
if (temp == 4) // WSYNC if (temp == 4) // WSYNC
cpu.RDY = false; cpu.RDY = false;
/*
for (int i = 0; i < 0x20; i++)
{
Console.Write(Maria_regs[i]);
Console.Write(" ");
}
Console.WriteLine(maria.scanline);
*/
} }
else else
{ {

View File

@ -14,6 +14,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
private bool _doTicks; private bool _doTicks;
private int _spf;
public int _hsyncCnt; public int _hsyncCnt;
private int _capChargeStart; private int _capChargeStart;
private bool _capCharging; private bool _capCharging;
@ -31,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
_capChargeStart = 0; _capChargeStart = 0;
_capCharging = false; _capCharging = false;
AudioClocks = 0; AudioClocks = 0;
_spf = (Core.maria._frameHz > 55) ? 740 : 880;
_doTicks = false; _doTicks = false;
} }
@ -92,35 +94,95 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
// inputs 0-3 are measured by a charging capacitor, these inputs are used with the paddles and the keyboard // inputs 0-3 are measured by a charging capacitor, these inputs are used with the paddles and the keyboard
// Changing the hard coded value will change the paddle position. The range seems to be roughly 0-56000 according to values from stella // Changing the hard coded value will change the paddle position. The range seems to be roughly 0-56000 according to values from stella
// 6105 roughly centers the paddle in Breakout // 6105 roughly centers the paddle in Breakout
//INPT0-3 are used to read 2 button joysticks as well for the A7800
if (maskedAddr == 0x08) // INPT0 if (maskedAddr == 0x08) // INPT0
{
if ((Core.m6532._outputB & 0x04) == 0 && (Core.m6532._ddRb & 0x04) == 0x04)
{
Core._islag = false;
return (byte)(Core.p1_fire_2x & 0x80);
}
else
{ {
return 0; return 0;
} }
}
if (maskedAddr == 0x09) // INPT1 if (maskedAddr == 0x09) // INPT1
{
if ((Core.m6532._outputB & 0x04) == 0 && (Core.m6532._ddRb & 0x04) == 0x04)
{
Core._islag = false;
return (byte)((Core.p1_fire_2x & 0x40)<<1);
}
else
{ {
return 0; return 0;
} }
}
if (maskedAddr == 0x0A) // INPT2 if (maskedAddr == 0x0A) // INPT2
{
if ((Core.m6532._outputB & 0x10) == 0 && (Core.m6532._ddRb & 0x10) == 0x10)
{
Core._islag = false;
return (byte)(Core.p2_fire_2x & 0x80);
}
else
{ {
return 0; return 0;
} }
}
if (maskedAddr == 0x0B) // INPT3 if (maskedAddr == 0x0B) // INPT3
{
if ((Core.m6532._outputB & 0x10) == 0 && (Core.m6532._ddRb & 0x10) == 0x10)
{
Core._islag = false;
return (byte)((Core.p2_fire_2x & 0x40)<<1);
}
else
{ {
return 0; return 0;
} }
}
if (maskedAddr == 0x0C) // INPT4 if (maskedAddr == 0x0C) // INPT4
{
Core._islag = false;
if (!Core.p1_is_2button)
{ {
return Core.p1_fire; return Core.p1_fire;
} }
else if ((Core.m6532._outputB & 0x04) != 0 || (Core.m6532._ddRb & 0x04) != 0x04)
{
return Core.p1_fire;
}
else
{
return 0x80;
}
}
if (maskedAddr == 0x0D) // INPT5 if (maskedAddr == 0x0D) // INPT5
{
Core._islag = false;
if (!Core.p2_is_2button)
{ {
return Core.p2_fire; return Core.p2_fire;
} }
else if ((Core.m6532._outputB & 0x10) != 0 || (Core.m6532._ddRb & 0x10) != 0x10)
{
return Core.p2_fire;
}
else
{
return 0x80;
}
}
return 0; return 0;

View File

@ -19,8 +19,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public void GetSamplesSync(out short[] samples, out int nsamp) public void GetSamplesSync(out short[] samples, out int nsamp)
{ {
short[] ret = new short[AudioClocks * 2]; short[] ret = new short[_spf * 2];
nsamp = AudioClocks; nsamp = _spf;
GetSamples(ret); GetSamples(ret);
samples = ret; samples = ret;
} }
@ -35,8 +35,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
AudioClocks = 0; AudioClocks = 0;
} }
private readonly int _spf;
// Exposing this as GetSamplesAsync would allow this to provide async sound // Exposing this as GetSamplesAsync would allow this to provide async sound
// However, it does nothing special for async sound so I don't see a point // However, it does nothing special for async sound so I don't see a point
private void GetSamples(short[] samples) private void GetSamples(short[] samples)

View File

@ -14,6 +14,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ser.Sync("Bus_State", ref BusState); ser.Sync("Bus_State", ref BusState);
ser.Sync("Ticks", ref _doTicks); ser.Sync("Ticks", ref _doTicks);
ser.Sync("_spf", ref _spf);
// some of these things weren't in the state because they weren't needed if // some of these things weren't in the state because they weren't needed if
// states were always taken at frame boundaries // states were always taken at frame boundaries

View File

@ -602,8 +602,11 @@ namespace BizHawk.Emulation.Cores.Intellivision
bool gram = attr.Bit(11); bool gram = attr.Bit(11);
byte loc_color = (byte)(attr & 7); byte loc_color = (byte)(attr & 7);
bool color_3 = attr.Bit(12); bool color_3 = attr.Bit(12);
if (color_3 && gram) if (color_3 && gram)
{
loc_color += 8; loc_color += 8;
}
bool priority = attr.Bit(13); bool priority = attr.Bit(13);
byte loc_x = (byte)(x & 0xFF); byte loc_x = (byte)(x & 0xFF);
@ -752,15 +755,15 @@ namespace BizHawk.Emulation.Cores.Intellivision
{ {
cur_y = j * y_size + m; cur_y = j * y_size + m;
if ((cur_x) < (167 - x_delay) && (loc_y * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && (cur_x) >= (8 - x_delay) && (loc_y * 2 + cur_y) >= (16 - y_delay * 2)) if ((cur_x) < (167 - x_delay) && (loc_y * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && cur_x >= (8 - x_delay) && (loc_y * 2 + cur_y) >= (16 - y_delay * 2))
{ {
if (!(priority && (Collision[cur_x, loc_y * 2 + cur_y]&0x100)>0)) if (!(priority && (Collision[cur_x, loc_y * 2 + cur_y]&0x100)>0))
FrameBuffer[(loc_y * 2 + cur_y - (16 - y_delay * 2)) * 176 + (cur_x + 8) - (8 - x_delay) + BORDER_OFFSET] = ColorToRGBA(loc_color); FrameBuffer[(loc_y * 2 + cur_y - (16 - y_delay * 2)) * 176 + cur_x + x_delay + BORDER_OFFSET] = ColorToRGBA(loc_color);
} }
// a MOB does not need to be visible for it to be interracting // a MOB does not need to be visible for it to be interracting
// special case: a mob with x position 0 is counted as off // special case: a mob with x position 0 is counted as off
if (intr && pixel && (cur_x) <= 167 && (loc_y * 2 + cur_y) < 210 && loc_x != 0) if (intr && pixel && cur_x <= 167 && (loc_y * 2 + cur_y) < 210 && loc_x != 0)
{ {
Collision[cur_x, loc_y * 2 + cur_y] |= (ushort)(1 << i); Collision[cur_x, loc_y * 2 + cur_y] |= (ushort)(1 << i);
} }
@ -770,7 +773,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
if ((cur_x + 1) < (167 - x_delay) && (loc_y * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && (cur_x + 1) >= (8 - x_delay) && (loc_y * 2 + cur_y) >= (16 - y_delay * 2)) if ((cur_x + 1) < (167 - x_delay) && (loc_y * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && (cur_x + 1) >= (8 - x_delay) && (loc_y * 2 + cur_y) >= (16 - y_delay * 2))
{ {
if (!(priority && (Collision[cur_x + 1, loc_y * 2 + cur_y] & 0x100) > 0)) if (!(priority && (Collision[cur_x + 1, loc_y * 2 + cur_y] & 0x100) > 0))
FrameBuffer[(loc_y * 2 + cur_y - (16 - y_delay * 2)) * 176 + (cur_x + 8) + 1 - (8 - x_delay) + BORDER_OFFSET] = ColorToRGBA(loc_color); FrameBuffer[(loc_y * 2 + cur_y - (16 - y_delay * 2)) * 176 + cur_x + x_delay + 1 + BORDER_OFFSET] = ColorToRGBA(loc_color);
} }
//a MOB does not need to be visible for it to be interracting //a MOB does not need to be visible for it to be interracting
//special case: a mob with x position 0 is counted as off //special case: a mob with x position 0 is counted as off
@ -797,15 +800,15 @@ namespace BizHawk.Emulation.Cores.Intellivision
{ {
cur_y = j * y_size + m; cur_y = j * y_size + m;
if ((cur_x) < (167 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && (cur_x) >= (8 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) >= (16 - y_delay * 2)) if ((cur_x) < (167 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && cur_x >= (8 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) >= (16 - y_delay * 2))
{ {
if (!(priority && (Collision[cur_x, (loc_y + 4 * y_size) * 2 + cur_y] & 0x100) > 0)) if (!(priority && (Collision[cur_x, (loc_y + 4 * y_size) * 2 + cur_y] & 0x100) > 0))
FrameBuffer[((loc_y + 4 * y_size) * 2 + cur_y - (16 - y_delay * 2)) * 176 + (cur_x + 8) - (8 - x_delay) + BORDER_OFFSET] = ColorToRGBA(loc_color); FrameBuffer[((loc_y + 4 * y_size) * 2 + cur_y - (16 - y_delay * 2)) * 176 + cur_x + x_delay + BORDER_OFFSET] = ColorToRGBA(loc_color);
} }
// a MOB does not need to be visible for it to be interracting // a MOB does not need to be visible for it to be interracting
// special case: a mob with x position 0 is counted as off // special case: a mob with x position 0 is counted as off
if (intr && pixel && (cur_x) <= 167 && ((loc_y + 4 * y_size) * 2 + cur_y) < 210 && loc_x != 0) if (intr && pixel && cur_x <= 167 && ((loc_y + 4 * y_size) * 2 + cur_y) < 210 && loc_x != 0)
{ {
Collision[cur_x, (loc_y + 4 * y_size) * 2 + cur_y] |= (ushort)(1 << i); Collision[cur_x, (loc_y + 4 * y_size) * 2 + cur_y] |= (ushort)(1 << i);
} }
@ -815,7 +818,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
if ((cur_x + 1) < (167 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && (cur_x + 1) >= (8 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) >= (16 - y_delay * 2)) if ((cur_x + 1) < (167 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) < (208 - y_delay * 2) && pixel && vis && (cur_x + 1) >= (8 - x_delay) && ((loc_y + 4 * y_size) * 2 + cur_y) >= (16 - y_delay * 2))
{ {
if (!(priority && (Collision[cur_x + 1, (loc_y + 4 * y_size) * 2 + cur_y] & 0x100) > 0)) if (!(priority && (Collision[cur_x + 1, (loc_y + 4 * y_size) * 2 + cur_y] & 0x100) > 0))
FrameBuffer[((loc_y + 4 * y_size) * 2 + cur_y - (16 - y_delay * 2)) * 176 + (cur_x + 8) + 1 - (8 - x_delay) + BORDER_OFFSET] = ColorToRGBA(loc_color); FrameBuffer[((loc_y + 4 * y_size) * 2 + cur_y - (16 - y_delay * 2)) * 176 + cur_x + x_delay + 1 + BORDER_OFFSET] = ColorToRGBA(loc_color);
} }
// a MOB does not need to be visible for it to be interracting // a MOB does not need to be visible for it to be interracting

View File

@ -49,6 +49,7 @@ namespace BizHawk.Emulation.Cores.Consoles.NEC.PCFX
public int CpuEmulation; public int CpuEmulation;
public int Port1; public int Port1;
public int Port2; public int Port2;
public int PixelPro;
} }
[BizImport(CC)] [BizImport(CC)]

View File

@ -222,6 +222,10 @@ namespace BizHawk.Emulation.Cores.Consoles.NEC.PCFX
[DeepEqualsIgnore] [DeepEqualsIgnore]
private bool _showLayerRAINBOW; private bool _showLayerRAINBOW;
[Description("Pixel Pro. Overrides HiResEmulation if set")]
[DefaultValue(false)]
public bool PixelPro { get; set; }
public Settings Clone() public Settings Clone()
{ {
return (Settings)MemberwiseClone(); return (Settings)MemberwiseClone();
@ -321,7 +325,8 @@ namespace BizHawk.Emulation.Cores.Consoles.NEC.PCFX
CdSpeed = _syncSettings.CdSpeed, CdSpeed = _syncSettings.CdSpeed,
CpuEmulation = (int)_syncSettings.CpuEmulation, CpuEmulation = (int)_syncSettings.CpuEmulation,
Port1 = (int)_syncSettings.Port1, Port1 = (int)_syncSettings.Port1,
Port2 = (int)_syncSettings.Port2 Port2 = (int)_syncSettings.Port2,
PixelPro = _settings.PixelPro ? 1 : 0
}; };
_core.PutSettingsBeforeInit(s); _core.PutSettingsBeforeInit(s);
} }

View File

@ -439,7 +439,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
#region ppudebug #region ppudebug
public bool GetGPUMemoryAreas(out IntPtr vram, out IntPtr bgpal, out IntPtr sppal, out IntPtr oam) public GPUMemoryAreas GetGPU()
{ {
IntPtr _vram = IntPtr.Zero; IntPtr _vram = IntPtr.Zero;
IntPtr _bgpal = IntPtr.Zero; IntPtr _bgpal = IntPtr.Zero;
@ -451,23 +451,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
|| !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.sppal, ref _sppal, ref unused) || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.sppal, ref _sppal, ref unused)
|| !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.oam, ref _oam, ref unused)) || !LibGambatte.gambatte_getmemoryarea(GambatteState, LibGambatte.MemoryAreas.oam, ref _oam, ref unused))
{ {
vram = IntPtr.Zero; throw new InvalidOperationException("Unexpected error in gambatte_getmemoryarea");
bgpal = IntPtr.Zero;
sppal = IntPtr.Zero;
oam = IntPtr.Zero;
return false;
}
vram = _vram;
bgpal = _bgpal;
sppal = _sppal;
oam = _oam;
return true;
} }
return new GPUMemoryAreas(_vram, _oam, _sppal, _bgpal);
/// <summary> }
/// </summary>
/// <param name="lcdc">current value of register $ff40 (LCDC)</param>
public delegate void ScanlineCallback(int lcdc);
/// <summary> /// <summary>
/// set up callback /// set up callback

View File

@ -1,4 +1,6 @@
using System; using BizHawk.Common;
using BizHawk.Emulation.Common;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -6,8 +8,49 @@ using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{ {
public interface IGameboyCommon /// <summary>
/// </summary>
/// <param name="lcdc">current value of register $ff40 (LCDC)</param>
public delegate void ScanlineCallback(byte lcdc);
public interface IGameboyCommon : ISpecializedEmulatorService
{ {
bool IsCGBMode(); bool IsCGBMode();
GPUMemoryAreas GetGPU();
/// <summary>
/// set up callback
/// </summary>
/// <param name="line">scanline. -1 = end of frame, -2 = RIGHT NOW</param>
void SetScanlineCallback(ScanlineCallback callback, int line);
}
public class GPUMemoryAreas : IMonitor
{
public IntPtr Vram { get; }
public IntPtr Oam { get; }
public IntPtr Sppal { get; }
public IntPtr Bgpal { get; }
private readonly IMonitor _monitor;
public GPUMemoryAreas(IntPtr vram, IntPtr oam, IntPtr sppal, IntPtr bgpal, IMonitor monitor = null)
{
Vram = vram;
Oam = oam;
Sppal = sppal;
Bgpal = bgpal;
_monitor = monitor;
}
public void Enter()
{
_monitor?.Enter();
}
public void Exit()
{
_monitor?.Exit();
}
} }
} }

View File

@ -9,7 +9,7 @@ using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{ {
public abstract class LibPizza : LibWaterboxCore, ICustomSaveram public abstract class LibSameboy : LibWaterboxCore
{ {
[Flags] [Flags]
public enum Buttons : uint public enum Buttons : uint
@ -23,21 +23,33 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
UP = 0x40, UP = 0x40,
DOWN = 0x80 DOWN = 0x80
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public new class FrameInfo : LibWaterboxCore.FrameInfo public new class FrameInfo : LibWaterboxCore.FrameInfo
{ {
public long Time; public long Time;
public Buttons Keys; public Buttons Keys;
} }
[BizImport(CC)] [BizImport(CC)]
public abstract bool Init(byte[] rom, int romlen, bool sgb, byte[] spc, int spclen); public abstract bool Init(bool cgb, byte[] spc, int spclen);
[BizImport(CC)] [BizImport(CC)]
public abstract bool IsCGB(); public abstract void GetGpuMemory(IntPtr[] ptrs);
[BizImport(CC)] [BizImport(CC)]
public abstract int GetSaveramSize(); public abstract void SetScanlineCallback(ScanlineCallback callback, int ly);
[BizImport(CC)] [BizImport(CC)]
public abstract void PutSaveram(byte[] data, int size); public abstract byte GetIoReg(byte port);
[BizImport(CC)] [BizImport(CC)]
public abstract void GetSaveram(byte[] data, int size); public abstract void PutSaveRam();
[BizImport(CC)]
public abstract void GetSaveRam();
[BizImport(CC)]
public abstract bool HasSaveRam();
} }
} }

View File

@ -1,169 +0,0 @@
using BizHawk.Common;
using BizHawk.Common.BizInvoke;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{
[Core("Pizza Boy", "Davide Berra", true, true, "c7bc6ee376028b3766de8d7a02e60ab794841f45",
"https://github.com/davideberra/emu-pizza/", false)]
public class Pizza : WaterboxCore, IGameboyCommon
{
private LibPizza _pizza;
private readonly bool _sgb;
[CoreConstructor("SGB")]
public Pizza(byte[] rom, CoreComm comm)
: this(rom, comm, true)
{ }
[CoreConstructor("GB")]
public Pizza(CoreComm comm, byte[] rom)
: this(rom, comm, false)
{ }
public Pizza(byte[] rom, CoreComm comm, bool sgb)
: base(comm, new Configuration
{
DefaultWidth = 160,
DefaultHeight = 144,
MaxWidth = 256,
MaxHeight = 224,
MaxSamples = 1024,
DefaultFpsNumerator = TICKSPERSECOND,
DefaultFpsDenominator = TICKSPERFRAME
})
{
if (sgb && (rom[0x143] & 0xc0) == 0xc0)
{
throw new CGBNotSupportedException();
}
_pizza = PreInit<LibPizza>(new PeRunnerOptions
{
Filename = "pizza.wbx",
SbrkHeapSizeKB = 128,
InvisibleHeapSizeKB = 16,
SealedHeapSizeKB = 5 * 1024,
PlainHeapSizeKB = 16,
MmapHeapSizeKB = 0
});
var spc = sgb
? Util.DecompressGzipFile(new MemoryStream(Properties.Resources.SgbCartPresent_SPC))
: new byte[0];
_sgb = sgb;
if (!_pizza.Init(rom, rom.Length, _sgb, spc, spc.Length))
{
throw new InvalidOperationException("Core rejected the rom!");
}
PostInit();
if (_sgb)
{
VsyncNumerator = TICKSPERSECOND_SGB;
BufferWidth = 256;
BufferHeight = 224;
}
InitializeRtc(new DateTime(2010, 1, 1)); // TODO: connect to syncsettings
Console.WriteLine("Pizza Initialized: CGB {0} SGB {1}", IsCGBMode(), IsSGBMode());
}
/// <summary>
/// the nominal length of one frame
/// </summary>
private const int TICKSPERFRAME = 35112;
/// <summary>
/// number of ticks per second (GB, CGB)
/// </summary>
private const int TICKSPERSECOND = 2097152;
/// <summary>
/// number of ticks per second (SGB)
/// </summary>
private const int TICKSPERSECOND_SGB = 2147727;
#region Controller
private static readonly ControllerDefinition _gbDefinition;
private static readonly ControllerDefinition _sgbDefinition;
public override ControllerDefinition ControllerDefinition => _sgb ? _sgbDefinition : _gbDefinition;
private static ControllerDefinition CreateControllerDefinition(int p)
{
var ret = new ControllerDefinition { Name = "Gameboy Controller" };
for (int i = 0; i < p; i++)
{
ret.BoolButtons.AddRange(
new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start" }
.Select(s => $"P{i + 1} {s}"));
}
return ret;
}
static Pizza()
{
_gbDefinition = CreateControllerDefinition(1);
_sgbDefinition = CreateControllerDefinition(4);
}
private LibPizza.Buttons GetButtons(IController c)
{
LibPizza.Buttons b = 0;
for (int i = _sgb ? 4 : 1; i > 0; i--)
{
if (c.IsPressed($"P{i} Up"))
b |= LibPizza.Buttons.UP;
if (c.IsPressed($"P{i} Down"))
b |= LibPizza.Buttons.DOWN;
if (c.IsPressed($"P{i} Left"))
b |= LibPizza.Buttons.LEFT;
if (c.IsPressed($"P{i} Right"))
b |= LibPizza.Buttons.RIGHT;
if (c.IsPressed($"P{i} A"))
b |= LibPizza.Buttons.A;
if (c.IsPressed($"P{i} B"))
b |= LibPizza.Buttons.B;
if (c.IsPressed($"P{i} Select"))
b |= LibPizza.Buttons.SELECT;
if (c.IsPressed($"P{i} Start"))
b |= LibPizza.Buttons.START;
if (i != 1)
b = (LibPizza.Buttons)((uint)b << 8);
}
return b;
}
#endregion
LibPizza.FrameInfo _tmp; // TODO: clean this up so it's not so hacky
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
return _tmp = new LibPizza.FrameInfo
{
Time = GetRtcTime(false),
Keys = GetButtons(controller)
};
}
protected override void FrameAdvancePost()
{
//Console.WriteLine(_tmp.Cycles);
_tmp = null;
}
public bool IsCGBMode() => _pizza.IsCGB();
public bool IsSGBMode() => _sgb;
public override string SystemId => _sgb ? "SGB" : "GB";
}
}

View File

@ -0,0 +1,298 @@
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Properties;
using BizHawk.Emulation.Cores.Waterbox;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
{
[Core("SameBoy", "LIJI32", true, false, "efc11783c7fb6da66e1dd084e41ba6a85c0bd17e",
"https://sameboy.github.io/", false)]
public class Sameboy : WaterboxCore,
IGameboyCommon, ISaveRam,
ISettable<object, Sameboy.SyncSettings>
{
/// <summary>
/// the nominal length of one frame
/// </summary>
private const int TICKSPERFRAME = 35112;
/// <summary>
/// number of ticks per second (GB, CGB)
/// </summary>
private const int TICKSPERSECOND = 2097152;
/// <summary>
/// number of ticks per second (SGB)
/// </summary>
private const int TICKSPERSECOND_SGB = 2147727;
private LibSameboy _core;
private bool _cgb;
private bool _sgb;
[CoreConstructor("SGB")]
public Sameboy(byte[] rom, CoreComm comm, SyncSettings syncSettings, bool deterministic)
: this(rom, comm, true, syncSettings, deterministic)
{ }
[CoreConstructor("GB")]
public Sameboy(CoreComm comm, byte[] rom, SyncSettings syncSettings, bool deterministic)
: this(rom, comm, false, syncSettings, deterministic)
{ }
public Sameboy(byte[] rom, CoreComm comm, bool sgb, SyncSettings syncSettings, bool deterministic)
: base(comm, new Configuration
{
DefaultWidth = sgb ? 256 : 160,
DefaultHeight = sgb ? 224 : 144,
MaxWidth = sgb ? 256 : 160,
MaxHeight = sgb ? 224 : 144,
MaxSamples = 1024,
DefaultFpsNumerator = sgb ? TICKSPERSECOND_SGB : TICKSPERSECOND,
DefaultFpsDenominator = TICKSPERFRAME,
SystemId = sgb ? "SGB" : "GB"
})
{
_core = PreInit<LibSameboy>(new PeRunnerOptions
{
Filename = "sameboy.wbx",
SbrkHeapSizeKB = 192,
InvisibleHeapSizeKB = 4,
SealedHeapSizeKB = 9 * 1024,
PlainHeapSizeKB = 4,
MmapHeapSizeKB = 1024
});
_cgb = (rom[0x143] & 0xc0) == 0xc0 && !sgb;
_sgb = sgb;
Console.WriteLine("Automaticly detected CGB to " + _cgb);
_syncSettings = syncSettings ?? new SyncSettings();
var bios = _syncSettings.UseRealBIOS && !sgb
? comm.CoreFileProvider.GetFirmware(_cgb ? "GBC" : "GB", "World", true)
: Util.DecompressGzipFile(new MemoryStream(_cgb ? Resources.SameboyCgbBoot : Resources.SameboyDmgBoot));
var spc = sgb
? Util.DecompressGzipFile(new MemoryStream(Resources.SgbCartPresent_SPC))
: null;
_exe.AddReadonlyFile(rom, "game.rom");
_exe.AddReadonlyFile(bios, "boot.rom");
if (!_core.Init(_cgb, spc, spc?.Length ?? 0))
{
throw new InvalidOperationException("Core rejected the rom!");
}
_exe.RemoveReadonlyFile("game.rom");
_exe.RemoveReadonlyFile("boot.rom");
PostInit();
var scratch = new IntPtr[4];
_core.GetGpuMemory(scratch);
_gpuMemory = new GPUMemoryAreas(scratch[0], scratch[1], scratch[3], scratch[2], _exe);
DeterministicEmulation = deterministic || !_syncSettings.UseRealTime;
InitializeRtc(_syncSettings.InitialTime);
}
#region Controller
private static readonly ControllerDefinition _gbDefinition;
private static readonly ControllerDefinition _sgbDefinition;
public override ControllerDefinition ControllerDefinition => _sgb ? _sgbDefinition : _gbDefinition;
private static ControllerDefinition CreateControllerDefinition(int p)
{
var ret = new ControllerDefinition { Name = "Gameboy Controller" };
for (int i = 0; i < p; i++)
{
ret.BoolButtons.AddRange(
new[] { "Up", "Down", "Left", "Right", "A", "B", "Select", "Start" }
.Select(s => $"P{i + 1} {s}"));
}
return ret;
}
static Sameboy()
{
_gbDefinition = CreateControllerDefinition(1);
_sgbDefinition = CreateControllerDefinition(4);
}
private LibSameboy.Buttons GetButtons(IController c)
{
LibSameboy.Buttons b = 0;
for (int i = _sgb ? 4 : 1; i > 0; i--)
{
if (c.IsPressed($"P{i} Up"))
b |= LibSameboy.Buttons.UP;
if (c.IsPressed($"P{i} Down"))
b |= LibSameboy.Buttons.DOWN;
if (c.IsPressed($"P{i} Left"))
b |= LibSameboy.Buttons.LEFT;
if (c.IsPressed($"P{i} Right"))
b |= LibSameboy.Buttons.RIGHT;
if (c.IsPressed($"P{i} A"))
b |= LibSameboy.Buttons.A;
if (c.IsPressed($"P{i} B"))
b |= LibSameboy.Buttons.B;
if (c.IsPressed($"P{i} Select"))
b |= LibSameboy.Buttons.SELECT;
if (c.IsPressed($"P{i} Start"))
b |= LibSameboy.Buttons.START;
if (i != 1)
b = (LibSameboy.Buttons)((uint)b << 8);
}
return b;
}
#endregion
#region ISaveram
public new bool SaveRamModified => _core.HasSaveRam();
public new byte[] CloneSaveRam()
{
_exe.AddTransientFile(null, "save.ram");
_core.GetSaveRam();
return _exe.RemoveTransientFile("save.ram");
}
public new void StoreSaveRam(byte[] data)
{
_exe.AddReadonlyFile(data, "save.ram");
_core.PutSaveRam();
_exe.RemoveReadonlyFile("save.ram");
}
#endregion
#region ISettable
private SyncSettings _syncSettings;
public class SyncSettings
{
[DisplayName("Initial Time")]
[Description("Initial time of emulation. Only relevant when UseRealTime is false.")]
[DefaultValue(typeof(DateTime), "2010-01-01")]
public DateTime InitialTime { get; set; }
[DisplayName("Use RealTime")]
[Description("If true, RTC clock will be based off of real time instead of emulated time. Ignored (set to false) when recording a movie.")]
[DefaultValue(false)]
public bool UseRealTime { get; set; }
[Description("If true, real BIOS files will be used. Ignored in SGB mode.")]
[DefaultValue(false)]
public bool UseRealBIOS { get; set; }
public SyncSettings Clone()
{
return (SyncSettings)MemberwiseClone();
}
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
public SyncSettings()
{
SettingsUtil.SetDefaultValues(this);
}
}
public object GetSettings()
{
return null;
}
public SyncSettings GetSyncSettings()
{
return _syncSettings.Clone();
}
public bool PutSettings(object o)
{
return false;
}
public bool PutSyncSettings(SyncSettings o)
{
var ret = SyncSettings.NeedsReboot(_syncSettings, o);
_syncSettings = o;
return ret;
}
#endregion
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)
{
return new LibSameboy.FrameInfo
{
Time = GetRtcTime(!DeterministicEmulation),
Keys = GetButtons(controller)
};
}
protected override void FrameAdvancePost()
{
if (_scanlineCallback != null && _scanlineCallbackLine == -1)
_scanlineCallback(_core.GetIoReg(0x40));
}
protected override void LoadStateBinaryInternal(BinaryReader reader)
{
UpdateCoreScanlineCallback(false);
}
public bool IsCGBMode() => _cgb;
private GPUMemoryAreas _gpuMemory;
public GPUMemoryAreas GetGPU() => _gpuMemory;
private ScanlineCallback _scanlineCallback;
private int _scanlineCallbackLine;
public void SetScanlineCallback(ScanlineCallback callback, int line)
{
_scanlineCallback = callback;
_scanlineCallbackLine = line;
UpdateCoreScanlineCallback(true);
}
private void UpdateCoreScanlineCallback(bool now)
{
if (_scanlineCallback == null)
{
_core.SetScanlineCallback(null, -1);
}
else
{
if (_scanlineCallbackLine >= 0 && _scanlineCallbackLine <= 153)
{
_core.SetScanlineCallback(_scanlineCallback, _scanlineCallbackLine);
}
else
{
_core.SetScanlineCallback(null, -1);
if (_scanlineCallbackLine == -2 && now)
{
_scanlineCallback(_core.GetIoReg(0x40));
}
}
}
}
}
}

View File

@ -37,10 +37,23 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public class NativeSettings public class NativeSyncSettings
{ {
public int InstantReadHack; public int InstantReadHack;
public int DisableParallax; public int DisableParallax;
public static NativeSyncSettings FromFrontendSettings(VirtualBoyee.SyncSettings ss)
{
return new NativeSyncSettings
{
InstantReadHack = ss.InstantReadHack ? 1 : 0,
DisableParallax = ss.DisableParallax ? 1 : 0,
};
}
}
public class NativeSettings
{
public int ThreeDeeMode; public int ThreeDeeMode;
public int SwapViews; public int SwapViews;
public int AnaglyphPreset; public int AnaglyphPreset;
@ -56,12 +69,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
return c.ToArgb(); return c.ToArgb();
} }
public static NativeSettings FromFrontendSettings(VirtualBoyee.Settings s, VirtualBoyee.SyncSettings ss) public static NativeSettings FromFrontendSettings(VirtualBoyee.Settings s)
{ {
return new NativeSettings return new NativeSettings
{ {
InstantReadHack = ss.InstantReadHack ? 1 : 0,
DisableParallax = ss.DisableParallax ? 1 : 0,
ThreeDeeMode = (int)s.ThreeDeeMode, ThreeDeeMode = (int)s.ThreeDeeMode,
SwapViews = s.SwapViews ? 1 : 0, SwapViews = s.SwapViews ? 1 : 0,
AnaglyphPreset = (int)s.AnaglyphPreset, AnaglyphPreset = (int)s.AnaglyphPreset,
@ -77,7 +88,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
[BizImport(CC)] [BizImport(CC)]
public abstract bool Load(byte[] rom, int length, [In]NativeSettings settings); public abstract bool Load(byte[] rom, int length, NativeSyncSettings settings);
[BizImport(CC)]
public abstract void SetSettings(NativeSettings settings);
[BizImport(CC)] [BizImport(CC)]
public abstract void HardReset(); public abstract void HardReset();

View File

@ -38,8 +38,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
{ {
_settings = settings ?? new Settings(); _settings = settings ?? new Settings();
_syncSettings = syncSettings ?? new SyncSettings(); _syncSettings = syncSettings ?? new SyncSettings();
// TODO: the way settings work in this core, changing the non-sync ones will invalidate savestates
var nativeSettings = LibVirtualBoyee.NativeSettings.FromFrontendSettings(_settings, _syncSettings);
_boyee = PreInit<LibVirtualBoyee>(new PeRunnerOptions _boyee = PreInit<LibVirtualBoyee>(new PeRunnerOptions
{ {
@ -50,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
PlainHeapSizeKB = 256 PlainHeapSizeKB = 256
}); });
if (!_boyee.Load(rom, rom.Length, nativeSettings)) if (!_boyee.Load(rom, rom.Length, LibVirtualBoyee.NativeSyncSettings.FromFrontendSettings(_syncSettings)))
throw new InvalidOperationException("Core rejected the rom"); throw new InvalidOperationException("Core rejected the rom");
// do a quick hack up for frame zero size // do a quick hack up for frame zero size
@ -60,6 +58,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
BufferHeight = tmp.Height; BufferHeight = tmp.Height;
PostInit(); PostInit();
_boyee.SetSettings(LibVirtualBoyee.NativeSettings.FromFrontendSettings(_settings));
} }
protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound) protected override LibWaterboxCore.FrameInfo FrameAdvancePrep(IController controller, bool render, bool rendersound)

View File

@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
{ {
public IEmulatorServiceProvider ServiceProvider { get; private set; } public IEmulatorServiceProvider ServiceProvider { get; private set; }
public ControllerDefinition ControllerDefinition => PCEngineController; public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
public void FrameAdvance(IController controller, bool render, bool rendersound) public void FrameAdvance(IController controller, bool render, bool rendersound)
{ {

View File

@ -1,4 +1,7 @@
using BizHawk.Emulation.Common; using System.ComponentModel;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.PCEngine namespace BizHawk.Emulation.Cores.PCEngine
{ {
@ -35,7 +38,6 @@ namespace BizHawk.Emulation.Cores.PCEngine
{ {
bool ret = PCESyncSettings.NeedsReboot(o, _syncSettings); bool ret = PCESyncSettings.NeedsReboot(o, _syncSettings);
_syncSettings = o; _syncSettings = o;
// SetControllerButtons(); // not safe to change the controller during emulation, so instead make it a reboot event
return ret; return ret;
} }
@ -62,42 +64,48 @@ namespace BizHawk.Emulation.Cores.PCEngine
public class PCESyncSettings public class PCESyncSettings
{ {
public ControllerSetting[] Controllers = [DefaultValue(PceControllerType.GamePad)]
{ [DisplayName("Port 1 Device")]
new ControllerSetting { IsConnected = true }, [Description("The type of controller plugged into the first controller port")]
new ControllerSetting { IsConnected = false }, [TypeConverter(typeof(DescribableEnumConverter))]
new ControllerSetting { IsConnected = false }, public PceControllerType Port1 { get; set; } = PceControllerType.GamePad;
new ControllerSetting { IsConnected = false },
new ControllerSetting { IsConnected = false } [DefaultValue(PceControllerType.Unplugged)]
}; [DisplayName("Port 2 Device")]
[Description("The type of controller plugged into the second controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public PceControllerType Port2 { get; set; } = PceControllerType.Unplugged;
[DefaultValue(PceControllerType.Unplugged)]
[DisplayName("Port 3 Device")]
[Description("The type of controller plugged into the third controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public PceControllerType Port3 { get; set; } = PceControllerType.Unplugged;
[DefaultValue(PceControllerType.Unplugged)]
[DisplayName("Port 4 Device")]
[Description("The type of controller plugged into the fourth controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public PceControllerType Port4 { get; set; } = PceControllerType.Unplugged;
[DefaultValue(PceControllerType.Unplugged)]
[DisplayName("Port 5 Device")]
[Description("The type of controller plugged into the fifth controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public PceControllerType Port5 { get; set; } = PceControllerType.Unplugged;
public PCESyncSettings Clone() public PCESyncSettings Clone()
{ {
var ret = new PCESyncSettings(); return (PCESyncSettings)MemberwiseClone();
for (int i = 0; i < Controllers.Length; i++)
{
ret.Controllers[i].IsConnected = Controllers[i].IsConnected;
}
return ret;
}
public class ControllerSetting
{
public bool IsConnected { get; set; }
} }
public static bool NeedsReboot(PCESyncSettings x, PCESyncSettings y) public static bool NeedsReboot(PCESyncSettings x, PCESyncSettings y)
{ {
for (int i = 0; i < x.Controllers.Length; i++) return x.Port1 != y.Port1
{ || x.Port2 != y.Port2
if (x.Controllers[i].IsConnected != y.Controllers[i].IsConnected) || x.Port3 != y.Port3
{ || x.Port4 != y.Port4
return true; || x.Port5 != y.Port5;
}
}
return false;
} }
} }
} }

View File

@ -1,92 +1,41 @@
using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.PCEngine
namespace BizHawk.Emulation.Cores.PCEngine
{ {
public partial class PCEngine public partial class PCEngine
{ {
private readonly ControllerDefinition PCEngineController = new ControllerDefinition private int _selectedController;
{ private byte _inputByte;
Name = "PC Engine Controller",
BoolButtons =
{
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Select", "P1 Run", "P1 B2", "P1 B1",
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Select", "P2 Run", "P2 B2", "P2 B1",
"P3 Up", "P3 Down", "P3 Left", "P3 Right", "P3 Select", "P3 Run", "P3 B2", "P3 B1",
"P4 Up", "P4 Down", "P4 Left", "P4 Right", "P4 Select", "P4 Run", "P4 B2", "P4 B1",
"P5 Up", "P5 Down", "P5 Left", "P5 Right", "P5 Select", "P5 Run", "P5 B2", "P5 B1"
}
};
private void SetControllerButtons() private bool Sel => (_inputByte & 1) != 0;
{ private bool Clr => (_inputByte & 2) != 0;
ControllerDefinition.BoolButtons.Clear();
ControllerDefinition.FloatControls.Clear();
for (int i = 0; i < 5; i++)
{
if (_syncSettings.Controllers[i].IsConnected)
{
ControllerDefinition.BoolButtons.AddRange(new[]
{
"P" + (i + 1) + " Up",
"P" + (i + 1) + " Down",
"P" + (i + 1) + " Left",
"P" + (i + 1) + " Right",
"P" + (i + 1) + " Select",
"P" + (i + 1) + " Run",
"P" + (i + 1) + " B1",
"P" + (i + 1) + " B2"
});
}
}
}
private int SelectedController;
private byte InputByte;
public bool SEL => (InputByte & 1) != 0;
public bool CLR => (InputByte & 2) != 0;
private void WriteInput(byte value) private void WriteInput(byte value)
{ {
bool prevSEL = SEL; bool prevSel = Sel;
InputByte = value; _inputByte = value;
if (SEL && CLR) if (Sel && Clr)
{ {
SelectedController = 0; _selectedController = 0;
} }
if (CLR == false && prevSEL == false && SEL == true) if (Clr == false && prevSel == false && Sel)
{ {
SelectedController = (SelectedController + 1); _selectedController = _selectedController + 1;
} }
} }
private readonly PceControllerDeck _controllerDeck;
private byte ReadInput() private byte ReadInput()
{ {
InputCallbacks.Call(); InputCallbacks.Call();
byte value = 0x3F; byte value = 0x3F;
int player = SelectedController + 1; int player = _selectedController + 1;
if (player < 6) if (player < 6)
{ {
_lagged = false; _lagged = false;
if (SEL == false) // return buttons value &= _controllerDeck.Read(player, _controller, Sel);
{
if (_controller.IsPressed("P" + player + " B1")) value &= 0xFE;
if (_controller.IsPressed("P" + player + " B2")) value &= 0xFD;
if (_controller.IsPressed("P" + player + " Select")) value &= 0xFB;
if (_controller.IsPressed("P" + player + " Run")) value &= 0xF7;
}
else
{
//return directions
if (_controller.IsPressed("P" + player + " Up")) value &= 0xFE;
if (_controller.IsPressed("P" + player + " Right")) value &= 0xFD;
if (_controller.IsPressed("P" + player + " Down")) value &= 0xFB;
if (_controller.IsPressed("P" + player + " Left")) value &= 0xF7;
}
} }
if (Region == "Japan") if (Region == "Japan")

View File

@ -41,7 +41,13 @@ namespace BizHawk.Emulation.Cores.PCEngine
Settings = (PCESettings)settings ?? new PCESettings(); Settings = (PCESettings)settings ?? new PCESettings();
_syncSettings = (PCESyncSettings)syncSettings ?? new PCESyncSettings(); _syncSettings = (PCESyncSettings)syncSettings ?? new PCESyncSettings();
Init(game, rom); Init(game, rom);
SetControllerButtons();
_controllerDeck = new PceControllerDeck(
_syncSettings.Port1,
_syncSettings.Port2,
_syncSettings.Port3,
_syncSettings.Port4,
_syncSettings.Port5);
} }
public PCEngine(CoreComm comm, GameInfo game, Disc disc, object Settings, object syncSettings) public PCEngine(CoreComm comm, GameInfo game, Disc disc, object Settings, object syncSettings)
@ -96,7 +102,13 @@ namespace BizHawk.Emulation.Cores.PCEngine
// the default RomStatusDetails don't do anything with Disc // the default RomStatusDetails don't do anything with Disc
CoreComm.RomStatusDetails = string.Format("{0}\r\nDisk partial hash:{1}", game.Name, new DiscSystem.DiscHasher(disc).OldHash()); CoreComm.RomStatusDetails = string.Format("{0}\r\nDisk partial hash:{1}", game.Name, new DiscSystem.DiscHasher(disc).OldHash());
SetControllerButtons();
_controllerDeck = new PceControllerDeck(
_syncSettings.Port1,
_syncSettings.Port2,
_syncSettings.Port3,
_syncSettings.Port4,
_syncSettings.Port5);
} }
// ROM // ROM

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.PCEngine
{
public enum PceControllerType
{
Unplugged,
GamePad
}
public class PceControllerDeck
{
private static readonly Type[] Implementors =
{
typeof(UnpluggedController), // Order must match PceControllerType enum values
typeof(StandardController)
};
public PceControllerDeck(
PceControllerType controller1,
PceControllerType controller2,
PceControllerType controller3,
PceControllerType controller4,
PceControllerType controller5)
{
_port1 = (IPort)Activator.CreateInstance(Implementors[(int)controller1], 1);
_port2 = (IPort)Activator.CreateInstance(Implementors[(int)controller2], 2);
_port3 = (IPort)Activator.CreateInstance(Implementors[(int)controller3], 3);
_port4 = (IPort)Activator.CreateInstance(Implementors[(int)controller4], 4);
_port5 = (IPort)Activator.CreateInstance(Implementors[(int)controller5], 5);
Definition = new ControllerDefinition
{
Name = "PC Engine Controller",
BoolButtons = _port1.Definition.BoolButtons
.Concat(_port2.Definition.BoolButtons)
.Concat(_port3.Definition.BoolButtons)
.Concat(_port4.Definition.BoolButtons)
.Concat(_port5.Definition.BoolButtons)
.ToList()
};
Definition.FloatControls.AddRange(_port1.Definition.FloatControls);
Definition.FloatControls.AddRange(_port2.Definition.FloatControls);
Definition.FloatControls.AddRange(_port3.Definition.FloatControls);
Definition.FloatControls.AddRange(_port4.Definition.FloatControls);
Definition.FloatControls.AddRange(_port5.Definition.FloatControls);
Definition.FloatRanges.AddRange(_port1.Definition.FloatRanges);
Definition.FloatRanges.AddRange(_port2.Definition.FloatRanges);
Definition.FloatRanges.AddRange(_port3.Definition.FloatRanges);
Definition.FloatRanges.AddRange(_port4.Definition.FloatRanges);
Definition.FloatRanges.AddRange(_port5.Definition.FloatRanges);
}
private readonly IPort _port1;
private readonly IPort _port2;
private readonly IPort _port3;
private readonly IPort _port4;
private readonly IPort _port5;
public byte Read(int portNum, IController c, bool sel)
{
switch (portNum)
{
default:
throw new ArgumentException($"Invalid {nameof(portNum)}: {portNum}");
case 1:
return _port1.Read(c, sel);
case 2:
return _port2.Read(c, sel);
case 3:
return _port3.Read(c, sel);
case 4:
return _port4.Read(c, sel);
case 5:
return _port5.Read(c, sel);
}
}
public ControllerDefinition Definition { get; }
}
public interface IPort
{
byte Read(IController c, bool sel);
ControllerDefinition Definition { get; }
int PortNum { get; }
}
public class UnpluggedController : IPort
{
public UnpluggedController(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition
{
BoolButtons = new List<string>()
};
}
public byte Read(IController c, bool sel)
{
return 0x3F;
}
public ControllerDefinition Definition { get; }
public int PortNum { get; }
}
public class StandardController : IPort
{
public StandardController(int portNum)
{
PortNum = portNum;
Definition = new ControllerDefinition
{
BoolButtons = BaseDefinition
.Select(b => $"P{PortNum} " + b)
.ToList()
};
}
public ControllerDefinition Definition { get; }
public int PortNum { get; }
public byte Read(IController c, bool sel)
{
byte result = 0x3F;
if (sel == false)
{
if (c.IsPressed($"P{PortNum} B1")) result &= 0xFE;
if (c.IsPressed($"P{PortNum} B2")) result &= 0xFD;
if (c.IsPressed($"P{PortNum} Select")) result &= 0xFB;
if (c.IsPressed($"P{PortNum} Run")) result &= 0xF7;
}
else
{
if (c.IsPressed($"P{PortNum} Up")) { result &= 0xFE; }
if (c.IsPressed($"P{PortNum} Right")) { result &= 0xFD; }
if (c.IsPressed($"P{PortNum} Down")) { result &= 0xFB; }
if (c.IsPressed($"P{PortNum} Left")) { result &= 0xF7; }
}
return result;
}
private static readonly string[] BaseDefinition =
{
"Up", "Down", "Left", "Right", "Select", "Run", "B2", "B1"
};
}
}

View File

@ -20,6 +20,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
[UnmanagedFunctionPointer(CC)] [UnmanagedFunctionPointer(CC)]
public delegate void CDReadCallback(int lba, IntPtr dest, bool audio); public delegate void CDReadCallback(int lba, IntPtr dest, bool audio);
public enum Region : int
{
Auto = 0,
JapanNTSC = 1,
JapanPAL = 2,
US = 4,
Europe = 8
}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -28,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
/// 32X games will still run, but will not have memory domains</param> /// 32X games will still run, but will not have memory domains</param>
/// <returns></returns> /// <returns></returns>
[BizImport(CC)] [BizImport(CC)]
public abstract bool Init(bool cd, bool _32xPreinit); public abstract bool Init(bool cd, bool _32xPreinit, Region regionAutoOrder, Region regionOverride);
[BizImport(CC)] [BizImport(CC)]
public abstract void SetCDReadCallback(CDReadCallback callback); public abstract void SetCDReadCallback(CDReadCallback callback);

View File

@ -8,12 +8,14 @@ using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO; using System.IO;
using BizHawk.Common;
using System.ComponentModel;
namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
{ {
[Core("PicoDrive", "notaz", true, true, [Core("PicoDrive", "notaz", true, true,
"0e352905c7aa80b166933970abbcecfce96ad64e", "https://github.com/notaz/picodrive", false)] "0e352905c7aa80b166933970abbcecfce96ad64e", "https://github.com/notaz/picodrive", false)]
public class PicoDrive : WaterboxCore, IDriveLight, IRegionable public class PicoDrive : WaterboxCore, IDriveLight, IRegionable, ISettable<object, PicoDrive.SyncSettings>
{ {
private LibPicoDrive _core; private LibPicoDrive _core;
private LibPicoDrive.CDReadCallback _cdcallback; private LibPicoDrive.CDReadCallback _cdcallback;
@ -22,15 +24,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
private bool _isPal; private bool _isPal;
[CoreConstructor("GEN")] [CoreConstructor("GEN")]
public PicoDrive(CoreComm comm, GameInfo game, byte[] rom, bool deterministic) public PicoDrive(CoreComm comm, GameInfo game, byte[] rom, bool deterministic, SyncSettings syncSettings)
:this(comm, game, rom, null, deterministic) : this(comm, game, rom, null, deterministic, syncSettings)
{ } { }
public PicoDrive(CoreComm comm, GameInfo game, Disc cd, bool deterministic) public PicoDrive(CoreComm comm, GameInfo game, Disc cd, bool deterministic, SyncSettings syncSettings)
:this(comm, game, null, cd, deterministic) : this(comm, game, null, cd, deterministic, syncSettings)
{ } { }
private PicoDrive(CoreComm comm, GameInfo game, byte[] rom, Disc cd, bool deterministic) private PicoDrive(CoreComm comm, GameInfo game, byte[] rom, Disc cd, bool deterministic, SyncSettings syncSettings)
: base(comm, new Configuration : base(comm, new Configuration
{ {
MaxSamples = 2048, MaxSamples = 2048,
@ -49,6 +51,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
throw new InvalidOperationException("32X BIOS files are required for deterministic mode"); throw new InvalidOperationException("32X BIOS files are required for deterministic mode");
deterministic |= has32xBios; deterministic |= has32xBios;
_syncSettings = syncSettings ?? new SyncSettings();
_core = PreInit<LibPicoDrive>(new PeRunnerOptions _core = PreInit<LibPicoDrive>(new PeRunnerOptions
{ {
Filename = "picodrive.wbx", Filename = "picodrive.wbx",
@ -83,7 +87,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
_exe.AddReadonlyFile(rom, "romfile.md"); _exe.AddReadonlyFile(rom, "romfile.md");
} }
if (!_core.Init(cd != null, game["32X"])) var regionAutoOrder = (LibPicoDrive.Region)(
(int)_syncSettings.FirstChoice |
(int)_syncSettings.SecondChoice << 4 |
(int)_syncSettings.ThirdChoice << 8);
if (!_core.Init(cd != null, game["32X"], regionAutoOrder, _syncSettings.RegionOverride))
throw new InvalidOperationException("Core rejected the file!"); throw new InvalidOperationException("Core rejected the file!");
if (cd != null) if (cd != null)
@ -174,6 +183,68 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
_core.SetCDReadCallback(_cdcallback); _core.SetCDReadCallback(_cdcallback);
} }
#region ISettable
public class SyncSettings
{
[DefaultValue(LibPicoDrive.Region.Auto)]
[Description("If set, force the console to this region")]
public LibPicoDrive.Region RegionOverride { get; set; }
[DefaultValue(LibPicoDrive.Region.Auto)]
[Description("When region is set to automatic, highest priority region to use if the game supports multiple regions")]
public LibPicoDrive.Region FirstChoice { get; set; }
[DefaultValue(LibPicoDrive.Region.Auto)]
[Description("When region is set to automatic, second highest priority region to use if the game supports multiple regions")]
public LibPicoDrive.Region SecondChoice { get; set; }
[DefaultValue(LibPicoDrive.Region.Auto)]
[Description("When region is set to automatic, lowest priority region to use if the game supports multiple regions")]
public LibPicoDrive.Region ThirdChoice { get; set; }
public SyncSettings Clone()
{
return (SyncSettings)MemberwiseClone();
}
public static bool NeedsReboot(SyncSettings x, SyncSettings y)
{
return !DeepEquality.DeepEquals(x, y);
}
public SyncSettings()
{
SettingsUtil.SetDefaultValues(this);
}
}
private SyncSettings _syncSettings;
public object GetSettings()
{
return new object();
}
public SyncSettings GetSyncSettings()
{
return _syncSettings.Clone();
}
public bool PutSettings(object o)
{
return false;
}
public bool PutSyncSettings(SyncSettings o)
{
var ret = SyncSettings.NeedsReboot(_syncSettings, o);
_syncSettings = o;
return ret;
}
#endregion
#region IDriveLight #region IDriveLight
public bool DriveLightEnabled { get; private set; } public bool DriveLightEnabled { get; private set; }

View File

@ -16,6 +16,31 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
Core.gpgx_reset(false); Core.gpgx_reset(false);
if (controller.IsPressed("Power")) if (controller.IsPressed("Power"))
Core.gpgx_reset(true); Core.gpgx_reset(true);
if (_cds != null)
{
var prev = controller.IsPressed("Previous Disk");
var next = controller.IsPressed("Next Disk");
int newDisk = _discIndex;
if (prev && !_prevDiskPressed)
newDisk--;
if (next && !_nextDiskPressed)
newDisk++;
_prevDiskPressed = prev;
_nextDiskPressed = next;
if (newDisk < -1)
newDisk = -1;
if (newDisk >= _cds.Length)
newDisk = _cds.Length - 1;
if (newDisk != _discIndex)
{
_discIndex = newDisk;
Core.gpgx_swap_disc(_discIndex == -1 ? null : GetCDDataStruct(_cds[_discIndex]));
Console.WriteLine("IMMA CHANGING MAH DISKS");
}
}
// this shouldn't be needed, as nothing has changed // this shouldn't be needed, as nothing has changed
// if (!Core.gpgx_get_control(input, inputsize)) // if (!Core.gpgx_get_control(input, inputsize))
@ -39,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (IsLagFrame) if (IsLagFrame)
LagCount++; LagCount++;
if (CD != null) if (_cds != null)
DriveLightOn = _drivelight; DriveLightOn = _drivelight;
} }
@ -70,8 +95,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{ {
if (_elf != null) if (_elf != null)
_elf.Dispose(); _elf.Dispose();
if (CD != null) if (_cds != null)
CD.Dispose(); foreach (var cd in _cds)
cd.Dispose();
_disposed = true; _disposed = true;
} }
} }

View File

@ -36,6 +36,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
Frame = reader.ReadInt32(); Frame = reader.ReadInt32();
LagCount = reader.ReadInt32(); LagCount = reader.ReadInt32();
IsLagFrame = reader.ReadBoolean(); IsLagFrame = reader.ReadBoolean();
_discIndex = reader.ReadInt32();
_prevDiskPressed = reader.ReadBoolean();
_nextDiskPressed = reader.ReadBoolean();
// any managed pointers that we sent to the core need to be resent now! // any managed pointers that we sent to the core need to be resent now!
Core.gpgx_set_input_callback(InputCallback); Core.gpgx_set_input_callback(InputCallback);
RefreshMemCallbacks(); RefreshMemCallbacks();
@ -51,6 +54,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
writer.Write(Frame); writer.Write(Frame);
writer.Write(LagCount); writer.Write(LagCount);
writer.Write(IsLagFrame); writer.Write(IsLagFrame);
writer.Write(_discIndex);
writer.Write(_prevDiskPressed);
writer.Write(_nextDiskPressed);
} }
public byte[] SaveStateBinary() public byte[] SaveStateBinary()

View File

@ -7,6 +7,8 @@ using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox; using BizHawk.Emulation.Cores.Waterbox;
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Emulation.DiscSystem; using BizHawk.Emulation.DiscSystem;
using System.Collections.Generic;
using System.Linq;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{ {
@ -27,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{ {
} }
public GPGX(CoreComm comm, byte[] rom, DiscSystem.Disc CD, object settings, object syncSettings) public GPGX(CoreComm comm, byte[] rom, IEnumerable<Disc> cds, object settings, object syncSettings)
{ {
ServiceProvider = new BasicServiceProvider(this); ServiceProvider = new BasicServiceProvider(this);
// this can influence some things internally (autodetect romtype, etc) // this can influence some things internally (autodetect romtype, etc)
@ -63,13 +65,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
LoadCallback = new LibGPGX.load_archive_cb(load_archive); LoadCallback = new LibGPGX.load_archive_cb(load_archive);
this.romfile = rom; _romfile = rom;
this.CD = CD;
if (CD != null) if (cds != null)
{ {
this.DiscSectorReader = new DiscSystem.DiscSectorReader(CD); _cds = cds.ToArray();
_cdReaders = cds.Select(c => new DiscSectorReader(c)).ToArray();
cd_callback_handle = new LibGPGX.cd_read_cb(CDRead); cd_callback_handle = new LibGPGX.cd_read_cb(CDRead);
Core.gpgx_set_cdd_callback(cd_callback_handle); Core.gpgx_set_cdd_callback(cd_callback_handle);
DriveLightEnabled = true;
} }
LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE; LibGPGX.INPUT_SYSTEM system_a = LibGPGX.INPUT_SYSTEM.SYSTEM_NONE;
@ -139,9 +143,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
InputCallback = new LibGPGX.input_cb(input_callback); InputCallback = new LibGPGX.input_cb(input_callback);
Core.gpgx_set_input_callback(InputCallback); Core.gpgx_set_input_callback(InputCallback);
if (CD != null)
DriveLightEnabled = true;
// process the non-init settings now // process the non-init settings now
PutSettings(_settings); PutSettings(_settings);
@ -154,14 +155,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
Tracer = new GPGXTraceBuffer(this, MemoryDomains, this); Tracer = new GPGXTraceBuffer(this, MemoryDomains, this);
(ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer); (ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer);
} }
_romfile = null;
} }
private LibGPGX Core; private LibGPGX Core;
private PeRunner _elf; private PeRunner _elf;
DiscSystem.Disc CD; private Disc[] _cds;
DiscSystem.DiscSectorReader DiscSectorReader; private int _discIndex;
byte[] romfile; private DiscSectorReader[] _cdReaders;
private bool _prevDiskPressed;
private bool _nextDiskPressed;
byte[] _romfile;
private bool _disposed = false; private bool _disposed = false;
@ -201,28 +208,28 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (filename == "PRIMARY_ROM") if (filename == "PRIMARY_ROM")
{ {
if (romfile == null) if (_romfile == null)
{ {
Console.WriteLine("Couldn't satisfy firmware request PRIMARY_ROM because none was provided."); Console.WriteLine("Couldn't satisfy firmware request PRIMARY_ROM because none was provided.");
return 0; return 0;
} }
srcdata = romfile; srcdata = _romfile;
} }
else if (filename == "PRIMARY_CD" || filename == "SECONDARY_CD") else if (filename == "PRIMARY_CD" || filename == "SECONDARY_CD")
{ {
if (filename == "PRIMARY_CD" && romfile != null) if (filename == "PRIMARY_CD" && _romfile != null)
{ {
Console.WriteLine("Declined to satisfy firmware request PRIMARY_CD because PRIMARY_ROM was provided."); Console.WriteLine("Declined to satisfy firmware request PRIMARY_CD because PRIMARY_ROM was provided.");
return 0; return 0;
} }
else else
{ {
if (CD == null) if (_cds == null)
{ {
Console.WriteLine("Couldn't satisfy firmware request {0} because none was provided.", filename); Console.WriteLine("Couldn't satisfy firmware request {0} because none was provided.", filename);
return 0; return 0;
} }
srcdata = GetCDData(CD); srcdata = GetCDData(_cds[0]);
if (srcdata.Length != maxsize) if (srcdata.Length != maxsize)
{ {
Console.WriteLine("Couldn't satisfy firmware request {0} because of struct size.", filename); Console.WriteLine("Couldn't satisfy firmware request {0} because of struct size.", filename);
@ -282,13 +289,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
} }
void CDRead(int lba, IntPtr dest, bool audio) void CDRead(int lba, IntPtr dest, bool audio)
{
if ((uint)_discIndex < _cds.Length)
{ {
if (audio) if (audio)
{ {
byte[] data = new byte[2352]; byte[] data = new byte[2352];
if (lba < CD.Session1.LeadoutLBA) if (lba < _cds[_discIndex].Session1.LeadoutLBA)
{ {
DiscSectorReader.ReadLBA_2352(lba, data, 0); _cdReaders[_discIndex].ReadLBA_2352(lba, data, 0);
} }
else else
{ {
@ -301,18 +310,18 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
else else
{ {
byte[] data = new byte[2048]; byte[] data = new byte[2048];
DiscSectorReader.ReadLBA_2048(lba, data, 0); _cdReaders[_discIndex].ReadLBA_2048(lba, data, 0);
Marshal.Copy(data, 0, dest, 2048); Marshal.Copy(data, 0, dest, 2048);
_drivelight = true; _drivelight = true;
} }
} }
}
LibGPGX.cd_read_cb cd_callback_handle; LibGPGX.cd_read_cb cd_callback_handle;
public static unsafe byte[] GetCDData(Disc cd) public static LibGPGX.CDData GetCDDataStruct(Disc cd)
{ {
LibGPGX.CDData ret = new LibGPGX.CDData(); var ret = new LibGPGX.CDData();
int size = Marshal.SizeOf(ret);
var ses = cd.Session1; var ses = cd.Session1;
int ntrack = ses.InformationTrackCount; int ntrack = ses.InformationTrackCount;
@ -338,6 +347,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
} }
} }
return ret;
}
public static unsafe byte[] GetCDData(Disc cd)
{
var ret = GetCDDataStruct(cd);
int size = Marshal.SizeOf(ret);
byte[] retdata = new byte[size]; byte[] retdata = new byte[size];
fixed (byte* p = &retdata[0]) fixed (byte* p = &retdata[0])
@ -360,7 +376,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (!Core.gpgx_get_control(input, inputsize)) if (!Core.gpgx_get_control(input, inputsize))
throw new Exception("gpgx_get_control() failed"); throw new Exception("gpgx_get_control() failed");
ControlConverter = new GPGXControlConverter(input); ControlConverter = new GPGXControlConverter(input, false); // _cds != null);
ControllerDefinition = ControlConverter.ControllerDef; ControllerDefinition = ControlConverter.ControllerDef;
} }
@ -369,7 +385,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
return (LibGPGX.INPUT_DEVICE[])input.dev.Clone(); return (LibGPGX.INPUT_DEVICE[])input.dev.Clone();
} }
public bool IsMegaCD { get { return CD != null; } } public bool IsMegaCD { get { return _cds != null; } }
public class VDPView : IMonitor public class VDPView : IMonitor
{ {

View File

@ -175,7 +175,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
}); });
} }
public GPGXControlConverter(LibGPGX.InputData input) public GPGXControlConverter(LibGPGX.InputData input, bool cdButtons)
{ {
Console.WriteLine("Genesis Controller report:"); Console.WriteLine("Genesis Controller report:");
foreach (var e in input.system) foreach (var e in input.system)
@ -189,6 +189,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
ControllerDef.BoolButtons.Add("Power"); ControllerDef.BoolButtons.Add("Power");
ControllerDef.BoolButtons.Add("Reset"); ControllerDef.BoolButtons.Add("Reset");
if (cdButtons)
{
ControllerDef.BoolButtons.Add("Previous Disk");
ControllerDef.BoolButtons.Add("Next Disk");
}
for (int i = 0; i < LibGPGX.MAX_DEVICES; i++) for (int i = 0; i < LibGPGX.MAX_DEVICES; i++)
{ {

View File

@ -151,8 +151,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
[BizImport(CallingConvention.Cdecl)] [BizImport(CallingConvention.Cdecl)]
public abstract void gpgx_set_cd_callback(CDCallback cd); public abstract void gpgx_set_cd_callback(CDCallback cd);
/// <summary> /// <summary>
/// not every flag is valid for every device! /// not every flag is valid for every device!
/// </summary> /// </summary>
@ -277,6 +275,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
[BizImport(CallingConvention.Cdecl)] [BizImport(CallingConvention.Cdecl)]
public abstract void gpgx_set_cdd_callback(cd_read_cb cddcb); public abstract void gpgx_set_cdd_callback(cd_read_cb cddcb);
[BizImport(CallingConvention.Cdecl, Compatibility = true)]
public abstract void gpgx_swap_disc(CDData toc);
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct VDPNameTable public struct VDPNameTable
{ {

View File

@ -60,6 +60,26 @@ namespace BizHawk.Emulation.Cores.Properties {
} }
} }
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] SameboyCgbBoot {
get {
object obj = ResourceManager.GetObject("SameboyCgbBoot", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] SameboyDmgBoot {
get {
object obj = ResourceManager.GetObject("SameboyDmgBoot", resourceCulture);
return ((byte[])(obj));
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Byte[]. /// Looks up a localized resource of type System.Byte[].
/// </summary> /// </summary>

View File

@ -118,6 +118,12 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="SameboyCgbBoot" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\cgb_boot.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="SameboyDmgBoot" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\dmg_boot.bin.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="SgbCartPresent_SPC" type="System.Resources.ResXFileRef, System.Windows.Forms"> <data name="SgbCartPresent_SPC" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\sgb-cart-present.spc.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>..\Resources\sgb-cart-present.spc.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>

Binary file not shown.

Binary file not shown.

View File

@ -308,6 +308,68 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
} }
private class TransientFile : IFileObject
{
private bool _inUse = false;
public string Name { get; }
public Stream Stream { get; }
public bool Close()
{
if (_inUse)
{
_inUse = false;
return true;
}
else
{
return false;
}
}
public bool Open(FileAccess access)
{
if (_inUse)
{
return false;
}
else
{
// TODO: if access != RW, the resultant handle lets you do those all anyway
_inUse = true;
Stream.Position = 0;
return true;
}
}
public void LoadStateBinary(BinaryReader br)
{
throw new InvalidOperationException("Internal savestate error!");
}
public void SaveStateBinary(BinaryWriter bw)
{
throw new InvalidOperationException("Transient files cannot be savestated!");
}
public TransientFile(byte[] data, string name)
{
Stream = new MemoryStream();
Name = name;
if (data != null)
{
Stream.Write(data, 0, data.Length);
Stream.Position = 0;
}
}
public byte[] GetContents()
{
if (_inUse)
throw new InvalidOperationException();
return ((MemoryStream)Stream).ToArray();
}
}
private readonly List<IFileObject> _openFiles = new List<IFileObject>(); private readonly List<IFileObject> _openFiles = new List<IFileObject>();
private readonly Dictionary<string, IFileObject> _availableFiles = new Dictionary<string, IFileObject>(); private readonly Dictionary<string, IFileObject> _availableFiles = new Dictionary<string, IFileObject>();
@ -697,6 +759,21 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
} }
private T RemoveFileInternal<T>(string name)
where T : IFileObject
{
IFileObject o;
if (!_availableFiles.TryGetValue(name, out o))
throw new InvalidOperationException("File was never registered!");
if (o.GetType() != typeof(T))
throw new InvalidOperationException("Object was not a the right kind of file");
if (_openFiles.Contains(o))
throw new InvalidOperationException("Core never closed the file!");
_availableFiles.Remove(name);
return (T)o;
}
public void AddReadonlyFile(byte[] data, string name) public void AddReadonlyFile(byte[] data, string name)
{ {
_availableFiles.Add(name, new ReadonlyFirmware(data, name)); _availableFiles.Add(name, new ReadonlyFirmware(data, name));
@ -704,15 +781,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void RemoveReadonlyFile(string name) public void RemoveReadonlyFile(string name)
{ {
IFileObject o; RemoveFileInternal<ReadonlyFirmware>(name);
if (!_availableFiles.TryGetValue(name, out o)) }
throw new InvalidOperationException("Firmware was never registered!");
var f = o as ReadonlyFirmware; public void AddTransientFile(byte[] data, string name)
if (f == null) {
throw new InvalidOperationException("Object was not a firmware!"); _availableFiles.Add(name, new TransientFile(data, name));
if (_openFiles.Contains(o)) }
throw new InvalidOperationException("Core never closed the firmware!"); public byte[] RemoveTransientFile(string name)
_availableFiles.Remove(name); {
return RemoveFileInternal<TransientFile>(name).GetContents();
} }
} }
@ -1090,6 +1168,24 @@ namespace BizHawk.Emulation.Cores.Waterbox
_syscalls.RemoveReadonlyFile(name); _syscalls.RemoveReadonlyFile(name);
} }
/// <summary>
/// Add a transient file that will appear to the waterbox core's libc. The file will be readable
/// and writable. Any attempt to save state while the file is loaded will fail.
/// </summary>
public void AddTransientFile(byte[] data, string name)
{
_syscalls.AddTransientFile(data, name); // don't need to clone data, as it's used at init only
}
/// <summary>
/// Remove a file previously added by AddTransientFile
/// </summary>
/// <returns>The state of the file when it was removed</returns>
public byte[] RemoveTransientFile(string name)
{
return _syscalls.RemoveTransientFile(name);
}
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
bw.Write(_createstamp); bw.Write(_createstamp);

View File

@ -344,6 +344,13 @@ namespace BizHawk.Emulation.Cores.Waterbox
Marshal.Copy(Z.US(_imports.Start), impData, 0, (int)_imports.Size); Marshal.Copy(Z.US(_imports.Start), impData, 0, (int)_imports.Size);
WaterboxUtils.ZeroMemory(Z.US(_imports.Start), (long)_imports.Size); WaterboxUtils.ZeroMemory(Z.US(_imports.Start), (long)_imports.Size);
} }
byte[] invData = null;
if (_invisible != null)
{
invData = new byte[_invisible.Size];
Marshal.Copy(Z.US(_invisible.Start), invData, 0, (int)_invisible.Size);
WaterboxUtils.ZeroMemory(Z.US(_invisible.Start), (long)_invisible.Size);
}
Memory.SaveXorSnapshot(); Memory.SaveXorSnapshot();
if (_imports != null) if (_imports != null)
{ {
@ -351,6 +358,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
_imports.W = false; _imports.W = false;
Memory.Protect(_imports.Start, _imports.Size, _imports.Prot); Memory.Protect(_imports.Start, _imports.Size, _imports.Prot);
} }
if (_invisible != null)
{
Marshal.Copy(invData, 0, Z.US(_invisible.Start), (int)_invisible.Size);
}
if (_sealed != null) if (_sealed != null)
{ {
_sealed.W = false; _sealed.W = false;

View File

@ -346,6 +346,11 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
public void FreePipeline(Pipeline pipeline) public void FreePipeline(Pipeline pipeline)
{ {
var pw = pipeline.Opaque as PipelineWrapper; var pw = pipeline.Opaque as PipelineWrapper;
//unavailable pipelines will have no opaque
if (pw == null)
return;
GL.DeleteProgram(pw.pid); GL.DeleteProgram(pw.pid);
pw.FragmentShader.Release(); pw.FragmentShader.Release();
@ -688,7 +693,11 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
var results = cgc.Run(source, entry, type == ShaderType.FragmentShader ? "glslf" : "glslv", false); var results = cgc.Run(source, entry, type == ShaderType.FragmentShader ? "glslf" : "glslv", false);
if (!results.Succeeded) if (!results.Succeeded)
{
Console.WriteLine("CGC failed");
Console.WriteLine(results.Errors);
return new Shader(this, null, false); return new Shader(this, null, false);
}
source = results.Code; source = results.Code;
sw.MapCodeToNative = results.MapCodeToNative; sw.MapCodeToNative = results.MapCodeToNative;

View File

@ -618,6 +618,18 @@ namespace Lua511
static void lua_atunlock(IntPtr luaState, LuaCSFunction^ unlockf); static void lua_atunlock(IntPtr luaState, LuaCSFunction^ unlockf);
#endif #endif
//zero 22-jul-2017
static int lua_pushthread(IntPtr luaState)
{
return ::lua_pushthread(((lua_State *)luaState.ToPointer()));
}
static void lua_xmove(IntPtr from, IntPtr to, int n)
{
::lua_xmove(((lua_State *)from.ToPointer()), ((lua_State *)to.ToPointer()),n);
}
static void lua_pushnumber(IntPtr luaState, double number) static void lua_pushnumber(IntPtr luaState, double number)
{ {
::lua_pushnumber(toState, number); ::lua_pushnumber(toState, number);

View File

@ -68,7 +68,7 @@ namespace NLua
"-- Preload the mscorlib assembly \n"+ "-- Preload the mscorlib assembly \n"+
"luanet.load_assembly(\"mscorlib\") \n"; "luanet.load_assembly(\"mscorlib\") \n";
/*readonly */ IntPtr luaState; /*readonly */ public IntPtr luaState; //zero 22-jul-2017 - made public
ObjectTranslator translator; ObjectTranslator translator;
LuaCSFunction panicCallback, lockCallback, unlockCallback; LuaCSFunction panicCallback, lockCallback, unlockCallback;

View File

@ -803,6 +803,13 @@ namespace NLua
{ {
((LuaFunction)o).push(luaState); ((LuaFunction)o).push(luaState);
} }
//zero 22-jul-2017
else if (o is Lua)
{
var lua = o as Lua;
LuaDLL.lua_pushthread(lua.luaState);
LuaDLL.lua_xmove(lua.luaState, luaState, 1);
}
else else
{ {
pushObject(luaState,o,"luaNet_metatable"); pushObject(luaState,o,"luaNet_metatable");

Binary file not shown.

BIN
output/dll/OpenAL32.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
output/dll/sameboy.wbx.gz Normal file

Binary file not shown.

Binary file not shown.

BIN
output/dll/wrap_oal.dll Normal file

Binary file not shown.

View File

@ -10,7 +10,11 @@ extern "C" {
// mark an entry point or callback pointer // mark an entry point or callback pointer
#define ECL_ENTRY #define ECL_ENTRY
// mark a visible symbol // mark a visible symbol
#ifdef __cplusplus
#define ECL_EXPORT extern "C" __attribute__((visibility("default")))
#else
#define ECL_EXPORT __attribute__((visibility("default"))) #define ECL_EXPORT __attribute__((visibility("default")))
#endif
// allocate memory from the "sealed" pool. this memory can never be freed, // allocate memory from the "sealed" pool. this memory can never be freed,
// and can only be allocated or written to during the init phase. after that, the host // and can only be allocated or written to during the init phase. after that, the host

View File

@ -192,6 +192,14 @@ GPGX_EX void gpgx_advance(void)
nsamples = audio_update(soundbuffer); nsamples = audio_update(soundbuffer);
} }
GPGX_EX void gpgx_swap_disc(const toc_t* toc)
{
if (system_hw == SYSTEM_MCD)
{
cdd_hotswap(toc);
}
}
typedef struct typedef struct
{ {
uint32 width; // in cells uint32 width; // in cells

View File

@ -203,6 +203,21 @@ void cdd_unload(void)
memset(&cdd.toc, 0x00, sizeof(cdd.toc)); memset(&cdd.toc, 0x00, sizeof(cdd.toc));
} }
void cdd_hotswap(const toc_t *toc)
{
if (toc)
{
cdd.loaded = 1;
memcpy(&cdd.toc, &toc, sizeof(cdd.toc));
}
else
{
cdd.loaded = 0;
memset(&cdd.toc, 0x00, sizeof(cdd.toc));
}
cdd_reset();
}
void cdd_read_data(uint8 *dst) void cdd_read_data(uint8 *dst)
{ {
/* only read DATA track sectors */ /* only read DATA track sectors */
@ -348,7 +363,7 @@ void cdd_read_audio(unsigned int samples)
void cdd_update(void) void cdd_update(void)
{ {
#ifdef LOG_CDD #ifdef LOG_CDD
error("LBA = %d (track n°%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency); error("LBA = %d (track n<EFBFBD>%d)(latency=%d)\n", cdd.lba, cdd.index, cdd.latency);
#endif #endif
/* seeking disc */ /* seeking disc */

View File

@ -103,4 +103,8 @@ extern void cdd_read_audio(unsigned int samples);
extern void cdd_update(void); extern void cdd_update(void);
extern void cdd_process(void); extern void cdd_process(void);
// switch disks after emulation was started
// pass NULL to open tray
void cdd_hotswap(const toc_t *toc);
#endif #endif

View File

@ -10,6 +10,7 @@
"xiosbase": "cpp", "xiosbase": "cpp",
"iosfwd": "cpp", "iosfwd": "cpp",
"xlocale": "cpp", "xlocale": "cpp",
"xstring": "cpp" "xstring": "cpp",
"queue": "cpp"
} }
} }

View File

@ -80,7 +80,7 @@ typedef struct
// Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size // Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
// of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure // of the image. If the emulated system sets the elements of LineWidths, then the width(w) of this structure
// is ignored while drawing the image. // is ignored while drawing the image.
int32 x, y, w, h; int32 y, w, h;
// Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and // Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
// only every other line in surface (with the start line defined by InterlacedField) has valid data // only every other line in surface (with the start line defined by InterlacedField) has valid data
@ -118,3 +118,5 @@ extern bool Setting_AdpcmNoClicks;
extern bool Setting_ChromaInterpolate; extern bool Setting_ChromaInterpolate;
extern int Setting_PortDevice[2]; extern int Setting_PortDevice[2];
extern bool Setting_PixelPro;

View File

@ -2628,7 +2628,6 @@ void KING_StartFrame(VDC **arg_vdc_chips, EmulateSpecStruct *espec)
LineWidths[0] = 0; LineWidths[0] = 0;
// These 2 should be overwritten in the big loop below. // These 2 should be overwritten in the big loop below.
espec->x = 0;
espec->w = 256; espec->w = 256;
espec->y = Setting_SlStart; espec->y = Setting_SlStart;
@ -3104,7 +3103,6 @@ static void MixLayers(void)
#undef YUV888_TO_xxx #undef YUV888_TO_xxx
} }
Ess->w = fx_vce.dot_clock ? HighDotClockWidth : 256; Ess->w = fx_vce.dot_clock ? HighDotClockWidth : 256;
Ess->x = 0;
// FIXME // FIXME
if (fx_vce.frame_interlaced) if (fx_vce.frame_interlaced)

View File

@ -706,6 +706,90 @@ EXPORT bool Init(int numDisks, const uint8_t *bios)
static int ActiveDisk; static int ActiveDisk;
static uint32_t PrevConsoleButtons; static uint32_t PrevConsoleButtons;
static void Blit(MyFrameInfo &f)
{
// two widths to deal with: 256 and "341" (which can be 256, 341, or 1024 wide depending on settings)
// two heights: 240 and 480, but watch out for scanlinestart / scanline end
// in pixel pro mode, 341 width is forced to 1024. we upsize 256 to 1024 as well, and double 240 tall
const uint32_t *src = FrameBuffer;
uint32_t *dst = f.VideoBuffer;
const int srcp = 1024;
src += Ess.y * srcp;
if (Setting_PixelPro)
{
f.Width = 1024;
f.Height = Ess.h;
const int dstp = 1024;
if (Ess.h > 240) // interlace
{
if (Ess.w == 256)
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
for (int i = 0; i < 256; i++)
{
auto c = src[i];
dst[i * 4 + 0] = c;
dst[i * 4 + 1] = c;
dst[i * 4 + 2] = c;
dst[i * 4 + 3] = c;
}
}
}
else
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
memcpy(dst, src, LineWidths[j + Ess.y] * sizeof(uint32_t));
}
}
}
else // progressive: line double
{
f.Height *= 2;
if (Ess.w == 256)
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp * 2)
{
for (int i = 0; i < 256; i++)
{
auto c = src[i];
dst[i * 4 + 0] = c;
dst[i * 4 + 1] = c;
dst[i * 4 + 2] = c;
dst[i * 4 + 3] = c;
}
memcpy(dst + dstp, dst, 4096);
}
}
else
{
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp * 2)
{
memcpy(dst, src, 4096);
memcpy(dst + dstp, src, 4096);
}
}
}
}
else
{
f.Width = Ess.w;
f.Height = Ess.h;
const int dstp = Ess.w;
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
memcpy(dst, src, LineWidths[j + Ess.y] * sizeof(uint32_t));
}
}
}
EXPORT void FrameAdvance(MyFrameInfo &f) EXPORT void FrameAdvance(MyFrameInfo &f)
{ {
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
@ -733,20 +817,10 @@ EXPORT void FrameAdvance(MyFrameInfo &f)
Ess.SoundBuf = f.SoundBuffer; Ess.SoundBuf = f.SoundBuffer;
Emulate(&Ess); Emulate(&Ess);
f.Cycles = Ess.MasterCycles; f.Cycles = Ess.MasterCycles;
f.Width = Ess.w;
f.Height = Ess.h;
f.Samples = Ess.SoundBufSize; f.Samples = Ess.SoundBufSize;
f.Lagged = Lagged; f.Lagged = Lagged;
const uint32_t *src = FrameBuffer; Blit(f);
uint32_t *dst = f.VideoBuffer;
const int srcp = 1024;
const int dstp = Ess.w;
src += Ess.y * srcp + Ess.x;
for (int j = 0; j < Ess.h; j++, src += srcp, dst += dstp)
{
memcpy(dst, src, LineWidths[j + Ess.y] * sizeof(uint32_t));
}
} }
EXPORT void GetMemoryAreas(MemoryArea *m) EXPORT void GetMemoryAreas(MemoryArea *m)
@ -821,6 +895,8 @@ ECL_SEALED bool Setting_ChromaInterpolate = false;
ECL_SEALED int Setting_PortDevice[2]; ECL_SEALED int Setting_PortDevice[2];
ECL_SEALED bool Setting_PixelPro;
struct FrontendSettings struct FrontendSettings
{ {
int32_t AdpcmEmulateBuggyCodec; int32_t AdpcmEmulateBuggyCodec;
@ -834,13 +910,14 @@ struct FrontendSettings
int32_t CpuEmulation; int32_t CpuEmulation;
int32_t Port1; int32_t Port1;
int32_t Port2; int32_t Port2;
int32_t PixelPro;
}; };
EXPORT void PutSettingsBeforeInit(const FrontendSettings &s) EXPORT void PutSettingsBeforeInit(const FrontendSettings &s)
{ {
Setting_AdpcmBuggy = s.AdpcmEmulateBuggyCodec; Setting_AdpcmBuggy = s.AdpcmEmulateBuggyCodec;
Setting_AdpcmNoClicks = s.AdpcmSuppressChannelResetClicks; Setting_AdpcmNoClicks = s.AdpcmSuppressChannelResetClicks;
Setting_HighDotclockWidth = s.HiResEmulation; Setting_HighDotclockWidth = s.PixelPro ? 1024 : s.HiResEmulation;
Setting_NoSpriteLimit = s.DisableSpriteLimit; Setting_NoSpriteLimit = s.DisableSpriteLimit;
Setting_ChromaInterpolate = s.ChromaInterpolation; Setting_ChromaInterpolate = s.ChromaInterpolation;
Setting_SlStart = s.ScanlineStart; Setting_SlStart = s.ScanlineStart;
@ -849,6 +926,7 @@ EXPORT void PutSettingsBeforeInit(const FrontendSettings &s)
Setting_CpuEmulation = s.CpuEmulation; Setting_CpuEmulation = s.CpuEmulation;
Setting_PortDevice[0] = s.Port1; Setting_PortDevice[0] = s.Port1;
Setting_PortDevice[1] = s.Port2; Setting_PortDevice[1] = s.Port2;
Setting_PixelPro = s.PixelPro;
} }
/*MDFNGI EmulatedPCFX = /*MDFNGI EmulatedPCFX =

View File

@ -138,8 +138,11 @@ static const uint8_t *TryLoadBios(const char *name)
return ret; return ret;
} }
ECL_EXPORT int Init(int cd, int _32xPreinit) ECL_EXPORT int Init(int cd, int _32xPreinit, int regionAutoOrder, int regionOverride)
{ {
PicoAutoRgnOrder = regionAutoOrder;
PicoRegionOverride = regionOverride;
p32x_bios_g = TryLoadBios("32x.g"); p32x_bios_g = TryLoadBios("32x.g");
p32x_bios_m = TryLoadBios("32x.m"); p32x_bios_m = TryLoadBios("32x.m");
p32x_bios_s = TryLoadBios("32x.s"); p32x_bios_s = TryLoadBios("32x.s");

View File

@ -1,49 +0,0 @@
# Emu-pizza
A new born Gameboy Classic/Color emulator....
Requirements
-----------
Emu-pizza requires libSDL2 to compile and run Space Invaders and Gameboy games. To install it
on an APT based distro:
```
sudo apt-get install libsdl2-dev
```
on a YUM based distro:
```
sudo yum install SDL2-devel
```
Compile
-------
```
make
```
Usage
-----
```
emu-pizza [gameboy rom]
```
Gameboy keys
-------------------
* Arrows -- Arrows (rly?)
* Enter -- Start
* Space -- Select
* Z/X -- A/B buttons
* Q -- Exit
Supported ROMS
--------------
* Almost totality of Gameboy roms
Todo
----
* Serial cable emulation
Credits
-------
Thanks to [Emulator 101](http://www.emulator101.com), the source of all my current knowledge on 8080 emulation

View File

@ -1,233 +0,0 @@
/*
This file is part of Emu-Pizza
Emu-Pizza is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Emu-Pizza is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "global.h"
#include "mmu.h"
#include "utils.h"
/* guess what */
/* return values */
/* 0: OK */
/* 1: Can't open/read file */
/* 2: Unknown cartridge */
char cartridge_load(const void *data, size_t sz)
{
int i, z = 0;
if (sz < 1 || sz > 1 << 22)
return 1;
const uint8_t *rom = (const uint8_t *)data;
/* gameboy color? */
if (rom[0x143] == 0xC0 || rom[0x143] == 0x80)
{
utils_log("Gameboy Color cartridge\n");
global_cgb = global_sgb ? 0 : 1;
}
else
{
utils_log("Gameboy Classic cartridge\n");
global_cgb = 0;
}
/* get cartridge infos */
uint8_t mbc = rom[0x147];
utils_log("Cartridge code: %02x\n", mbc);
switch (mbc)
{
case 0x00:
utils_log("ROM ONLY\n");
break;
case 0x01:
utils_log("MBC1\n");
break;
case 0x02:
utils_log("MBC1 + RAM\n");
break;
case 0x03:
utils_log("MBC1 + RAM + BATTERY\n");
break;
case 0x05:
utils_log("MBC2\n");
break;
case 0x06:
mmu_init_ram(512);
utils_log("MBC2 + BATTERY\n");
break;
case 0x10:
utils_log("MBC3 + TIMER + RAM + BATTERY\n");
break;
case 0x11:
utils_log("MBC3\n");
break;
case 0x12:
utils_log("MBC3 + RAM\n");
break;
case 0x13:
utils_log("MBC3 + RAM + BATTERY\n");
break;
case 0x19:
utils_log("MBC5\n");
break;
case 0x1A:
utils_log("MBC5 + RAM\n");
break;
case 0x1B:
utils_log("MBC5 + RAM + BATTERY\n");
break;
case 0x1C:
global_rumble = 1;
utils_log("MBC5 + RUMBLE\n");
break;
case 0x1D:
global_rumble = 1;
utils_log("MBC5 + RUMBLE + RAM\n");
break;
case 0x1E:
global_rumble = 1;
utils_log("MBC5 + RUMBLE + RAM + BATTERY\n");
break;
default:
utils_log("Unknown cartridge type: %02x\n", mbc);
return 2;
}
/* title */
for (i = 0x134; i < 0x143; i++)
if (rom[i] > 0x40 && rom[i] < 0x5B)
global_cart_name[z++] = rom[i];
global_cart_name[z] = '\0';
utils_log("%s\n", global_cart_name);
/* get ROM banks */
uint8_t byte = rom[0x148];
utils_log("ROM: ");
switch (byte)
{
case 0x00:
utils_log("0 banks\n");
break;
case 0x01:
utils_log("4 banks\n");
break;
case 0x02:
utils_log("8 banks\n");
break;
case 0x03:
utils_log("16 banks\n");
break;
case 0x04:
utils_log("32 banks\n");
break;
case 0x05:
utils_log("64 banks\n");
break;
case 0x06:
utils_log("128 banks\n");
break;
case 0x07:
utils_log("256 banks\n");
break;
case 0x52:
utils_log("72 banks\n");
break;
case 0x53:
utils_log("80 banks\n");
break;
case 0x54:
utils_log("96 banks\n");
break;
}
/* init MMU */
mmu_init(mbc, byte);
/* get RAM banks */
byte = rom[0x149];
utils_log("RAM: ");
switch (byte)
{
case 0x00:
utils_log("NO RAM\n");
break;
case 0x01:
mmu_init_ram(1 << 11);
utils_log("2 kB\n");
break;
case 0x02:
/* MBC5 got bigger values */
if (mbc >= 0x19 && mbc <= 0x1E)
{
mmu_init_ram(1 << 16);
utils_log("64 kB\n");
}
else
{
mmu_init_ram(1 << 13);
utils_log("8 kB\n");
}
break;
case 0x03:
mmu_init_ram(1 << 15);
utils_log("32 kB\n");
break;
case 0x04:
mmu_init_ram(1 << 17);
utils_log("128 kB\n");
break;
case 0x05:
mmu_init_ram(1 << 16);
utils_log("64 kB\n");
break;
}
/* restore saved RAM if it's the case */
//mmu_restore_ram(file_sav);
/* restore saved RTC if it's the case */
//mmu_restore_rtc(file_rtc);
/* load FULL ROM at 0x0000 address of system memory */
mmu_load_cartridge(rom, sz);
return 0;
}
/*void cartridge_term()
{
// save persistent data (battery backed RAM and RTC clock)
mmu_save_ram(file_sav);
mmu_save_rtc(file_rtc);
}*/

View File

@ -1,28 +0,0 @@
/*
This file is part of Emu-Pizza
Emu-Pizza is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Emu-Pizza is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CARTRIDGE_HDR__
#define __CARTRIDGE_HDR__
#include <stdint.h>
/* prototypes */
char cartridge_load(const void* data, size_t sz);
#endif

View File

@ -1,321 +0,0 @@
/*
This file is part of Emu-Pizza
Emu-Pizza is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Emu-Pizza is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "cycles.h"
#include "global.h"
#include "gpu.h"
#include "mmu.h"
#include "serial.h"
#include "sound.h"
#include "timer.h"
#include "interrupt.h"
#include "utils.h"
interrupts_flags_t *cycles_if;
/* instance of the main struct */
cycles_t cycles = {0, 0, 0, 0};
#define CYCLES_PAUSES 256
/* hard sync stuff (for remote connection) */
uint8_t cycles_hs_mode = 0;
/* type of next */
typedef enum {
CYCLES_NEXT_TYPE_CYCLES,
CYCLES_NEXT_TYPE_CYCLES_HS,
CYCLES_NEXT_TYPE_DMA,
} cycles_next_type_enum_e;
/* closest next and its type */
uint_fast32_t cycles_very_next;
cycles_next_type_enum_e cycles_next_type;
/* set hard sync mode. sync is given by the remote peer + local timer */
void cycles_start_hs()
{
utils_log("Hard sync mode ON\n");
/* boolean set to on */
cycles_hs_mode = 1;
}
void cycles_stop_hs()
{
utils_log("Hard sync mode OFF\n");
/* boolean set to on */
cycles_hs_mode = 0;
}
/* set double or normal speed */
void cycles_set_speed(char dbl)
{
/* set global */
global_cpu_double_speed = dbl;
/* update clock */
if (global_cpu_double_speed)
cycles.clock = 4194304 * 2;
else
cycles.clock = 4194304;
/* calculate the mask */
cycles_change_emulation_speed();
}
/* set emulation speed */
void cycles_change_emulation_speed()
{
cycles.step = ((4194304 / CYCLES_PAUSES)
<< global_cpu_double_speed);
}
void cycles_closest_next()
{
int_fast32_t diff = cycles.cnt - cycles.next;
/* init */
cycles_very_next = cycles.next;
cycles_next_type = CYCLES_NEXT_TYPE_CYCLES;
int_fast32_t diff_new = cycles.cnt - mmu.dma_next;
/* DMA? */
if (diff_new < diff)
{
/* this is the new lowest */
cycles_very_next = mmu.dma_next;
cycles_next_type = CYCLES_NEXT_TYPE_DMA;
}
}
/* this function is gonna be called every M-cycle = 4 ticks of CPU */
void cycles_step()
{
cycles.cnt += 4;
cycles.sampleclock += 2 >> global_cpu_double_speed;
/*
while (cycles.cnt >= cycles_very_next)
{
switch (cycles_next_type)
{
case CYCLES_NEXT_TYPE_CYCLES:
deadline.tv_nsec += 1000000000 / CYCLES_PAUSES;
if (deadline.tv_nsec > 1000000000)
{
deadline.tv_sec += 1;
deadline.tv_nsec -= 1000000000;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME,
&deadline, NULL);
cycles.next += cycles.step;
if (cycles.cnt % cycles.clock == 0)
cycles.seconds++;
break;
case CYCLES_NEXT_TYPE_DMA:
memcpy(&mmu.memory[0xFE00], &mmu.memory[mmu.dma_address], 160);
mmu.dma_address = 0x0000;
mmu.dma_next = 1;
break;
}
cycles_closest_next();
}
*/
/* 65536 == cpu clock / CYCLES_PAUSES pauses every second */
if (cycles.cnt == cycles.next)
{
cycles.next += cycles.step;
}
/* hard sync next step */
if (cycles.cnt == cycles.hs_next)
{
/* set cycles for hard sync */
cycles.hs_next += ((4096 * 4) << global_cpu_double_speed);
/* hard sync is on? */
if (cycles_hs_mode)
{
/* send my status and wait for peer status back */
serial_send_byte();
/* wait for reply */
serial_wait_data();
/* verify if we need to trigger an interrupt */
serial_verify_intr();
}
}
/* DMA */
if (mmu.dma_next == cycles.cnt)
{
memcpy(&mmu.memory[0xFE00], &mmu.memory[mmu.dma_address], 160);
/* reset address */
mmu.dma_address = 0x0000;
/* reset */
mmu.dma_next = 1;
}
/* update GPU state */
if (gpu.next == cycles.cnt)
gpu_step();
/* fs clock */
if (sound.fs_cycles_next == cycles.cnt)
sound_step_fs();
/* channel one */
if (sound.channel_one.duty_cycles_next == cycles.cnt)
sound_step_ch1();
/* channel two */
if (sound.channel_two.duty_cycles_next == cycles.cnt)
sound_step_ch2();
/* channel three */
if (sound.channel_three.cycles_next <= cycles.cnt)
sound_step_ch3();
/* channel four */
if (sound.channel_four.cycles_next == cycles.cnt)
sound_step_ch4();
/* update timer state */
if (cycles.cnt == timer.next)
{
timer.next += 256;
timer.div++;
}
/* timer is on? */
if (timer.sub_next == cycles.cnt)
{
timer.sub_next += timer.threshold;
timer.cnt++;
/* cnt value > 255? trigger an interrupt */
if (timer.cnt > 255)
{
timer.cnt = timer.mod;
/* trigger timer interrupt */
cycles_if->timer = 1;
}
}
/* update serial state */
if (serial.next == cycles.cnt)
{
/* nullize serial next */
serial.next -= 1;
/* reset counter */
serial.bits_sent = 0;
/* gotta reply with 0xff when asking for ff01 */
serial.data = 0xFF;
/* reset transfer_start flag to yell I'M DONE */
serial.transfer_start = 0;
/* if not connected, trig the fucking interrupt */
cycles_if->serial_io = 1;
}
}
/* things to do when vsync kicks in */
void cycles_vblank()
{
return;
}
/* stuff tied to entering into hblank state */
void cycles_hdma()
{
/* HDMA (only CGB) */
if (mmu.hdma_to_transfer)
{
/* hblank transfer */
if (mmu.hdma_transfer_mode)
{
/* transfer when line is changed and we're into HBLANK phase */
if (mmu.memory[0xFF44] < 143 &&
mmu.hdma_current_line != mmu.memory[0xFF44] &&
(mmu.memory[0xFF41] & 0x03) == 0x00)
{
/* update current line */
mmu.hdma_current_line = mmu.memory[0xFF44];
/* copy 0x10 bytes */
if (mmu.vram_idx)
memcpy(mmu_addr_vram1() + mmu.hdma_dst_address - 0x8000,
&mmu.memory[mmu.hdma_src_address], 0x10);
else
memcpy(mmu_addr_vram0() + mmu.hdma_dst_address - 0x8000,
&mmu.memory[mmu.hdma_src_address], 0x10);
/* decrease bytes to transfer */
mmu.hdma_to_transfer -= 0x10;
/* increase pointers */
mmu.hdma_dst_address += 0x10;
mmu.hdma_src_address += 0x10;
}
}
}
}
char cycles_init()
{
cycles.inited = 1;
/* interrupt registers */
cycles_if = mmu_addr(0xFF0F);
/* init clock and counter */
cycles.clock = 4194304;
cycles.cnt = 0;
cycles.hs_next = 70224;
/* mask for pauses cycles fast calc */
cycles.step = 4194304 / CYCLES_PAUSES;
cycles.next = 4194304 / CYCLES_PAUSES;
return 0;
}

View File

@ -1,68 +0,0 @@
/*
This file is part of Emu-Pizza
Emu-Pizza is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Emu-Pizza is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CYCLES_HDR__
#define __CYCLES_HDR__
#include <stdint.h>
#include <stdio.h>
typedef struct cycles_s
{
/* am i init'ed? */
uint_fast32_t inited;
/* ticks counter */
uint64_t cnt;
// CPU clock. advances at 4MHz or 8MHz depending on current cgb setting
uint_fast32_t clock;
/* handy for calculation */
uint64_t next;
/* step varying on cpu and emulation speed */
uint_fast32_t step;
/* 2 spares */
uint64_t hs_next;
// reference clock. advances at 2MHz always
uint64_t sampleclock;
} cycles_t;
extern cycles_t cycles;
// extern uint8_t cycles_hs_local_cnt;
// extern uint8_t cycles_hs_peer_cnt;
/* callback function */
typedef void (*cycles_send_cb_t)(uint32_t v);
/* prototypes */
void cycles_change_emulation_speed();
void cycles_hdma();
char cycles_init();
void cycles_set_speed(char dbl);
void cycles_start_hs();
void cycles_step();
void cycles_stop_hs();
void cycles_vblank();
#endif

View File

@ -1,235 +0,0 @@
/*
This file is part of Emu-Pizza
Emu-Pizza is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Emu-Pizza is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <string.h>
#include "cartridge.h"
#include "sound.h"
#include "mmu.h"
#include "cycles.h"
#include "gpu.h"
#include "global.h"
#include "input.h"
#include "timer.h"
#include "serial.h"
#include "utils.h"
#include "z80_gameboy_regs.h"
#include "z80_gameboy.h"
char gameboy_inited = 0;
void gameboy_init()
{
/* init z80 */
z80_init();
/* init cycles syncronizer */
cycles_init();
/* init timer */
timer_init();
/* init serial */
serial_init();
/* init sound (this will start audio thread) */
sound_init();
/* reset GPU counters */
gpu_reset();
/* reset to default values */
mmu_write_no_cyc(0xFF05, 0x00);
mmu_write_no_cyc(0xFF06, 0x00);
mmu_write_no_cyc(0xFF07, 0x00);
mmu_write_no_cyc(0xFF10, 0x80);
mmu_write_no_cyc(0xFF11, 0xBF);
mmu_write_no_cyc(0xFF12, 0xF3);
mmu_write_no_cyc(0xFF14, 0xBF);
mmu_write_no_cyc(0xFF16, 0x3F);
mmu_write_no_cyc(0xFF17, 0x00);
mmu_write_no_cyc(0xFF19, 0xBF);
mmu_write_no_cyc(0xFF1A, 0x7F);
mmu_write_no_cyc(0xFF1B, 0xFF);
mmu_write_no_cyc(0xFF1C, 0x9F);
mmu_write_no_cyc(0xFF1E, 0xBF);
mmu_write_no_cyc(0xFF20, 0xFF);
mmu_write_no_cyc(0xFF21, 0x00);
mmu_write_no_cyc(0xFF22, 0x00);
mmu_write_no_cyc(0xFF23, 0xBF);
mmu_write_no_cyc(0xFF24, 0x77);
mmu_write_no_cyc(0xFF25, 0xF3);
mmu_write_no_cyc(0xFF26, 0xF1);
mmu_write_no_cyc(0xFF40, 0x91);
mmu_write_no_cyc(0xFF41, 0x80);
mmu_write_no_cyc(0xFF42, 0x00);
mmu_write_no_cyc(0xFF43, 0x00);
mmu_write_no_cyc(0xFF44, 0x00);
mmu_write_no_cyc(0xFF45, 0x00);
mmu_write_no_cyc(0xFF47, 0xFC);
mmu_write_no_cyc(0xFF48, 0xFF);
mmu_write_no_cyc(0xFF49, 0xFF);
mmu_write_no_cyc(0xFF4A, 0x00);
mmu_write_no_cyc(0xFF4B, 0x00);
mmu_write_no_cyc(0xFF98, 0xDC);
mmu_write_no_cyc(0xFFFF, 0x00);
mmu_write_no_cyc(0xC000, 0x08);
mmu_write_no_cyc(0xFFFE, 0x69);
if (global_cgb)
state.a = 0x11;
else
state.a = 0x00;
state.b = 0x00;
state.c = 0x13;
state.d = 0x00;
state.e = 0xd8;
state.h = 0x01;
state.l = 0x4d;
state.pc = 0x0100;
state.sp = 0xFFFE;
*state.f = 0xB0;
/* reset counter */
cycles.cnt = 0;
/* start at normal speed */
global_cpu_double_speed = 0;
/* mark as inited */
gameboy_inited = 1;
return;
}
void gameboy_run(uint64_t target)
{
uint8_t op;
/* get interrupt flags and interrupt enables */
uint8_t *int_e;
uint8_t *int_f;
/* pointers to memory location of interrupt enables/flags */
int_e = mmu_addr(0xFFFF);
int_f = mmu_addr(0xFF0F);
/* run stuff! */
/* mechanism is simple. */
/* 1) execute instruction 2) update cycles counter 3) check interrupts */
/* and repeat forever */
while (cycles.sampleclock < target)
{
/* get op */
op = mmu_read(state.pc);
/* print out CPU state if enabled by debug flag */
if (global_debug)
{
utils_log("OP: %02x F: %02x PC: %04x:%02x:%02x SP: %04x:%02x:%02x ",
op, *state.f & 0xd0, state.pc,
mmu_read_no_cyc(state.pc + 1),
mmu_read_no_cyc(state.pc + 2), state.sp,
mmu_read_no_cyc(state.sp),
mmu_read_no_cyc(state.sp + 1));
utils_log("A: %02x BC: %04x DE: %04x HL: %04x FF41: %02x "
"FF44: %02x ENAB: %02x INTE: %02x INTF: %02x\n",
state.a, *state.bc,
*state.de, *state.hl,
mmu_read_no_cyc(0xFF41),
mmu_read_no_cyc(0xFF44),
state.int_enable,
*int_e, *int_f);
}
/* execute instruction by the GB Z80 version */
z80_execute(op);
/* if last op was Interrupt Enable (0xFB) */
/* we need to check for INTR on next cycle */
if (op == 0xFB)
continue;
/* interrupts filtered by enable flags */
uint8_t int_r = (*int_f & *int_e);
/* check for interrupts */
if ((state.int_enable || op == 0x76) && (int_r != 0))
{
/* discard useless bits */
if ((int_r & 0x1F) == 0x00)
continue;
/* beware of instruction that doesn't move PC! */
/* like HALT (0x76) */
if (op == 0x76)
{
state.pc++;
if (state.int_enable == 0)
continue;
}
/* reset int-enable flag, it will be restored after a RETI op */
state.int_enable = 0;
if ((int_r & 0x01) == 0x01)
{
/* vblank interrupt triggers RST 5 */
/* reset flag */
*int_f &= 0xFE;
/* handle the interrupt */
z80_intr(0x0040);
}
else if ((int_r & 0x02) == 0x02)
{
/* LCD Stat interrupt */
/* reset flag */
*int_f &= 0xFD;
/* handle the interrupt! */
z80_intr(0x0048);
}
else if ((int_r & 0x04) == 0x04)
{
/* timer interrupt */
/* reset flag */
*int_f &= 0xFB;
/* handle the interrupt! */
z80_intr(0x0050);
}
else if ((int_r & 0x08) == 0x08)
{
/* serial interrupt */
/* reset flag */
*int_f &= 0xF7;
/* handle the interrupt! */
z80_intr(0x0058);
}
}
}
}

View File

@ -1,28 +0,0 @@
/*
This file is part of Emu-Pizza
Emu-Pizza is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Emu-Pizza is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Emu-Pizza. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GAMEBOY_HDR__
#define __GAMEBOY_HDR__
/* prototypes */
void gameboy_init();
void gameboy_run(uint64_t target);
void gameboy_stop();
#endif

Some files were not shown because too many files have changed in this diff Show More