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
;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:0be996d25144966d5541c9eb4919b289 Ace of Aces A78 NTSC=true;board=A78SG
md5:aadde920b3aaba03bc10b40bd0619c94 Ace of Aces A78 PAL=true;board=A78SG
md5:877dcc97a775ed55081864b2dbf5f1e2 Alien Brigade A78 NTSC=true;board=A78S9
md5:de3e9496cb7341f865f27e5a72c7f2f5 Alien Brigade A78 PAL=true;board=A78S9
md5:0a9e58ef5eb9ff93246e0fff684dc7f1 Arkanoid (0911) A78 NTSC=true;board=A7832P
md5:A0285769753B18C407CB6E818B7DCAD2 3D Asteroids A78 NTSC=true;board=0
md5:0be996d25144966d5541c9eb4919b289 Ace of Aces A78 NTSC=true;board=1
md5:aadde920b3aaba03bc10b40bd0619c94 Ace of Aces A78 PAL=true;board=1
md5:877dcc97a775ed55081864b2dbf5f1e2 Alien Brigade A78 NTSC=true;board=2
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:a65f79ad4a0bbdecd59d5f7eb3623fd7 Asteroids Deluxe A78 NTSC=true;board=A7832
md5:1baf41de200f26ec643625021290bec2 Asteroids Deluxe A78 PAL=true;board=A7832
md5:a65f79ad4a0bbdecd59d5f7eb3623fd7 Asteroids Deluxe A78 NTSC=true;board=0
md5:1baf41de200f26ec643625021290bec2 Asteroids Deluxe A78 PAL=true;board=0
md5:07342c78619ba6ffcc61c10e907e3b50 Asteroids A78 NTSC=true;board=0
md5:8fc3a695eaea3984912d98ed4a543376 Ballblazer A78 NTSC=true;board=A7832P
md5:b558814d54904ce0582e2f6a801d03af Ballblazer A78 PAL=true;board=A7832P
md5:42682415906c21c6af80e4198403ffda Barnyard Blaster A78 NTSC=true;board=A78SG
md5:babe2bc2976688bafb8b23c192658126 Barnyard Blaster A78 PAL=true;board=A78SG
md5:f5f6b69c5eb4b55fc163158d1a6b423e Basketbrawl A78 NTSC=true;board=A78SG
md5:fba002089fcfa176454ab507e0eb76cb Basketbrawl A78 PAL=true;board=A78SG
md5:8fc3a695eaea3984912d98ed4a543376 Ballblazer A78 NTSC=true;board=0;Pokey=true
md5:b558814d54904ce0582e2f6a801d03af Ballblazer A78 PAL=true;board=0;Pokey=true
md5:42682415906c21c6af80e4198403ffda Barnyard Blaster A78 NTSC=true;board=1
md5:babe2bc2976688bafb8b23c192658126 Barnyard Blaster A78 PAL=true;board=1
md5:f5f6b69c5eb4b55fc163158d1a6b423e Basketbrawl A78 NTSC=true;board=1
md5:fba002089fcfa176454ab507e0eb76cb Basketbrawl A78 PAL=true;board=1
md5:6010a398070dfacb4c0173d75d73c50a 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:38c056a48472d9a9e16ebda5ed91dae7 Centipede A78 PAL=true;board=0
md5:93e4387864b014c155d7c17877990d1e Choplifter! A78 NTSC=true;board=0
md5:59d4edb0230b5acc918b94f6bc94779f Choplifter! A78 PAL=true;board=0
md5:441ac404cdc7bcbd4d787f911df7bf0d Color Test A78 NTSC=true;board=0
md5:2e8e28f6ad8b9b9267d518d880c73ebb Commando A78 NTSC=true;board=A78SGP
md5:55da6c6c3974d013f517e725aa60f48e Commando A78 PAL=true;board=A78SGP
md5:db691469128d9a4217ec7e315930b646 Crack'ed A78 NTSC=true;board=A78SG
md5:7cbe78fa06f47ba6516a67a4b003c9ee Crack'ed A78 PAL=true;board=A78SG
md5:0c9b124355d5328697a3b9e0011353f2 Crazy Brix A78 NTSC=true;board=A7816
md5:45e1d527becc96d1715e810d1c07ac27 Crazy Brix A78 NTSC=true;board=A7816
md5:fc7db1a9243ce2140f716762b8352a5c Crazy Brix A78 PAL=true;board=A7816
md5:a94e4560b6ad053a1c24e096f1262ebf Crossbow A78 NTSC=true;board=A78S9
md5:63db371d67a98daec547b2abd5e7aa95 Crossbow A78 PAL=true;board=A78S9
md5:179b76ff729d4849b8f66a502398acae CDark Chambers A78 NTSC=true;board=A78SG
md5:a2b8e2f159642c4b91de82e9a2928494 Dark Chambers A78 PAL=true;board=A78SG
md5:2e8e28f6ad8b9b9267d518d880c73ebb Commando A78 NTSC=true;board=1;Pokey=true
md5:55da6c6c3974d013f517e725aa60f48e Commando A78 PAL=true;board=1;Pokey=true
md5:db691469128d9a4217ec7e315930b646 Crack'ed A78 NTSC=true;board=1
md5:7cbe78fa06f47ba6516a67a4b003c9ee Crack'ed A78 PAL=true;board=1
md5:0c9b124355d5328697a3b9e0011353f2 Crazy Brix A78 NTSC=true;board=0
md5:45e1d527becc96d1715e810d1c07ac27 Crazy Brix A78 NTSC=true;board=0
md5:fc7db1a9243ce2140f716762b8352a5c Crazy Brix A78 PAL=true;board=0
md5:a94e4560b6ad053a1c24e096f1262ebf Crossbow A78 NTSC=true;board=2
md5:63db371d67a98daec547b2abd5e7aa95 Crossbow A78 PAL=true;board=2
md5:179b76ff729d4849b8f66a502398acae CDark Chambers A78 NTSC=true;board=1
md5:a2b8e2f159642c4b91de82e9a2928494 Dark Chambers A78 PAL=true;board=1
md5:95ac811c7d27af0032ba090f28c107bd Desert Falcon A78 NTSC=true;board=0
md5:2d5d99b993a885b063f9f22ce5e6523d Desert Falcon A78 PAL=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:19f1ee292a23636bd57d408b62de79c7 Donkey Kong A78 NTSC=true;board=0
md5:8e96ef14ce9b5d84bcbc996b66d6d4c7 Donkey Kong A78 PAL=true;board=0
md5:de2ebafcf0e37aaa9d0e9525a7f4dd62 Double Dragon A78 PAL=true;board=A78AC
md5:543484c00ba233736bcaba2da20eeea9 Double Dragon A78 NTSC=true;board=A78AC
md5:2251a6a0f3aec84cc0aff66fc9fa91e8 F-18 Hornet A78 NTSC=true;board=A78AB
md5:e7709da8e49d3767301947a0a0b9d2e6 F-18 Hornet A78 PAL=true;board=A78AB
md5:6287727ab36391a62f728bbdee88675c FailSafe A78 NTSC=true;board=A7848
md5:d2bb22f704f1610a4c396c51f5188e15 FailSafe A78 NTSC=true;board=A7848
md5:d25d5d19188e9f149977c49eb0367cd1 Fatal Run A78 NTSC=true;board=A78SG
md5:23505651ac2e47f3637152066c3aa62f Fatal Run A78 PAL=true;board=A78SG
md5:e80f24e953563e6b61556737d67d3836 Fight Night A78 PAL=true;board=A78SG
md5:07dbbfe612a0a28e283c01545e59f25e Fight Night A78 NTSC=true;board=A78SG
md5:de2ebafcf0e37aaa9d0e9525a7f4dd62 Double Dragon A78 PAL=true;board=4
md5:543484c00ba233736bcaba2da20eeea9 Double Dragon A78 NTSC=true;board=4
md5:2251a6a0f3aec84cc0aff66fc9fa91e8 F-18 Hornet A78 NTSC=true;board=3
md5:e7709da8e49d3767301947a0a0b9d2e6 F-18 Hornet A78 PAL=true;board=3
md5:6287727ab36391a62f728bbdee88675c FailSafe A78 NTSC=true;board=0
md5:d2bb22f704f1610a4c396c51f5188e15 FailSafe A78 NTSC=true;board=0
md5:d25d5d19188e9f149977c49eb0367cd1 Fatal Run A78 NTSC=true;board=1
md5:23505651ac2e47f3637152066c3aa62f Fatal Run A78 PAL=true;board=1
md5:e80f24e953563e6b61556737d67d3836 Fight Night A78 PAL=true;board=1
md5:07dbbfe612a0a28e283c01545e59f25e Fight Night A78 NTSC=true;board=1
md5:cf76b00244105b8e03cdc37677ec1073 Food Fight A78 NTSC=true;board=0
md5:de0d4f5a9bf1c1bddee3ed2f7ec51209 Food Fight A78 PAL=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:0baec96787ce17f390e204de1a136e59 Hat Trick A78 PAL=true;board=0
md5:fd9e78e201b6baafddfd3e1fbfe6ba31 Hat Trick A78 NTSC=true;board=0
md5:c3672482ca93f70eafd9134b936c3feb Ikari Warriors A78 NTSC=true;board=A78SG
md5:8c2c2a1ea6e9a928a44c3151ba5c1ce3 Ikari Warriors A78 PAL=true;board=A78SG
md5:1745feadabb24e7cefc375904c73fa4c Impossible Mission Fixed A78 NTSC=true;board=A78SGR
md5:baebc9246c087e893dfa489632157180 Impossible Mission A78 NTSC=true;board=A78SGR
md5:80dead01ea2db5045f6f4443faa6fce8 Impossible Mission A78 PAL=true;board=A78SGR
md5:045fd12050b7f2b842d5970f2414e912 Jinks A78 NTSC=true;board=A78SGR
md5:dfb86f4d06f05ad00cf418f0a59a24f7 Jinks A78 PAL=true;board=A78SGR
md5:c3672482ca93f70eafd9134b936c3feb Ikari Warriors A78 NTSC=true;board=1
md5:8c2c2a1ea6e9a928a44c3151ba5c1ce3 Ikari Warriors A78 PAL=true;board=1
md5:1745feadabb24e7cefc375904c73fa4c Impossible Mission Fixed A78 NTSC=true;board=1;RAM=8
md5:baebc9246c087e893dfa489632157180 Impossible Mission A78 NTSC=true;board=1;RAM=8
md5:80dead01ea2db5045f6f4443faa6fce8 Impossible Mission A78 PAL=true;board=1;RAM=8
md5:045fd12050b7f2b842d5970f2414e912 Jinks A78 NTSC=true;board=1;RAM=8
md5:dfb86f4d06f05ad00cf418f0a59a24f7 Jinks A78 PAL=true;board=1;RAM=8
md5:f18b3b897a25ab3885b43b4bd141b396 Joust A78 NTSC=true;board=0
md5:f2dae0264a4b4a73762b9d7177e989f6 Joust A78 PAL=true;board=0
md5:548ba2e54e4fc45ab84ed634d702c136 Jr. Ms. Pac-Man A78 NTSC=true;board=A7832P
md5:6bc2daeb48e28d103a4298a276e7e551 Jr. Pac-Man (Tunnels) A78 NTSC=true;board=A7832P
md5:0b3baf47886915dd2eec5da7671bfa63 Jr. Pac-Man A78 NTSC=true;board=A78SGR
md5:8281ab17fa3bfc0a6c497d6a4f350061 Jr. Pac-Man A78 NTSC=true;board=A78SGR
md5:17b3b764d33eae9b5260f01df7bb9d2f KLAX A78 NTSC=true;board=A78SG
md5:5e0a1e832bbcea6facb832fde23a440a Karateka A78 PAL=true;board=A78S4
md5:548ba2e54e4fc45ab84ed634d702c136 Jr. Ms. Pac-Man A78 NTSC=true;board=0;Pokey=true
md5:6bc2daeb48e28d103a4298a276e7e551 Jr. Pac-Man (Tunnels) A78 NTSC=true;board=0;Pokey=true
md5:0b3baf47886915dd2eec5da7671bfa63 Jr. Pac-Man A78 NTSC=true;board=1;RAM=8
md5:8281ab17fa3bfc0a6c497d6a4f350061 Jr. Pac-Man A78 NTSC=true;board=1;RAM=8
md5:17b3b764d33eae9b5260f01df7bb9d2f KLAX A78 NTSC=true;board=1
md5:5e0a1e832bbcea6facb832fde23a440a Karateka A78 PAL=true;board=1
md5:c3a5a8692a423d43d9d28dd5b7d109d9 Karateka 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:431ca060201ee1f9eb49d44962874049 Mario Bros. A78 NTSC=true;board=0
md5:d2e861306be78e44248bb71d7475d8a3 Mario Bros. A78 PAL=true;board=0
md5:37b5692e33a98115e574185fa8398c22 Mat Mania Challenge A78 NTSC=true;board=A78SG
md5:6819c37b96063b024898a19dbae2df54 Mat Mania Challenge A78 PAL=true;board=A78SG
md5:f2f5e5841e4dda89a2faf8933dc33ea6 Mean 18 Ultimate Golf A78 NTSC=true;board=A78SG
md5:2e9dbad6c0fa381a6cd1bb9abf98a104 Mean 18 Ultimate Golf A78 PAL=true;board=A78SG
md5:bedc30ec43587e0c98fc38c39c1ef9d0 Meltdown A78 NTSC=true;board=A78SG
md5:c80155d7eec9e3dcb79aa6b83c9ccd1e Meltdown A78 PAL=true;board=A78SG
md5:b02f93661f4b7e712810d2bf8e02ad79 Meteor Shower A78 NTSC=true;board=A7816
md5:2f1f199ecc2b414d28e01f0de53ca8f7 Meteor Shower A78 PAL=true;board=A7816
md5:bc1e905db1008493a9632aa83ab4682b Midnight Mutants A78 NTSC=true;board=A78SG
md5:6794ea31570eba0b88a0bf1ead3f3f1b Midnight Mutants A78 PAL=true;board=A78SG
md5:017066f522908081ec3ee624f5e4a8aa Missing in Action A78 NTSC=true;board=A78S9
md5:d0f46bf92ed6e7b1cce63278420cae8a Missing in Action A78 NTSC=true;board=A78S9
md5:9ff38ea62004201d870caa8bd9463525 Moon Cresta A78 NTSC=true;board=A7832
md5:3bc8f554cf86f8132a623cc2201a564b Motor Psycho A78 NTSC=true;board=A78SG
md5:5330bfe428a6b601b7e76c2cfc4cd049 Motor Psycho A78 PAL=true;board=A78SG
md5:37b5692e33a98115e574185fa8398c22 Mat Mania Challenge A78 NTSC=true;board=1
md5:6819c37b96063b024898a19dbae2df54 Mat Mania Challenge A78 PAL=true;board=1
md5:f2f5e5841e4dda89a2faf8933dc33ea6 Mean 18 Ultimate Golf A78 NTSC=true;board=1
md5:2e9dbad6c0fa381a6cd1bb9abf98a104 Mean 18 Ultimate Golf A78 PAL=true;board=1
md5:bedc30ec43587e0c98fc38c39c1ef9d0 Meltdown A78 NTSC=true;board=1
md5:c80155d7eec9e3dcb79aa6b83c9ccd1e Meltdown A78 PAL=true;board=1
md5:b02f93661f4b7e712810d2bf8e02ad79 Meteor Shower A78 NTSC=true;board=0
md5:2f1f199ecc2b414d28e01f0de53ca8f7 Meteor Shower A78 PAL=true;board=0
md5:bc1e905db1008493a9632aa83ab4682b Midnight Mutants A78 NTSC=true;board=1
md5:6794ea31570eba0b88a0bf1ead3f3f1b Midnight Mutants A78 PAL=true;board=1
md5:017066f522908081ec3ee624f5e4a8aa Missing in Action A78 NTSC=true;board=2
md5:d0f46bf92ed6e7b1cce63278420cae8a Missing in Action A78 NTSC=true;board=2
md5:9ff38ea62004201d870caa8bd9463525 Moon Cresta A78 NTSC=true;board=0
md5:3bc8f554cf86f8132a623cc2201a564b Motor Psycho A78 NTSC=true;board=1
md5:5330bfe428a6b601b7e76c2cfc4cd049 Motor Psycho A78 PAL=true;board=1
md5:fc0ea52a9fac557251b65ee680d951e5 Ms. Pac-Man A78 NTSC=true;board=0
md5:56469e8c5ff8983c6cb8dadc64eb0363 Ms. Pac-Man A78 PAL=true;board=0
md5:220121f771fc4b98cef97dc040e8d378 Ninja Golf A78 NTSC=true;board=A78SG
md5:ea0c859aa54fe5eaf4c1f327fab06221 Ninja Golf A78 PAL=true;board=A78SG
md5:220121f771fc4b98cef97dc040e8d378 Ninja Golf A78 NTSC=true;board=1
md5:ea0c859aa54fe5eaf4c1f327fab06221 Ninja Golf A78 PAL=true;board=1
md5:74569571a208f8b0b1ccfb22d7c914e1 One on One Basketball A78 NTSC=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: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:1a5207870dec6fae9111cb747e20d8e3 Pete Rose Baseball A78 NTSC=true;board=0
md5:05f43244465943ce819780a71a5b572a Pitfighter A78 NTSC=true;board=A78S4
md5:33aea1e2b6634a1dec8c7006d9afda22 Planet Smashers A78 NTSC=true;board=A78SG
md5:2837a8fd49b7fc7ccd70fd45b69c5099 Planet Smashers A78 PAL=true;board=A78SG
md5:86546808dc60961cdb1b20e761c50ab1 Plutos A78 NTSC=true;board=A78SGR
md5:05f43244465943ce819780a71a5b572a Pitfighter A78 NTSC=true;board=1
md5:33aea1e2b6634a1dec8c7006d9afda22 Planet Smashers A78 NTSC=true;board=1
md5:2837a8fd49b7fc7ccd70fd45b69c5099 Planet Smashers A78 PAL=true;board=1
md5:86546808dc60961cdb1b20e761c50ab1 Plutos A78 NTSC=true;board=1;RAM=8
md5:584582bb09ee8122e7fc09dc7d1ed813 Pole Position II A78 NTSC=true;board=0
md5:865457e0e0f48253b08f77b9e18f93b2 Pole Position II A78 PAL=true;board=0
md5:66e7230f7ef9d14db82d76b06b241bc0 Q-bert A78 NTSC=true;board=A7832
md5:ac03806cef2558fc795a7d5d8dba7bc0 Rampage A78 NTSC=true;board=A78AC
md5:383ed9bd1efb9b6cb3388a777678c928 Realsports Baseball A78 NTSC=true;board=A78S4
md5:8f7eb10ad0bd75474abf0c6c36c08486 Rescue on Fractalus A78 NTSC=true;board=A7832
md5:43525a0405184875c2ecfd0196886a34 Rip Off A78 NTSC=true;board=A7816
md5:106b409c6f4c219b1a3b3d099ead3b2b Rip Off A78 PAL=true;board=0A7816
md5:505f05e7f161f62ccd749dab3c4a204b Robot Finds Kitten A78 NTSC=true;board=A7832
md5:66e7230f7ef9d14db82d76b06b241bc0 Q-bert A78 NTSC=true;board=0
md5:ac03806cef2558fc795a7d5d8dba7bc0 Rampage A78 NTSC=true;board=4
md5:383ed9bd1efb9b6cb3388a777678c928 Realsports Baseball A78 NTSC=true;board=1
md5:8f7eb10ad0bd75474abf0c6c36c08486 Rescue on Fractalus A78 NTSC=true;board=0
md5:43525a0405184875c2ecfd0196886a34 Rip Off A78 NTSC=true;board=0
md5:106b409c6f4c219b1a3b3d099ead3b2b Rip Off A78 PAL=true;board=0
md5:505f05e7f161f62ccd749dab3c4a204b Robot Finds Kitten 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:c265cfd65534a4514f226cb4c7f7d6bf Scramble A78 NTSC=true;board=0
md5:1ee26fc6b06b4c9ba74931914b7e719d Scramble A78 PAL=true;board=0
md5:65fe82f419f6583a0f9a736242cb303d Scramble A78 PAL=true;board=0
md5:980c35ae9625773a450aa7ef51751c04 Scrapyard Dog A78 NTSC=true;board=A78SG
md5:53db322c201323fe2ca8f074c0a2bf86 Scrapyard Dog A78 PAL=true;board=A78SG
md5:b697d9c2d1b9f6cb21041286d1bbfa7f Sentinel A78 NTSC=true;board=A78SG
md5:5469b4de0608f23a5c4f98f331c9e75f Sentinel A78 PAL=true;board=A78SG
md5:2d643ac548c40e58c99d0fe433ba4ba0 Sirius A78 NTSC=true;board=A78SGR
md5:980c35ae9625773a450aa7ef51751c04 Scrapyard Dog A78 NTSC=true;board=1
md5:53db322c201323fe2ca8f074c0a2bf86 Scrapyard Dog A78 PAL=true;board=1
md5:b697d9c2d1b9f6cb21041286d1bbfa7f Sentinel A78 NTSC=true;board=1;Pokey=true
md5:5469b4de0608f23a5c4f98f331c9e75f Sentinel A78 PAL=true;board=1;Pokey=true
md5:2d643ac548c40e58c99d0fe433ba4ba0 Sirius A78 NTSC=true;board=1;RAM=8
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: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:162f9c953f0657689cc74ab20b40280f Super Huey UH-IX A78 PAL=true;board=0
md5:59b5793bece1c80f77b55d60fb39cb94 Super Skateboardin' A78 NTSC=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:1af475ff6429a160752b592f0f92b287 Titlematch Pro Wrestling A78 NTSC=true;board=0
md5:c3903ab01a51222a52197dbfe6538ecf Tomcat F14 A78 NTSC=true;board=0
md5:682338364243b023ecc9d24f0abfc9a7 Tomcat F14 A78 PAL=true;board=0
md5:208ef955fa90a29815eb097bce89bace Touchdown Football A78 NTSC=true;board=A78SG
md5:8d64763db3100aadc552db5e6868506a Tower Toppler A78 NTSC=true;board=A78S4R
md5:32a37244a9c6cc928dcdf02b45365aa8 Tower Toppler A78 PAL=true;board=A78S4R
md5:412cc5bfa08bd03244b9c4e8d46cd0a0 Wasp (Standard Edition) A78 NTSC=true;board=A7832
md5:427cb05d0a1abb068998e2760d77f4fb Water Ski A78 NTSC=true;board=A78S4
md5:3799d72f78dda2ee87b0ef8bf7b91186 Winter Games A78 NTSC=true;board=A78SGR
md5:6813ffff510f930c867b3f0aba78ac85 Worm (0703) A78 NTSC=true;board=A7816
md5:05fb699db9eef564e2fe45c568746dbc Xenophobe A78 NTSC=true;board=A78SG
md5:70937c3184f0be33d06f7f4382ca54de Xenophobe A78 PAL=true;board=A78SG
md5:208ef955fa90a29815eb097bce89bace Touchdown Football A78 NTSC=true;board=1
md5:8d64763db3100aadc552db5e6868506a Tower Toppler A78 NTSC=true;board=1;RAM=8
md5:32a37244a9c6cc928dcdf02b45365aa8 Tower Toppler A78 PAL=true;board=1;RAM=8
md5:412cc5bfa08bd03244b9c4e8d46cd0a0 Wasp (Standard Edition) A78 NTSC=true;board=0
md5:427cb05d0a1abb068998e2760d77f4fb Water Ski A78 NTSC=true;board=1
md5:3799d72f78dda2ee87b0ef8bf7b91186 Winter Games A78 NTSC=true;board=1;RAM=16
md5:6813ffff510f930c867b3f0aba78ac85 Worm (0703) A78 NTSC=true;board=0
md5:05fb699db9eef564e2fe45c568746dbc Xenophobe A78 NTSC=true;board=1
md5:70937c3184f0be33d06f7f4382ca54de Xenophobe A78 PAL=true;board=1
md5:d7dc17379aa25e5ae3c14b9e780c6f6d Xevious A78 NTSC=true;board=0
md5:b1a9f196ce5f47ca8caf8fa7bc4ca46c Xevious A78 PAL=true;board=0
md5:ce6fbdc7b037a4efdaf87267f5f292cc b*nQ A78 NTSC=true;board=0

View File

@ -134,6 +134,9 @@ namespace BizHawk.Client.Common
return path;
}
if (Path.IsPathRooted(path))
return path;
//handling of initial .. was removed (Path.GetFullPath can handle it)
//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.
// Other 'recognized' header sizes may need to be added.
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);
headerOffset = 0;
@ -86,6 +86,13 @@ namespace BizHawk.Client.Common
// note: this will be taking several hashes, of a potentially large amount of data.. yikes!
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();

View File

@ -554,7 +554,7 @@ namespace BizHawk.Client.Common
switch (game.System)
{
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;
break;
case "SAT":
@ -729,6 +729,15 @@ namespace BizHawk.Client.Common
nextEmulator = new Tst(nextComm, pcfxDiscs,
(Tst.Settings)GetCoreSettings<Tst>(), (Tst.SyncSettings)GetCoreSyncSettings<Tst>());
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:
return false;
}
@ -911,7 +920,6 @@ namespace BizHawk.Client.Common
case "GBC":
if (!Global.Config.GB_AsSGB)
{
//core = CoreInventory.Instance["GB", "Pizza Boy"];
core = CoreInventory.Instance["GB", "Gambatte"];
}
else
@ -925,7 +933,7 @@ namespace BizHawk.Client.Common
}
else
{
core = CoreInventory.Instance["SGB", "Pizza Boy"];
core = CoreInventory.Instance["SGB", "SameBoy"];
}
}
break;
@ -940,7 +948,7 @@ namespace BizHawk.Client.Common
{
nextEmulator = Global.Config.A78_UseEmu7800
? 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;

View File

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

View File

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

View File

@ -54,9 +54,10 @@ namespace BizHawk.Client.EmuHawk
public uint dwDrawStage;
public IntPtr Hdc;
public RECT Rect;
public int dwItemSpec;
public IntPtr dwItemSpec;
public uint ItemState;
public int lItemlParam;
private int _pad64bits;
public IntPtr lItemlParam;
}
[StructLayout(LayoutKind.Sequential)]
@ -596,7 +597,7 @@ namespace BizHawk.Client.EmuHawk
if (QueryItemBkColor != null)
{
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;
Marshal.StructureToPtr(cd, m.LParam, false);
}

View File

@ -176,7 +176,9 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions
public static DialogResult ShowHawkDialog(this CommonDialog form)
{
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();
return result;
}

View File

@ -180,8 +180,8 @@ namespace BizHawk.Client.EmuHawk
void InitializeButtons()
{
const int dzp = 9000;
const int dzn = -9000;
const int dzp = 20000;
const int dzn = -20000;
const int dzt = 40;
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.Client.ApiHawk;
using BizHawk.Emulation.Cores.Computers.Commodore64;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
namespace BizHawk.Client.EmuHawk
{
@ -1257,7 +1258,7 @@ namespace BizHawk.Client.EmuHawk
private void SGBCoreSubmenu_DropDownOpened(object sender, EventArgs e)
{
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)
@ -1270,7 +1271,6 @@ namespace BizHawk.Client.EmuHawk
}
}
private void GbInSgbMenuItem_Click(object sender, EventArgs e)
{
Global.Config.GB_AsSGB ^= true;
@ -2002,7 +2002,14 @@ namespace BizHawk.Client.EmuHawk
private void GBCoreSettingsMenuItem_Click(object sender, EventArgs e)
{
GBPrefs.DoGBPrefsDialog(this);
if (Global.Emulator is Gameboy)
{
GBPrefs.DoGBPrefsDialog(this);
}
else // sameboy
{
GenericCoreConfig.DoDialog(this, "Gameboy Settings");
}
}
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
}
if (_chromeless)
if (argParse._chromeless)
{
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.Consoles.SNK;
using BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive;
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
namespace BizHawk.Client.EmuHawk
{
@ -153,7 +154,6 @@ namespace BizHawk.Client.EmuHawk
}
};
ArgParser argParse = new ArgParser();
argParse.parseArguments(args);
Database.LoadDatabase(Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb.txt"));
@ -299,9 +299,9 @@ namespace BizHawk.Client.EmuHawk
Global.MovieSession.ReadOnly = true;
// 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
@ -1022,15 +1022,15 @@ namespace BizHawk.Client.EmuHawk
{
// TODO - maybe apply a hack tracked during fullscreen here to override it
FormBorderStyle = FormBorderStyle.None;
MainMenuStrip.Visible = Global.Config.DispChrome_MenuFullscreen && !_chromeless;
MainStatusBar.Visible = Global.Config.DispChrome_StatusBarFullscreen && !_chromeless;
MainMenuStrip.Visible = Global.Config.DispChrome_MenuFullscreen && !argParse._chromeless;
MainStatusBar.Visible = Global.Config.DispChrome_StatusBarFullscreen && !argParse._chromeless;
}
else
{
MainStatusBar.Visible = Global.Config.DispChrome_StatusBarWindowed && !_chromeless;
MainMenuStrip.Visible = Global.Config.DispChrome_MenuWindowed && !_chromeless;
MaximizeBox = MinimizeBox = Global.Config.DispChrome_CaptionWindowed && !_chromeless;
if (Global.Config.DispChrome_FrameWindowed == 0 || _chromeless)
MainStatusBar.Visible = Global.Config.DispChrome_StatusBarWindowed && !argParse._chromeless;
MainMenuStrip.Visible = Global.Config.DispChrome_MenuWindowed && !argParse._chromeless;
MaximizeBox = MinimizeBox = Global.Config.DispChrome_CaptionWindowed && !argParse._chromeless;
if (Global.Config.DispChrome_FrameWindowed == 0 || argParse._chromeless)
{
FormBorderStyle = FormBorderStyle.None;
}
@ -1356,7 +1356,6 @@ namespace BizHawk.Client.EmuHawk
// AVI/WAV state
private IVideoWriter _currAviWriter;
private readonly HashSet<int> _currAviWriterFrameList;
private AutofireController _autofireNullControls;
@ -1399,13 +1398,9 @@ namespace BizHawk.Client.EmuHawk
private Point _windowedLocation;
private bool _needsFullscreenOnLoad;
private int _autoDumpLength;
private readonly bool _autoCloseOnDump;
private int _lastOpenRomFilter;
// chrome is never shown, even in windowed mode
private readonly bool _chromeless;
private ArgParser argParse = new ArgParser();
// Resources
private Bitmap _statusBarDiskLightOnImage;
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 = "";
}
@ -1695,10 +1690,7 @@ namespace BizHawk.Client.EmuHawk
switch (system)
{
case "GEN":
if (!(Emulator is PicoDrive)) // Currently PicoDrive doesn't support anything in this menu
{
GenesisSubMenu.Visible = true;
}
GenesisSubMenu.Visible = true;
break;
case "TI83":
TI83SubMenu.Visible = true;
@ -1750,6 +1742,10 @@ namespace BizHawk.Client.EmuHawk
{
sNESToolStripMenuItem.Visible = true;
}
else if (Emulator is Sameboy)
{
GBSubMenu.Visible = true;
}
break;
case "Coleco":
ColecoSubMenu.Visible = true;
@ -3272,9 +3268,9 @@ namespace BizHawk.Client.EmuHawk
try
{
// 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;
}
@ -3356,14 +3352,14 @@ namespace BizHawk.Client.EmuHawk
AbortAv();
}
HANDLE_AUTODUMP:
if (_autoDumpLength > 0)
HANDLE_AUTODUMP:
if (argParse._autoDumpLength > 0)
{
_autoDumpLength--;
if (_autoDumpLength == 0) // finish
argParse._autoDumpLength--;
if (argParse._autoDumpLength == 0) // finish
{
StopAv();
if (_autoCloseOnDump)
if (argParse._autoCloseOnDump)
{
_exit = true;
}
@ -3545,7 +3541,7 @@ namespace BizHawk.Client.EmuHawk
if (result)
{
string loaderName = "*" + OpenAdvancedSerializer.Serialize(ioa);
Emulator = loader.LoadedEmulator;
Global.Game = loader.Game;

View File

@ -28,52 +28,63 @@
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PCEControllerConfig));
this.CancelBtn = new System.Windows.Forms.Button();
this.OkBtn = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// CancelBtn
//
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.Location = new System.Drawing.Point(235, 145);
this.CancelBtn.Name = "CancelBtn";
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
this.CancelBtn.TabIndex = 3;
this.CancelBtn.Text = "&Cancel";
this.CancelBtn.UseVisualStyleBackColor = true;
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
//
// OkBtn
//
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.Name = "OkBtn";
this.OkBtn.Size = new System.Drawing.Size(60, 23);
this.OkBtn.TabIndex = 2;
this.OkBtn.Text = "&OK";
this.OkBtn.UseVisualStyleBackColor = true;
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
//
// PCEControllerConfig
//
this.AcceptButton = this.OkBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CancelBtn;
this.ClientSize = new System.Drawing.Size(307, 180);
this.Controls.Add(this.CancelBtn);
this.Controls.Add(this.OkBtn);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PCEControllerConfig";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Controller Settings";
this.Load += new System.EventHandler(this.PCEControllerConfig_Load);
this.ResumeLayout(false);
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PCEControllerConfig));
this.CancelBtn = new System.Windows.Forms.Button();
this.OkBtn = new System.Windows.Forms.Button();
this.ControllerPropertyGrid = new System.Windows.Forms.PropertyGrid();
this.SuspendLayout();
//
// CancelBtn
//
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.Location = new System.Drawing.Point(235, 203);
this.CancelBtn.Name = "CancelBtn";
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
this.CancelBtn.TabIndex = 3;
this.CancelBtn.Text = "&Cancel";
this.CancelBtn.UseVisualStyleBackColor = true;
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
//
// OkBtn
//
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, 203);
this.OkBtn.Name = "OkBtn";
this.OkBtn.Size = new System.Drawing.Size(60, 23);
this.OkBtn.TabIndex = 2;
this.OkBtn.Text = "&OK";
this.OkBtn.UseVisualStyleBackColor = true;
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
//
this.AcceptButton = this.OkBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CancelBtn;
this.ClientSize = new System.Drawing.Size(307, 238);
this.Controls.Add(this.ControllerPropertyGrid);
this.Controls.Add(this.CancelBtn);
this.Controls.Add(this.OkBtn);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "PCEControllerConfig";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Controller Settings";
this.Load += new System.EventHandler(this.PCEControllerConfig_Load);
this.ResumeLayout(false);
}
@ -81,5 +92,6 @@
private System.Windows.Forms.Button CancelBtn;
private System.Windows.Forms.Button OkBtn;
private System.Windows.Forms.PropertyGrid ControllerPropertyGrid;
}
}

View File

@ -1,6 +1,4 @@
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Emulation.Cores.PCEngine;
@ -10,6 +8,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class PCEControllerConfig : Form
{
private PCEngine.PCESyncSettings _controllerSettings;
public PCEControllerConfig()
{
InitializeComponent();
@ -18,37 +18,13 @@ namespace BizHawk.Client.EmuHawk
private void PCEControllerConfig_Load(object sender, EventArgs e)
{
var pceSettings = ((PCEngine)Global.Emulator).GetSyncSettings();
for (int i = 0; i < 5; i++)
{
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
});
}
_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;
}
private void OkBtn_Click(object sender, EventArgs e)
{
var pceSettings = ((PCEngine)Global.Emulator).GetSyncSettings();
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);
GlobalWin.MainForm.PutCoreSyncSettings(_controllerSettings);
DialogResult = DialogResult.OK;
Close();
}

View File

@ -9,13 +9,15 @@ using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Client.EmuHawk.WinFormExtensions;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
public partial class GBGPUView : Form, IToolFormAutoConfig
{
[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
// 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
// b' = 8.25b
// gambatte doesn't modify these memory locations unless you reconstruct, so we can store
private IntPtr _vram;
private IntPtr _bgpal;
private IntPtr _sppal;
private IntPtr _oam;
private GPUMemoryAreas _memory;
private bool _cgb; // set once at start
private int _lcdc; // set at each callback
@ -89,13 +88,9 @@ namespace BizHawk.Client.EmuHawk
_cgb = Gb.IsCGBMode();
_lcdc = 0;
// TODO: can this be a required Emulator Service, and let the tool manage the logic of closing?
if (!Gb.GetGPUMemoryAreas(out _vram, out _bgpal, out _sppal, out _oam))
{
if (Visible)
Close();
}
tilespal = _bgpal;
_memory = Gb.GetGPU();
tilespal = _memory.Bgpal;
if (_cgb)
label4.Enabled = true;
@ -357,112 +352,120 @@ namespace BizHawk.Client.EmuHawk
#endregion
void ScanlineCallback(int lcdc)
void ScanlineCallback(byte lcdc)
{
_lcdc = lcdc;
// set alpha on all pixels
unsafe
using (_memory.EnterExit())
{
int* p = (int*)_bgpal;
for (int i = 0; i < 32; i++)
p[i] |= unchecked((int)0xff000000);
p = (int*)_sppal;
for (int i = 0; i < 32; i++)
p[i] |= unchecked((int)0xff000000);
int c = Spriteback.ToArgb();
for (int i = 0; i < 32; i += 4)
p[i] = c;
}
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
// bg maps
if (!_cgb)
{
DrawBGDMG(
bmpViewBG.BMP,
_vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
_vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
!lcdc.Bit(4),
_bgpal);
_lcdc = lcdc;
// set alpha on all pixels
// TODO: RE: Spriteback, you can't muck with Sameboy in this way due to how SGB reads stuff...?
/*unsafe
{
int* p = (int*)_bgpal;
for (int i = 0; i < 32; i++)
p[i] |= unchecked((int)0xff000000);
p = (int*)_sppal;
for (int i = 0; i < 32; i++)
p[i] |= unchecked((int)0xff000000);
int c = Spriteback.ToArgb();
for (int i = 0; i < 32; i += 4)
p[i] = c;
}*/
DrawBGDMG(
bmpViewWin.BMP,
_vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
_vram + 0x1000, // force win to second tile bank???
true,
_bgpal);
}
else
{
DrawBGCGB(
bmpViewBG.BMP,
_vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
_vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
!lcdc.Bit(4),
_bgpal);
// bg maps
if (!_cgb)
{
DrawBGDMG(
bmpViewBG.BMP,
_vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
_vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
!lcdc.Bit(4),
_bgpal);
DrawBGCGB(
bmpViewWin.BMP,
_vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
_vram + 0x1000, // force win to second tile bank???
true,
_bgpal);
}
bmpViewBG.Refresh();
bmpViewWin.Refresh();
DrawBGDMG(
bmpViewWin.BMP,
_vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
_vram + 0x1000, // force win to second tile bank???
true,
_bgpal);
}
else
{
DrawBGCGB(
bmpViewBG.BMP,
_vram + (lcdc.Bit(3) ? 0x1c00 : 0x1800),
_vram + (lcdc.Bit(4) ? 0x0000 : 0x1000),
!lcdc.Bit(4),
_bgpal);
// tile display
// TODO: user selects palette to use, instead of fixed palette 0
// or possibly "smart" where, if a tile is in use, it's drawn with one of the palettes actually being used with it?
DrawTiles(bmpViewTiles1.BMP, _vram, tilespal);
bmpViewTiles1.Refresh();
if (_cgb)
{
DrawTiles(bmpViewTiles2.BMP, _vram + 0x2000, tilespal);
bmpViewTiles2.Refresh();
}
DrawBGCGB(
bmpViewWin.BMP,
_vram + (lcdc.Bit(6) ? 0x1c00 : 0x1800),
_vram + 0x1000, // force win to second tile bank???
true,
_bgpal);
}
bmpViewBG.Refresh();
bmpViewWin.Refresh();
// palettes
if (_cgb)
{
bmpViewBGPal.ChangeBitmapSize(8, 4);
if (bmpViewBGPal.Width != 128)
bmpViewBGPal.Width = 128;
bmpViewSPPal.ChangeBitmapSize(8, 4);
if (bmpViewSPPal.Width != 128)
bmpViewSPPal.Width = 128;
DrawPal(bmpViewBGPal.BMP, _bgpal, 8);
DrawPal(bmpViewSPPal.BMP, _sppal, 8);
}
else
{
bmpViewBGPal.ChangeBitmapSize(1, 4);
if (bmpViewBGPal.Width != 16)
bmpViewBGPal.Width = 16;
bmpViewSPPal.ChangeBitmapSize(2, 4);
if (bmpViewSPPal.Width != 32)
bmpViewSPPal.Width = 32;
DrawPal(bmpViewBGPal.BMP, _bgpal, 1);
DrawPal(bmpViewSPPal.BMP, _sppal, 2);
}
bmpViewBGPal.Refresh();
bmpViewSPPal.Refresh();
// tile display
// TODO: user selects palette to use, instead of fixed palette 0
// or possibly "smart" where, if a tile is in use, it's drawn with one of the palettes actually being used with it?
DrawTiles(bmpViewTiles1.BMP, _vram, tilespal);
bmpViewTiles1.Refresh();
if (_cgb)
{
DrawTiles(bmpViewTiles2.BMP, _vram + 0x2000, tilespal);
bmpViewTiles2.Refresh();
}
// oam
if (lcdc.Bit(2)) // 8x16
{
bmpViewOAM.ChangeBitmapSize(320, 16);
if (bmpViewOAM.Height != 16)
bmpViewOAM.Height = 16;
}
else
{
bmpViewOAM.ChangeBitmapSize(320, 8);
if (bmpViewOAM.Height != 8)
bmpViewOAM.Height = 8;
}
DrawOam(bmpViewOAM.BMP, _oam, _vram, _sppal, lcdc.Bit(2), _cgb);
bmpViewOAM.Refresh();
// palettes
if (_cgb)
{
bmpViewBGPal.ChangeBitmapSize(8, 4);
if (bmpViewBGPal.Width != 128)
bmpViewBGPal.Width = 128;
bmpViewSPPal.ChangeBitmapSize(8, 4);
if (bmpViewSPPal.Width != 128)
bmpViewSPPal.Width = 128;
DrawPal(bmpViewBGPal.BMP, _bgpal, 8);
DrawPal(bmpViewSPPal.BMP, _sppal, 8);
}
else
{
bmpViewBGPal.ChangeBitmapSize(1, 4);
if (bmpViewBGPal.Width != 16)
bmpViewBGPal.Width = 16;
bmpViewSPPal.ChangeBitmapSize(2, 4);
if (bmpViewSPPal.Width != 32)
bmpViewSPPal.Width = 32;
DrawPal(bmpViewBGPal.BMP, _bgpal, 1);
DrawPal(bmpViewSPPal.BMP, _sppal, 2);
}
bmpViewBGPal.Refresh();
bmpViewSPPal.Refresh();
// oam
if (lcdc.Bit(2)) // 8x16
{
bmpViewOAM.ChangeBitmapSize(320, 16);
if (bmpViewOAM.Height != 16)
bmpViewOAM.Height = 16;
}
else
{
bmpViewOAM.ChangeBitmapSize(320, 8);
if (bmpViewOAM.Height != 8)
bmpViewOAM.Height = 8;
}
DrawOam(bmpViewOAM.BMP, _oam, _vram, _sppal, lcdc.Bit(2), _cgb);
bmpViewOAM.Refresh();
}
// 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
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)
{
if (cbscanline == -2 && Gb != null)
if (cbscanline == -2)
Gb.SetScanlineCallback(ScanlineCallback, -2);
}
@ -614,145 +617,177 @@ namespace BizHawk.Client.EmuHawk
private unsafe void PaletteMouseover(int x, int y, bool sprite)
{
bmpViewDetails.ChangeBitmapSize(8, 10);
if (bmpViewDetails.Height != 80)
bmpViewDetails.Height = 80;
var sb = new StringBuilder();
x /= 16;
y /= 16;
int* pal = (int*)(sprite ? _sppal : _bgpal) + x * 4;
int color = pal[y];
sb.AppendLine(string.Format("Palette {0}", x));
sb.AppendLine(string.Format("Color {0}", y));
sb.AppendLine(string.Format("(R,G,B) = ({0},{1},{2})", color >> 16 & 255, color >> 8 & 255, color & 255));
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 10), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
int* dest = (int*)lockdata.Scan0;
int pitch = lockdata.Stride / sizeof(int);
for (int py = 0; py < 10; py++)
using (_memory.EnterExit())
{
for (int px = 0; px < 8; px++)
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
bmpViewDetails.ChangeBitmapSize(8, 10);
if (bmpViewDetails.Height != 80)
bmpViewDetails.Height = 80;
var sb = new StringBuilder();
x /= 16;
y /= 16;
int* pal = (int*)(sprite ? _sppal : _bgpal) + x * 4;
int color = pal[y];
sb.AppendLine(string.Format("Palette {0}", x));
sb.AppendLine(string.Format("Color {0}", y));
sb.AppendLine(string.Format("(R,G,B) = ({0},{1},{2})", color >> 16 & 255, color >> 8 & 255, color & 255));
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 10), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
int* dest = (int*)lockdata.Scan0;
int pitch = lockdata.Stride / sizeof(int);
for (int py = 0; py < 10; py++)
{
if (py < 8)
*dest++ = color;
else
*dest++ = pal[px / 2];
for (int px = 0; px < 8; px++)
{
if (py < 8)
*dest++ = color;
else
*dest++ = pal[px / 2];
}
dest -= 8;
dest += pitch;
}
dest -= 8;
dest += pitch;
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
unsafe void TileMouseover(int x, int y, bool secondbank)
{
// todo: draw with a specific palette
bmpViewDetails.ChangeBitmapSize(8, 8);
if (bmpViewDetails.Height != 64)
bmpViewDetails.Height = 64;
var sb = new StringBuilder();
x /= 8;
y /= 8;
int tileindex = y * 16 + x;
int tileoffs = tileindex * 16;
if (_cgb)
sb.AppendLine(string.Format("Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, secondbank ? 1 : 0));
else
sb.AppendLine(string.Format("Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
DrawTile((byte*)_vram + tileoffs + (secondbank ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)tilespal);
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
// todo: draw with a specific palette
bmpViewDetails.ChangeBitmapSize(8, 8);
if (bmpViewDetails.Height != 64)
bmpViewDetails.Height = 64;
var sb = new StringBuilder();
x /= 8;
y /= 8;
int tileindex = y * 16 + x;
int tileoffs = tileindex * 16;
if (_cgb)
sb.AppendLine(string.Format("Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, secondbank ? 1 : 0));
else
sb.AppendLine(string.Format("Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
DrawTile((byte*)_vram + tileoffs + (secondbank ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)tilespal);
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
}
unsafe void TilemapMouseover(int x, int y, bool win)
{
bmpViewDetails.ChangeBitmapSize(8, 8);
if (bmpViewDetails.Height != 64)
bmpViewDetails.Height = 64;
var sb = new StringBuilder();
bool secondmap = win ? _lcdc.Bit(6) : _lcdc.Bit(3);
int mapoffs = secondmap ? 0x1c00 : 0x1800;
x /= 8;
y /= 8;
mapoffs += y * 32 + x;
byte* mapbase = (byte*)_vram + mapoffs;
int tileindex = mapbase[0];
if (win || !_lcdc.Bit(4)) // 0x9000 base
if (tileindex < 128)
tileindex += 256; // compute all if from 0x8000 base
int tileoffs = tileindex * 16;
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
if (!_cgb)
using (_memory.EnterExit())
{
sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
DrawTile((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal);
}
else
{
int tileext = mapbase[8192];
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, tileext.Bit(3) ? 1 : 0));
sb.AppendLine(string.Format(" Palette {0}", tileext & 7));
sb.AppendLine(string.Format(" Flags {0}{1}{2}", tileext.Bit(5) ? 'H' : ' ', tileext.Bit(6) ? 'V' : ' ', tileext.Bit(7) ? 'P' : ' '));
DrawTileHv((byte*)_vram + tileoffs + (tileext.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal + 4 * (tileext & 7), tileext.Bit(5), tileext.Bit(6));
bmpViewDetails.ChangeBitmapSize(8, 8);
if (bmpViewDetails.Height != 64)
bmpViewDetails.Height = 64;
var sb = new StringBuilder();
bool secondmap = win ? _lcdc.Bit(6) : _lcdc.Bit(3);
int mapoffs = secondmap ? 0x1c00 : 0x1800;
x /= 8;
y /= 8;
mapoffs += y * 32 + x;
byte* mapbase = (byte*)_vram + mapoffs;
int tileindex = mapbase[0];
if (win || !_lcdc.Bit(4)) // 0x9000 base
if (tileindex < 128)
tileindex += 256; // compute all if from 0x8000 base
int tileoffs = tileindex * 16;
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
if (!_cgb)
{
sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", tileindex, tileoffs + 0x8000));
DrawTile((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal);
}
else
{
int tileext = mapbase[8192];
sb.AppendLine(string.Format("{0} Map ({1},{2}) @{3:x4}", win ? "Win" : "BG", x, y, mapoffs + 0x8000));
sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", tileindex, tileoffs + 0x8000, tileext.Bit(3) ? 1 : 0));
sb.AppendLine(string.Format(" Palette {0}", tileext & 7));
sb.AppendLine(string.Format(" Flags {0}{1}{2}", tileext.Bit(5) ? 'H' : ' ', tileext.Bit(6) ? 'V' : ' ', tileext.Bit(7) ? 'P' : ' '));
DrawTileHv((byte*)_vram + tileoffs + (tileext.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_bgpal + 4 * (tileext & 7), tileext.Bit(5), tileext.Bit(6));
}
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
unsafe void SpriteMouseover(int x, int y)
{
bool tall = _lcdc.Bit(2);
x /= 8;
y /= 8;
bmpViewDetails.ChangeBitmapSize(8, tall ? 16 : 8);
if (bmpViewDetails.Height != bmpViewDetails.BMP.Height * 8)
bmpViewDetails.Height = bmpViewDetails.BMP.Height * 8;
var sb = new StringBuilder();
using (_memory.EnterExit())
{
var _bgpal = _memory.Bgpal;
var _sppal = _memory.Sppal;
var _oam = _memory.Oam;
var _vram = _memory.Vram;
byte* oament = (byte*)_oam + 4 * x;
int sy = oament[0];
int sx = oament[1];
int tilenum = oament[2];
int flags = oament[3];
bool hflip = flags.Bit(5);
bool vflip = flags.Bit(6);
if (tall)
tilenum = vflip ? tilenum | 1 : tilenum & ~1;
int tileoffs = tilenum * 16;
sb.AppendLine(string.Format("Sprite #{0} @{1:x4}", x, 4 * x + 0xfe00));
sb.AppendLine(string.Format(" (x,y) = ({0},{1})", sx, sy));
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, tall ? 16 : 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
if (_cgb)
{
sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000, flags.Bit(3) ? 1 : 0));
sb.AppendLine(string.Format(" Palette {0}", flags & 7));
DrawTileHv((byte*)_vram + tileoffs + (flags.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
bool tall = _lcdc.Bit(2);
x /= 8;
y /= 8;
bmpViewDetails.ChangeBitmapSize(8, tall ? 16 : 8);
if (bmpViewDetails.Height != bmpViewDetails.BMP.Height * 8)
bmpViewDetails.Height = bmpViewDetails.BMP.Height * 8;
var sb = new StringBuilder();
byte* oament = (byte*)_oam + 4 * x;
int sy = oament[0];
int sx = oament[1];
int tilenum = oament[2];
int flags = oament[3];
bool hflip = flags.Bit(5);
bool vflip = flags.Bit(6);
if (tall)
DrawTileHv((byte*)_vram + (tileoffs ^ 16) + (flags.Bit(3) ? 8192 : 0), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
tilenum = vflip ? tilenum | 1 : tilenum & ~1;
int tileoffs = tilenum * 16;
sb.AppendLine(string.Format("Sprite #{0} @{1:x4}", x, 4 * x + 0xfe00));
sb.AppendLine(string.Format(" (x,y) = ({0},{1})", sx, sy));
var lockdata = bmpViewDetails.BMP.LockBits(new Rectangle(0, 0, 8, tall ? 16 : 8), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
if (_cgb)
{
sb.AppendLine(string.Format(" Tile #{0} @{2}:{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000, flags.Bit(3) ? 1 : 0));
sb.AppendLine(string.Format(" Palette {0}", flags & 7));
DrawTileHv((byte*)_vram + tileoffs + (flags.Bit(3) ? 8192 : 0), (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
if (tall)
DrawTileHv((byte*)_vram + (tileoffs ^ 16) + (flags.Bit(3) ? 8192 : 0), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags & 7), hflip, vflip);
}
else
{
sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000));
sb.AppendLine(string.Format(" Palette {0}", flags.Bit(4) ? 1 : 0));
DrawTileHv((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + (flags.Bit(4) ? 4 : 0), hflip, vflip);
if (tall)
DrawTileHv((byte*)_vram + (tileoffs ^ 16), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags.Bit(4) ? 4 : 0), hflip, vflip);
}
sb.AppendLine(string.Format(" Flags {0}{1}{2}", hflip ? 'H' : ' ', vflip ? 'V' : ' ', flags.Bit(7) ? 'P' : ' '));
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
else
{
sb.AppendLine(string.Format(" Tile #{0} @{1:x4}", y == 1 ? tilenum ^ 1 : tilenum, tileoffs + 0x8000));
sb.AppendLine(string.Format(" Palette {0}", flags.Bit(4) ? 1 : 0));
DrawTileHv((byte*)_vram + tileoffs, (int*)lockdata.Scan0, lockdata.Stride / sizeof(int), (int*)_sppal + (flags.Bit(4) ? 4 : 0), hflip, vflip);
if (tall)
DrawTileHv((byte*)_vram + (tileoffs ^ 16), (int*)(lockdata.Scan0 + lockdata.Stride * 8), lockdata.Stride / sizeof(int), (int*)_sppal + 4 * (flags.Bit(4) ? 4 : 0), hflip, vflip);
}
sb.AppendLine(string.Format(" Flags {0}{1}{2}", hflip ? 'H' : ' ', vflip ? 'V' : ' ', flags.Bit(7) ? 'P' : ' '));
bmpViewDetails.BMP.UnlockBits(lockdata);
labelDetails.Text = sb.ToString();
bmpViewDetails.Refresh();
}
private void bmpViewBG_MouseEnter(object sender, EventArgs e)
@ -882,9 +917,9 @@ namespace BizHawk.Client.EmuHawk
else if (e.Button == MouseButtons.Left)
{
if (sender == bmpViewBGPal)
tilespal = _bgpal + e.X / 16 * 16;
tilespal = _memory.Bgpal + e.X / 16 * 16;
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()
{
Docs = new LuaDocumentation();
if(NLua.Lua.WhichLua == "NLua")
//if(NLua.Lua.WhichLua == "NLua")
_lua["keepalives"] = _lua.NewTable();
}
@ -178,7 +178,7 @@ namespace BizHawk.Client.EmuHawk
var content = File.ReadAllText(file);
var main = lua.LoadString(content, "main");
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;
//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.DoString(command);
if (NLua.Lua.WhichLua == "NLua")
//if (NLua.Lua.WhichLua == "NLua")
_lua.Pop();
}

View File

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

View File

@ -78,7 +78,7 @@ namespace BizHawk.Client.EmuHawk
DenoteMarkersWithBGColor = true;
}
public RecentFiles RecentTas { get; }
public RecentFiles RecentTas { get; set; }
public bool DrawInput { get; set; }
public bool AutoPause { 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 StandardControllerName => typeof(StandardController).DisplayName();
private string ProLineControllerName => typeof(ProLineController).DisplayName();
public IEnumerable<PadSchema> GetPadSchemas(IEmulator core)
{
var intvSyncSettings = ((A7800Hawk)core).GetSyncSettings().Clone();
var port1 = intvSyncSettings.Port1;
var port2 = intvSyncSettings.Port2;
var A78SyncSettings = ((A7800Hawk)core).GetSyncSettings().Clone();
var port1 = A78SyncSettings.Port1;
var port2 = A78SyncSettings.Port2;
if (port1 == StandardControllerName)
{
@ -28,7 +29,17 @@ namespace BizHawk.Client.EmuHawk
{
yield return JoystickController(2);
}
if (port1 == ProLineControllerName)
{
yield return ProLineController(1);
}
if (port2 == ProLineControllerName)
{
yield return ProLineController(2);
}
}
private static PadSchema ProLineController(int controller)

View File

@ -1,7 +1,10 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.PCEngine;
namespace BizHawk.Client.EmuHawk
{
@ -13,9 +16,34 @@ namespace BizHawk.Client.EmuHawk
{
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
{
Name = "P" + controller + " Up",
Name = $"P{controller} Up",
DisplayName = "",
Icon = Properties.Resources.BlueUp,
Location = new Point(14, 12),
@ -37,7 +65,7 @@ namespace BizHawk.Client.EmuHawk
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " Down",
Name = $"P{controller} Down",
DisplayName = "",
Icon = Properties.Resources.BlueDown,
Location = new Point(14, 56),
@ -45,7 +73,7 @@ namespace BizHawk.Client.EmuHawk
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " Left",
Name = $"P{controller} Left",
DisplayName = "",
Icon = Properties.Resources.Back,
Location = new Point(2, 34),
@ -53,7 +81,7 @@ namespace BizHawk.Client.EmuHawk
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " Right",
Name = $"P{controller} Right",
DisplayName = "",
Icon = Properties.Resources.Forward,
Location = new Point(24, 34),
@ -61,28 +89,28 @@ namespace BizHawk.Client.EmuHawk
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " B2",
Name = $"P{controller} B2",
DisplayName = "II",
Location = new Point(122, 34),
Type = PadSchema.PadInputType.Boolean
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " B1",
Name = $"P{controller} B1",
DisplayName = "I",
Location = new Point(146, 34),
Type = PadSchema.PadInputType.Boolean
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " Select",
Name = $"P{controller} Select",
DisplayName = "s",
Location = new Point(52, 34),
Type = PadSchema.PadInputType.Boolean
},
new PadSchema.ButtonSchema
{
Name = "P" + controller + " Run",
Name = $"P{controller} Run",
DisplayName = "R",
Location = new Point(74, 34),
Type = PadSchema.PadInputType.Boolean

View File

@ -72,7 +72,8 @@ namespace BizHawk.Emulation.Common
Option("SAT", "E", ss_100_j);
Option("SAT", "E", ss_101_j);
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_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\A7800HawkControllers.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\MemoryMap.cs">
<DependentUpon>A7800Hawk.cs</DependentUpon>
@ -537,8 +541,8 @@
<Compile Include="Consoles\Nintendo\Gameboy\GBDisassembler.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\IGameboyCommon.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\LibGambatte.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\LibPizza.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\Pizza.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\LibSameboy.cs" />
<Compile Include="Consoles\Nintendo\Gameboy\Sameboy.cs" />
<Compile Include="Consoles\Nintendo\GBA\ArmV4Disassembler.cs" />
<Compile Include="Consoles\Nintendo\GBA\GBA.cs" />
<Compile Include="Consoles\Nintendo\GBA\IGBAGPUViewable.cs" />
@ -1005,6 +1009,7 @@
<Compile Include="Consoles\PC Engine\ADPCM.cs" />
<Compile Include="Consoles\PC Engine\MemoryMap.TurboCD.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.ICodeDataLogger.cs">
<DependentUpon>PCEngine.cs</DependentUpon>
@ -1309,6 +1314,8 @@
<None Include="Consoles\Nintendo\NES\Docs\BoardTable.xlsx" />
<None Include="Consoles\Nintendo\NES\Docs\MapperCompatibilityList.url" />
<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" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
@ -1326,4 +1333,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>

View File

@ -13,6 +13,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
//Maria related variables
public int cycle;
public int cpu_cycle;
public int m6532_cycle;
public bool cpu_is_haltable;
public bool cpu_is_halted;
public bool cpu_halt_pending;
@ -23,7 +24,15 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public byte p2_state;
public byte p1_fire;
public byte p2_fire;
public byte p1_fire_2x;
public byte p2_fire_2x;
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)
// 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)
{
Console.WriteLine("-----------------------FRAME-----------------------");
if (_tracer.Enabled)
{
cpu.TraceCallback = s => _tracer.Put(s);
@ -75,6 +85,14 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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)))
{
cpu_is_haltable = true;
@ -149,6 +167,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
p2_state = _controllerDeck.ReadPort2(controller);
p1_fire = _controllerDeck.ReadFire1(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)
@ -157,12 +179,34 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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"))
{
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"))
{
result |= (1 << 3);

View File

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

View File

@ -51,6 +51,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
tia.SyncState(ser);
maria.SyncState(ser);
m6532.SyncState(ser);
mapper.SyncState(ser);
ser.BeginSection("Atari7800");
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("_isPAL", ref _isPAL);
ser.Sync("TIA_regs", ref TIA_regs, false);
ser.Sync("Maria_regs", ref Maria_regs, false);
ser.Sync("RAM", ref RAM, false);
ser.Sync("RAM_6532", ref RAM_6532, false);
@ -70,15 +70,23 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ser.Sync("cycle", ref 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_halted", ref cpu_is_halted);
ser.Sync("cpu_halt_pending", ref cpu_halt_pending);
ser.Sync("cpu_resume_pending", ref cpu_resume_pending);
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.Emulation.Common;
using BizHawk.Emulation.Cores.Components.M6502;
using BizHawk.Common.NumberExtensions;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
@ -22,7 +23,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public byte A7800_control_register;
// memory domains
public byte[] TIA_regs = new byte[0x20];
public byte[] Maria_regs = new byte[0x20];
public byte[] RAM = new byte[0x1000];
public byte[] RAM_6532 = new byte[0x80];
@ -37,16 +37,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public string s_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;
public MOS6502X cpu;
public Maria maria;
private bool _isPAL;
public bool _isPAL;
public M6532 m6532;
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);
@ -70,16 +74,24 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
CoreComm = comm;
_settings = (A7800Settings)settings ?? new A7800Settings();
_syncSettings = (A7800SyncSettings)syncSettings ?? new A7800SyncSettings();
_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[] 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[] header = new byte[128];
bool is_header = false;
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];
is_header = true;
Buffer.BlockCopy(rom, 0, header, 0, 128);
Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length);
rom = newrom;
}
@ -107,11 +119,77 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
s_mapper = dict["board"];
}
else
{
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
{
s_mapper = "1";
}
}
else
{
s_mapper = "0";
}
}
else
{
throw new Exception("ROM not in gamedb");
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);
@ -131,6 +209,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
maria._frameHz = 50;
maria._screen_width = 320;
maria._screen_height = 313;
maria._vblanklines = 20;
maria._palette = PALPalette;
}
else
@ -138,6 +217,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
maria._frameHz = 60;
maria._screen_width = 320;
maria._screen_height = 263;
maria._vblanklines = 20;
maria._palette = NTSCPalette;
}
@ -171,7 +251,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
maria.Reset();
m6532.Reset();
TIA_regs = new byte[0x20];
Maria_regs = new byte[0x20];
RAM = new byte[0x1000];
@ -185,10 +264,26 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
private void Reset_Mapper(string m)
{
if (m=="0")
if (m == "0")
{
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;
}
@ -197,93 +292,96 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
* MariaTables.cs
*
* Palette tables for the Maria class.
* All derived from Dan Boris' 7800/MAME code.
* PAL derived from Dan Boris' 7800/MAME code.
*
* Copyright © 2004 Mike Murphy
* PAL Table: Copyright © 2004 Mike Murphy
*
* NTSC Table Source: http://atariage.com/forums/topic/95498-7800-color-palette-in-mess/?p=1174461
*
*
*/
public static readonly int[] NTSCPalette =
{
0x000000, 0x1c1c1c, 0x393939, 0x595959, // Grey
0x797979, 0x929292, 0xababab, 0xbcbcbc,
0xcdcdcd, 0xd9d9d9, 0xe6e6e6, 0xececec,
0xf2f2f2, 0xf8f8f8, 0xffffff, 0xffffff,
0x000000, 0x2e2e2e, 0x3c3c3c, 0x595959,
0x777777, 0x838383, 0xa0a0a0, 0xb7b7b7,
0xcdcdcd, 0xd8d8d8, 0xdddddd, 0xe0e0e0,
0xeaeaea, 0xf0f0f0, 0xf6f6f6, 0xffffff,
0x391701, 0x5e2304, 0x833008, 0xa54716, // Gold
0xc85f24, 0xe37820, 0xff911d, 0xffab1d,
0xffc51d, 0xffce34, 0xffd84c, 0xffe651,
0xfff456, 0xfff977, 0xffff98, 0xffff98,
0x412000, 0x542800, 0x763706, 0x984f0f,
0xbb6818, 0xd78016, 0xff911d, 0xffab1d,
0xffc51d, 0xffd03b, 0xffd84c, 0xffe651,
0xfff456, 0xfff977, 0xffff98, 0xffffab,
0x451904, 0x721e11, 0x9f241e, 0xb33a20, // Orange
0xc85122, 0xe36920, 0xff811e, 0xff8c25,
0xff982c, 0xffae38, 0xffc545, 0xffc559,
0xffc66d, 0xffd587, 0xffe4a1, 0xffe4a1,
0x451904, 0x721e11, 0x9f241e, 0xb33a20,
0xc85122, 0xe36920, 0xfc811e, 0xff8c25,
0xff982c, 0xffae38, 0xffc455, 0xffc559,
0xffc66d, 0xffd587, 0xffe4a1, 0xffe6ab,
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119, // Red Orange
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
0xff706e, 0xff7f7e, 0xff8f8f, 0xff9d9e,
0xffabad, 0xffb9bd, 0xffc7ce, 0xffc7ce,
0x5f1f0e, 0x7a240d, 0x9c2c0f, 0xb02f0e,
0xbf3624, 0xd34e2a, 0xe7623e, 0xf36e4a,
0xfd7854, 0xff8a6a, 0xff987c, 0xffa48b,
0xffb39e, 0xffc2b2, 0xffd0c3, 0xffdad0,
0x050568, 0x3b136d, 0x712272, 0x8b2a8c, // Pink
0xa532a6, 0xb938ba, 0xcd3ecf, 0xdb47dd,
0xea51eb, 0xf45ff5, 0xfe6dff, 0xfe7afd,
0xff87fb, 0xff95fd, 0xffa4ff, 0xffa4ff,
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119,
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
0xff7063, 0xff7f7e, 0xff8f8f, 0xff9d9e,
0xffabad, 0xffb9bd, 0xffc7ce, 0xffcade,
0x280479, 0x400984, 0x590f90, 0x70249d, // Purple
0x8839aa, 0xa441c3, 0xc04adc, 0xd054ed,
0xe05eff, 0xe96dff, 0xf27cff, 0xf88aff,
0xff98ff, 0xfea1ff, 0xfeabff, 0xfeabff,
0x490136, 0x66014b, 0x80035f, 0x951874,
0xaa2d89, 0xba3d99, 0xca4da9, 0xd75ab6,
0xe467c3, 0xef72ce, 0xfb7eda, 0xff8de1,
0xff9de5, 0xffa5e7, 0xffafea, 0xffb8ec,
0x35088a, 0x420aad, 0x500cd0, 0x6428d0, // Purple Blue
0x7945d0, 0x8d4bd4, 0xa251d9, 0xb058ec,
0xbe60ff, 0xc56bff, 0xcc77ff, 0xd183ff,
0xd790ff, 0xdb9dff, 0xdfaaff, 0xdfaaff,
0x48036c, 0x5c0488, 0x650d91, 0x7b23a7,
0x933bbf, 0x9d45c9, 0xa74fd3, 0xb25ade,
0xbd65e9, 0xc56df1, 0xce76fa, 0xd583ff,
0xda90ff, 0xde9cff, 0xe2a9ff, 0xe6b6ff,
0x051e81, 0x0626a5, 0x082fca, 0x263dd4, // Blue1
0x444cde, 0x4f5aee, 0x5a68ff, 0x6575ff,
0x051e81, 0x0626a5, 0x082fca, 0x263dd4,
0x444cde, 0x4f5aec, 0x5a68ff, 0x6575ff,
0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff,
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xc0cbff,
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xcdd3ff,
0x0c048b, 0x2218a0, 0x382db5, 0x483ec7, // Blue2
0x584fda, 0x6159ec, 0x6b64ff, 0x7a74ff,
0x8a84ff, 0x918eff, 0x9998ff, 0xa5a3ff,
0xb1aeff, 0xb8b8ff, 0xc0c2ff, 0xc0c2ff,
0x0b0779, 0x201c8e, 0x3531a3, 0x4642b4,
0x5753c5, 0x615dcf, 0x6d69db, 0x7b77e9,
0x8985f7, 0x918dff, 0x9c98ff, 0xa7a4ff,
0xb2afff, 0xbbb8ff, 0xc3c1ff, 0xd3d1ff,
0x1d295a, 0x1d3876, 0x1d4892, 0x1c5cac, // Light Blue
0x1c71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
0x1d295a, 0x1d3876, 0x1d4892, 0x1d5cac,
0x1d71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff,
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xc3e9ff,
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xcfedff,
0x2f4302, 0x395202, 0x446103, 0x417a12, // Turquoise
0x3e9421, 0x4a9f2e, 0x57ab3b, 0x5cbd55,
0x61d070, 0x69e27a, 0x72f584, 0x7cfa8d,
0x87ff97, 0x9affa6, 0xadffb6, 0xadffb6,
0x014b59, 0x015d6e, 0x016f84, 0x01849c,
0x0199b5, 0x01abca, 0x01bcde, 0x01d0f5,
0x1adcff, 0x3ee1ff, 0x64e7ff, 0x76eaff,
0x8bedff, 0x9aefff, 0xb1f3ff, 0xc7f6ff,
0x0a4108, 0x0d540a, 0x10680d, 0x137d0f, // Green Blue
0x169212, 0x19a514, 0x1cb917, 0x1ec919,
0x21d91b, 0x47e42d, 0x6ef040, 0x78f74d,
0x83ff5b, 0x9aff7a, 0xb2ff9a, 0xb2ff9a,
0x004800, 0x005400, 0x036b03, 0x0e760e,
0x188018, 0x279227, 0x36a436, 0x4eb94e,
0x51cd51, 0x72da72, 0x7ce47c, 0x85ed85,
0xa2ffa2, 0xb5ffb5, 0xc8ffc8, 0xd0ffd0,
0x04410b, 0x05530e, 0x066611, 0x077714, // Green
0x088817, 0x099b1a, 0x0baf1d, 0x48c41f,
0x86d922, 0x8fe924, 0x99f927, 0xa8fc41,
0xb7ff5b, 0xc9ff6e, 0xdcff81, 0xdcff81,
0x164000, 0x1c5300, 0x236600, 0x287800,
0x2e8c00, 0x3a980c, 0x47a519, 0x51af23,
0x5cba2e, 0x71cf43, 0x85e357, 0x8deb5f,
0x97f569, 0xa4ff97, 0xb9ff97, 0xb9ff97,
0x02350f, 0x073f15, 0x0c4a1c, 0x2d5f1e, // Yellow Green
0x4f7420, 0x598324, 0x649228, 0x82a12e,
0xa1b034, 0xa9c13a, 0xb2d241, 0xc4d945,
0xd6e149, 0xe4f04e, 0xf2ff53, 0xf2ff53,
0x2c3500, 0x384400, 0x445200, 0x495600,
0x607100, 0x6c7f00, 0x798d0a, 0x8b9f1c,
0x9eb22f, 0xabbf3c, 0xb8cc49, 0xc2d653,
0xcde153, 0xdbef6c, 0xe8fc79, 0xf2ffab,
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
0x463a09, 0x4d3f09, 0x544509, 0x6c5809,
0x907609, 0xab8b0a, 0xc1a120, 0xd0b02f,
0xdebe3d, 0xe6c645, 0xedcd4c, 0xf6da65,
0xfde67d, 0xfff2a2, 0xfff9c5, 0xfff9d4,
0x401a02, 0x581f05, 0x702408, 0x8d3a13, // Light Orange
0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
0x401a02, 0x581f05, 0x702408, 0x8d3a13,
0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c,
0xffc160, 0xffc671, 0xffcb83, 0xffcb83
0xffc160, 0xffc671, 0xffcb83, 0xffd498
};
public static readonly int[] PALPalette =

View File

@ -70,6 +70,26 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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 void SyncState(Serializer ser)

View File

@ -9,7 +9,7 @@ using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
/// <summary>
/// Represents a controller plugged into a controller port on the intellivision
/// Represents a controller plugged into a controller port on the A7800
/// </summary>
public interface IPort
{
@ -17,6 +17,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
byte ReadFire(IController c);
byte ReadFire2x(IController c);
bool Is_2_button(IController c);
ControllerDefinition Definition { get; }
void SyncState(Serializer ser);
@ -42,10 +46,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
public byte ReadFire(IController c)
{
return 0x80;
}
public byte ReadFire2x(IController c)
{
return 0;
}
public bool Is_2_button(IController c)
{
return false;
}
public ControllerDefinition Definition { get; }
public void SyncState(Serializer ser)
@ -101,8 +115,17 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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)
{
@ -122,4 +145,89 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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 System;
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
@ -8,9 +9,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public A7800Hawk Core { get; set; }
private byte _ddRa = 0x00;
private byte _ddRb = 0x00;
private byte _outputA = 0x00;
public byte _ddRa = 0x00;
public byte _ddRb = 0x00;
public byte _outputA = 0x00;
public byte _outputB = 0x00;
public TimerData Timer;
@ -52,9 +54,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
if (registerAddr == 0x02)
{
Core._islag = false;
// Read Output reg B
byte temp = Core.con_state;
temp = (byte)(temp & ~_ddRb);
temp = (byte)(temp + (_outputB & _ddRb));
return temp;
}
@ -166,7 +171,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
else if (registerAddr == 0x02)
{
// Write Output reg B
// But is read only
_outputB = value;
}
else if (registerAddr == 0x03)
{
@ -187,7 +192,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
_ddRa = 0x00;
_ddRb = 0x00;
_outputA = 0x00;
}
_outputB = 0x00;
}
public void SyncState(Serializer ser)
{
@ -195,6 +201,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ser.Sync("ddra", ref _ddRa);
ser.Sync("ddrb", ref _ddRb);
ser.Sync("OutputA", ref _outputA);
ser.Sync("OutputB", ref _outputB);
Timer.SyncState(ser);
ser.EndSection();
}

View File

@ -38,9 +38,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
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
{

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 BizHawk.Emulation.Common;
using BizHawk.Common.NumberExtensions;
using BizHawk.Common;
@ -24,17 +23,21 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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
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 _screen_width = 320;
public int _screen_height = 263;
public int _vblanklines = 20;
public int[] _vidbuffer;
public int[] _palette;
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()
{
@ -42,9 +45,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
public int VirtualWidth => 320;
public int VirtualHeight => _screen_height;
public int VirtualHeight => _screen_height - _vblanklines;
public int BufferWidth => 320;
public int BufferHeight => _screen_height;
public int BufferHeight => _screen_height - _vblanklines;
public int BackgroundColor => unchecked((int)0xff000000);
public int VsyncNumerator => _frameHz;
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 graphics_read_time = 3; // depends on content of graphics header
public int DMA_phase_next;
public int base_scanline;
public ushort display_zone_pointer;
public int display_zone_counter;
@ -82,12 +84,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public bool current_DLL_H16;
public bool current_DLL_H8;
public int header_counter;
public int header_counter_max;
public int header_pointer; // since headers could be 4 or 5 bytes, we need a seperate pointer
public bool overrun_dma;
public bool global_write_mode;
// write mode is actually persistent but exists outside of the regs
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 scanline consists of 113.5 CPU cycles (fast access) which equates to 454 Maria cycles
@ -95,13 +97,13 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public void RunFrame()
{
scanline = 0;
global_write_mode = false;
Core.Maria_regs[8] = 0x80; // indicates VBlank state
// 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
// this is free time for the CPU to set up display lists
while (scanline < 19)
while (scanline < 20)
{
Core.RunCPUCycle();
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
sl_DMA_complete = false;
do_dma = false;
Core.Maria_regs[8] = 0; // we have now left VBLank
for (int i=0; i<454;i++)
{
if (i<28)
{
// 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))
if(i==28 && Core.Maria_regs[0x1C].Bit(6) && !Core.Maria_regs[0x1C].Bit(5))
{
Core.cpu_halt_pending = true;
DMA_phase = DMA_START_UP;
@ -161,26 +160,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
scanline++;
cycle = 0;
do_dma = false;
Core.Maria_regs[8] = 0; // we have now left VBLank
base_scanline = 0;
sl_DMA_complete = false;
Core.cpu.RDY = true;
// 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
while (scanline < 263)
{
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))
while (scanline < _screen_height)
{
if (cycle == 28 && Core.Maria_regs[0x1C].Bit(6) && !Core.Maria_regs[0x1C].Bit(5))
{
Core.cpu_halt_pending = true;
DMA_phase = DMA_START_UP;
DMA_phase_counter = 0;
do_dma = true;
sl_DMA_complete = false;
}
else if (!sl_DMA_complete && do_dma)
{
@ -194,6 +187,20 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
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)
{
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();
cycle++;
@ -214,14 +243,23 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
// add the current graphics to the buffer
draw_scanline(scanline - 21);
}
//Console.Write("Scanline");
//Console.WriteLine(scanline - 21);
scanline++;
cycle = 0;
Core.tia._hsyncCnt = 0;
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)
{
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++;
byte temp = ReadMemory((ushort)(current_DLL_addr + header_pointer));
// if there is no width, then we must have an extended header
@ -286,12 +324,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
else
{
// 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);
GFX_Objects[header_counter].ind_mode = temp.Bit(5);
GFX_Objects[GFX_index, header_counter].ind_mode = temp.Bit(5);
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++;
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)
@ -299,18 +337,18 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
if (temp_w == 0)
{
// 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
{
temp_w = (temp_w - 1);
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++;
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++;
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)
temp_w = (temp_w - 1);
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++;
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++;
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++;
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;
}
@ -358,37 +396,38 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
ushort addr_t = 0;
// 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;
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;
GFX_Objects[GFX_index, header_counter].width *= 2;
}
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;
}
// the address here is specified by CHAR_BASE maria registers
//ushort addr = (ushort)(GFX_Objects[header_counter].addr & 0xFF);
for (int i = 0; i < GFX_Objects[header_counter].width; i++)
// ushort addr = (ushort)(GFX_Objects[header_counter].addr & 0xFF);
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);
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)
{
@ -398,36 +437,37 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
graphics_read_time -= 9;
}
}
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
{
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);
if ((current_DLL_H16 && addr_t.Bit(12)) || (current_DLL_H8 && addr_t.Bit(11)))
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))) && (addr_t >= 0x8000))
{
GFX_Objects[header_counter].obj[i] = 0;
GFX_Objects[GFX_index, header_counter].obj[i] = 0;
graphics_read_time -= 3;
}
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;
sl_DMA_complete = true;
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_pointer = 0;
return;
@ -471,10 +511,11 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
current_DLL_offset = (byte)(temp & 0xF);
current_DLL_DLI = temp.Bit(7);
current_DLL_H16 = temp.Bit(6);
current_DLL_H8 = temp.Bit(5);
header_counter_max = header_counter;
header_counter_max[GFX_index] = header_counter;
header_counter = -1;
header_pointer = 0;
}
@ -490,70 +531,60 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
int local_palette;
int index;
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 temp_bg = Core.Maria_regs[0];
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_palette = GFX_Objects[i].palette;
local_start = GFX_Objects[local_GFX_index, i].h_pos;
local_palette = GFX_Objects[local_GFX_index, i].palette;
// the two different rendering paths are basically controlled by write mode
if (GFX_Objects[i].write_mode)
{
}
else
if (GFX_Objects[local_GFX_index, i].write_mode)
{
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 k = 7; k >= 0; k--)
for (int k = 3; k >= 0; k--)
{
index = local_start * 2 + j * 8 + (7 - k);
index = local_start * 2 + j * 4 + (3 - k);
if (index > 511)
{
index -= 512;
}
if (index > 511) index -= 512;
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
if (k>=6)
if (k >= 2)
{
color = (color >> 6) & 0x3;
}
else if (k>=4)
{
color = (color >> 4) & 0x3;
}
else if (k>=2)
{
color = (color >> 2) & 0x3;
color = (((color >> 2) & 0x3) << 2) + ((color >> 6) & 0x3);
}
else
{
color = color & 0x3;
color = ((color & 0x3) << 2) + ((color >> 4) & 0x3);
}
if (color != 0) // transparent
{
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
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];
}
}
@ -562,53 +593,203 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
else if (disp_mode == 2) // note: 1 is not used
{
local_width = GFX_Objects[i].width;
// here the palette is determined by palette bit 2 only
// hence only palette 0 or 4 is available
local_palette = GFX_Objects[i].palette & 0x4;
int temp_c0 = GFX_Objects[i].palette & 0x1;
int temp_c1 = GFX_Objects[i].palette & 0x2;
local_width = GFX_Objects[local_GFX_index, i].width;
for (int j = 0; j < local_width; j++)
{
for (int k = 7; k >= 0; k--)
{
color = (GFX_Objects[i].obj[j] >> k) & 1;
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
{
if (disp_mode == 0)
{
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 * 2 + 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) & 0x3;
}
else if (k >= 4)
{
color = (color >> 4) & 0x3;
}
else if (k >= 2)
{
color = (color >> 2) & 0x3;
}
else
{
color = color & 0x3;
}
if (color != 0) // transparent
{
color = Core.Maria_regs[local_palette * 4 + 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;
// here the palette is determined by palette bit 2 only
// hence only palette 0 or 4 is available
local_palette = GFX_Objects[local_GFX_index, i].palette & 0x4;
int temp_c0 = GFX_Objects[local_GFX_index, i].palette & 0x1;
int temp_c1 = GFX_Objects[local_GFX_index, i].palette & 0x2;
for (int j = 0; j < local_width; j++)
{
for (int k = 7; k >= 0; k--)
{
color = (GFX_Objects[local_GFX_index, i].obj[j] >> k) & 1;
color = (color << 1) | ((k % 2 == 0) ? temp_c0 : temp_c1);
index = local_start * 2 + j * 8 + (7 - k);
if (index > 511) index -= 512;
if (index < 320)
{
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];
}
}
}
}
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 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);
if (index > 511) index -= 512;
if (index < 320 && color == 1)
{
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];
}
}
@ -628,10 +809,13 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
_vidbuffer = new int[VirtualWidth * VirtualHeight];
for (int i = 0; i < 128; i++)
for (int j = 0; j < 2; j++)
{
GFX_Objects[i].obj = new byte[32];
}
for (int i = 0; i < 128; i++)
{
GFX_Objects[j, i].obj = new byte[128];
}
}
}
// Most of the Maria state is captured in Maria Regs in the core
@ -641,7 +825,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
{
ser.BeginSection("Maria");
ser.Sync("global write mode", ref global_write_mode);
ser.Sync("GFX_index", ref GFX_index);
ser.EndSection();
}

View File

@ -35,7 +35,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
else
{
return tia.ReadMemory((ushort)(addr & 0x1F), false);
//return TIA_regs[addr & 0x1F]; // TODO: what to return here?
}
}
else if ((addr & 0xFCE0) == 0x20)
@ -110,7 +109,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
}
else
{
TIA_regs[addr & 0x1F] = value;
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
var temp = addr & 0x1F;
if (temp != 8)
Maria_regs[temp] = value;
if (temp == 4) // WSYNC
cpu.RDY = false;
/*
for (int i = 0; i < 0x20; i++)
{
Console.Write(Maria_regs[i]);
Console.Write(" ");
}
Console.WriteLine(maria.scanline);
*/
}
else
{

View File

@ -14,6 +14,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
private bool _doTicks;
private int _spf;
public int _hsyncCnt;
private int _capChargeStart;
private bool _capCharging;
@ -31,7 +33,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
_capChargeStart = 0;
_capCharging = false;
AudioClocks = 0;
_spf = (Core.maria._frameHz > 55) ? 740 : 880;
_doTicks = false;
}
@ -92,34 +94,94 @@ 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
// 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
//INPT0-3 are used to read 2 button joysticks as well for the A7800
if (maskedAddr == 0x08) // INPT0
{
return 0;
if ((Core.m6532._outputB & 0x04) == 0 && (Core.m6532._ddRb & 0x04) == 0x04)
{
Core._islag = false;
return (byte)(Core.p1_fire_2x & 0x80);
}
else
{
return 0;
}
}
if (maskedAddr == 0x09) // INPT1
{
return 0;
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;
}
}
if (maskedAddr == 0x0A) // INPT2
{
return 0;
if ((Core.m6532._outputB & 0x10) == 0 && (Core.m6532._ddRb & 0x10) == 0x10)
{
Core._islag = false;
return (byte)(Core.p2_fire_2x & 0x80);
}
else
{
return 0;
}
}
if (maskedAddr == 0x0B) // INPT3
{
return 0;
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;
}
}
if (maskedAddr == 0x0C) // INPT4
{
return Core.p1_fire;
Core._islag = false;
if (!Core.p1_is_2button)
{
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
{
return Core.p2_fire;
Core._islag = false;
if (!Core.p2_is_2button)
{
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;

View File

@ -19,8 +19,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
public void GetSamplesSync(out short[] samples, out int nsamp)
{
short[] ret = new short[AudioClocks * 2];
nsamp = AudioClocks;
short[] ret = new short[_spf * 2];
nsamp = _spf;
GetSamples(ret);
samples = ret;
}
@ -35,8 +35,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
AudioClocks = 0;
}
private readonly int _spf;
// 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
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("Ticks", ref _doTicks);
ser.Sync("_spf", ref _spf);
// some of these things weren't in the state because they weren't needed if
// states were always taken at frame boundaries

View File

@ -492,10 +492,10 @@ namespace BizHawk.Emulation.Cores.Intellivision
// also if the pixel is on set it in the collision matrix
// note that the collision field is attached to the lower right corner of the BG
// so we add 8 to x and 16 to y here
if ((card_col * 8 + (7-pict_col) + 8) < 167)
if ((card_col * 8 + (7 - pict_col) + 8) < 167)
{
Collision[card_col * 8 + (7-pict_col) + 8, (card_row * 8 + pict_row) * 2 + 16] = 1 << 8;
Collision[card_col * 8 + (7-pict_col) + 8, (card_row * 8 + pict_row) * 2 + 16 + 1] = 1 << 8;
Collision[card_col * 8 + (7 - pict_col) + 8, (card_row * 8 + pict_row) * 2 + 16] = 1 << 8;
Collision[card_col * 8 + (7 - pict_col) + 8, (card_row * 8 + pict_row) * 2 + 16 + 1] = 1 << 8;
}
}
else
@ -521,7 +521,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
int min_x = x_border == 0 ? x_delay : x_border;
int min_y = y_border == 0 ? y_delay : y_border;
for (int j=input_row*8;j < (input_row * 8)+8; j++)
for (int j = input_row * 8; j < (input_row * 8) + 8; j++)
{
for (int i = 0; i < 159; i++)
{
@ -602,8 +602,11 @@ namespace BizHawk.Emulation.Cores.Intellivision
bool gram = attr.Bit(11);
byte loc_color = (byte)(attr & 7);
bool color_3 = attr.Bit(12);
if (color_3 && gram)
{
loc_color += 8;
}
bool priority = attr.Bit(13);
byte loc_x = (byte)(x & 0xFF);
@ -619,7 +622,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
ushort y_size = (ushort)(ysiz2 * ysiz4);
// setting yres implicitly uses an even card first
if (yres>1)
if (yres > 1)
card &= 0xFE;
// in GRAM mode only take the first 6 bits of the card number
@ -642,7 +645,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
}
// assign the y_mob, used to double vertical resolution
if (yres>1)
if (yres > 1)
{
for (int j = 0; j < 8; j++)
{
@ -752,15 +755,15 @@ namespace BizHawk.Emulation.Cores.Intellivision
{
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))
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
// 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);
}
@ -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 (!(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
//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;
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))
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
// 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);
}
@ -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 (!(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
@ -833,8 +836,8 @@ namespace BizHawk.Emulation.Cores.Intellivision
// by now we have collision information for all 8 mobs and the BG
// so we can store data in the collision registers here
int x_border = Register[0x32].Bit(0) ? 15-x_delay : 7-x_delay;
int y_border = Register[0x32].Bit(1) ? 30-y_delay*2 : 14-y_delay*2;
int x_border = Register[0x32].Bit(0) ? 15 - x_delay : 7 - x_delay;
int y_border = Register[0x32].Bit(1) ? 30 - y_delay * 2 : 14 - y_delay * 2;
int x_border_2 = Register[0x32].Bit(0) ? 8 : 0;
int y_border_2 = Register[0x32].Bit(1) ? 16 : 0;
@ -844,17 +847,17 @@ namespace BizHawk.Emulation.Cores.Intellivision
for (int j = 0; j < 210; j++)
{
// while we are here we can set collision detection bits for the border region
if (i == x_border || i == (167-x_delay))
if (i == x_border || i == (167 - x_delay))
{
Collision[i, j] |= (1 << 9);
}
if (j == y_border || j == y_border+1 || j == (208-y_delay*2) || j == (208 - y_delay * 2+1))
if (j == y_border || j == y_border + 1 || j == (208 - y_delay * 2) || j == (208 - y_delay * 2 + 1))
{
Collision[i, j] |= (1 << 9);
}
// and also make sure the border region is all the border color
if ((i-x_delay)>=0 && (i-x_delay)<=159 && (j-y_delay*2)>=0 && (j-y_delay*2)<192)
if ((i-x_delay)>=0 && (i-x_delay) <= 159 && (j-y_delay*2) >= 0 && (j-y_delay*2) < 192)
{
if ((i-x_delay) < x_border_2)
FrameBuffer[(j - y_delay*2) * 176 + ((i + 8) - x_delay) + BORDER_OFFSET] = ColorToRGBA(Register[0x2C] & 0xF);
@ -869,7 +872,7 @@ namespace BizHawk.Emulation.Cores.Intellivision
}
// the extra condition here is to ignore only border/BG collsion bit set
if (Collision[i, j] != 0 && Collision[i,j] != (1<<9) && Collision[i,j] != (1<<8))
if (Collision[i, j] != 0 && Collision[i,j] != (1 << 9) && Collision[i,j] != (1 << 8))
{
for (int k = 0; k < 8; k++)
{

View File

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

View File

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

View File

@ -439,7 +439,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
#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 _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.oam, ref _oam, ref unused))
{
vram = IntPtr.Zero;
bgpal = IntPtr.Zero;
sppal = IntPtr.Zero;
oam = IntPtr.Zero;
return false;
throw new InvalidOperationException("Unexpected error in gambatte_getmemoryarea");
}
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>
/// 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.Linq;
using System.Text;
@ -6,8 +8,49 @@ using System.Threading.Tasks;
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();
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
{
public abstract class LibPizza : LibWaterboxCore, ICustomSaveram
public abstract class LibSameboy : LibWaterboxCore
{
[Flags]
public enum Buttons : uint
@ -23,21 +23,33 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy
UP = 0x40,
DOWN = 0x80
}
[StructLayout(LayoutKind.Sequential)]
public new class FrameInfo : LibWaterboxCore.FrameInfo
{
public long Time;
public Buttons Keys;
}
[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)]
public abstract bool IsCGB();
public abstract void GetGpuMemory(IntPtr[] ptrs);
[BizImport(CC)]
public abstract int GetSaveramSize();
public abstract void SetScanlineCallback(ScanlineCallback callback, int ly);
[BizImport(CC)]
public abstract void PutSaveram(byte[] data, int size);
public abstract byte GetIoReg(byte port);
[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)]
public class NativeSettings
public class NativeSyncSettings
{
public int InstantReadHack;
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 SwapViews;
public int AnaglyphPreset;
@ -56,12 +69,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
return c.ToArgb();
}
public static NativeSettings FromFrontendSettings(VirtualBoyee.Settings s, VirtualBoyee.SyncSettings ss)
public static NativeSettings FromFrontendSettings(VirtualBoyee.Settings s)
{
return new NativeSettings
{
InstantReadHack = ss.InstantReadHack ? 1 : 0,
DisableParallax = ss.DisableParallax ? 1 : 0,
ThreeDeeMode = (int)s.ThreeDeeMode,
SwapViews = s.SwapViews ? 1 : 0,
AnaglyphPreset = (int)s.AnaglyphPreset,
@ -77,7 +88,10 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
[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)]
public abstract void HardReset();

View File

@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
[CoreConstructor("VB")]
public VirtualBoyee(CoreComm comm, byte[] rom, Settings settings, SyncSettings syncSettings)
:base(comm, new Configuration
: base(comm, new Configuration
{
DefaultFpsNumerator = 20000000,
DefaultFpsDenominator = 397824,
@ -38,8 +38,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
{
_settings = settings ?? new Settings();
_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
{
@ -50,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
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");
// do a quick hack up for frame zero size
@ -60,6 +58,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.VB
BufferHeight = tmp.Height;
PostInit();
_boyee.SetSettings(LibVirtualBoyee.NativeSettings.FromFrontendSettings(_settings));
}
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 ControllerDefinition ControllerDefinition => PCEngineController;
public ControllerDefinition ControllerDefinition => _controllerDeck.Definition;
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
{
@ -35,7 +38,6 @@ namespace BizHawk.Emulation.Cores.PCEngine
{
bool ret = PCESyncSettings.NeedsReboot(o, _syncSettings);
_syncSettings = o;
// SetControllerButtons(); // not safe to change the controller during emulation, so instead make it a reboot event
return ret;
}
@ -62,42 +64,48 @@ namespace BizHawk.Emulation.Cores.PCEngine
public class PCESyncSettings
{
public ControllerSetting[] Controllers =
{
new ControllerSetting { IsConnected = true },
new ControllerSetting { IsConnected = false },
new ControllerSetting { IsConnected = false },
new ControllerSetting { IsConnected = false },
new ControllerSetting { IsConnected = false }
};
[DefaultValue(PceControllerType.GamePad)]
[DisplayName("Port 1 Device")]
[Description("The type of controller plugged into the first controller port")]
[TypeConverter(typeof(DescribableEnumConverter))]
public PceControllerType Port1 { get; set; } = PceControllerType.GamePad;
[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()
{
var ret = new PCESyncSettings();
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; }
return (PCESyncSettings)MemberwiseClone();
}
public static bool NeedsReboot(PCESyncSettings x, PCESyncSettings y)
{
for (int i = 0; i < x.Controllers.Length; i++)
{
if (x.Controllers[i].IsConnected != y.Controllers[i].IsConnected)
{
return true;
}
}
return false;
return x.Port1 != y.Port1
|| x.Port2 != y.Port2
|| x.Port3 != y.Port3
|| x.Port4 != y.Port4
|| x.Port5 != y.Port5;
}
}
}

View File

@ -1,92 +1,41 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Emulation.Cores.PCEngine
namespace BizHawk.Emulation.Cores.PCEngine
{
public partial class PCEngine
{
private readonly ControllerDefinition PCEngineController = new ControllerDefinition
{
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 int _selectedController;
private byte _inputByte;
private void SetControllerButtons()
{
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 bool Sel => (_inputByte & 1) != 0;
private bool Clr => (_inputByte & 2) != 0;
private void WriteInput(byte value)
{
bool prevSEL = SEL;
InputByte = value;
bool prevSel = Sel;
_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()
{
InputCallbacks.Call();
byte value = 0x3F;
int player = SelectedController + 1;
int player = _selectedController + 1;
if (player < 6)
{
_lagged = false;
if (SEL == false) // return buttons
{
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;
}
value &= _controllerDeck.Read(player, _controller, Sel);
}
if (Region == "Japan")

View File

@ -41,7 +41,13 @@ namespace BizHawk.Emulation.Cores.PCEngine
Settings = (PCESettings)settings ?? new PCESettings();
_syncSettings = (PCESyncSettings)syncSettings ?? new PCESyncSettings();
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)
@ -96,7 +102,13 @@ namespace BizHawk.Emulation.Cores.PCEngine
// 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());
SetControllerButtons();
_controllerDeck = new PceControllerDeck(
_syncSettings.Port1,
_syncSettings.Port2,
_syncSettings.Port3,
_syncSettings.Port4,
_syncSettings.Port5);
}
// 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)]
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>
@ -28,7 +37,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
/// 32X games will still run, but will not have memory domains</param>
/// <returns></returns>
[BizImport(CC)]
public abstract bool Init(bool cd, bool _32xPreinit);
public abstract bool Init(bool cd, bool _32xPreinit, Region regionAutoOrder, Region regionOverride);
[BizImport(CC)]
public abstract void SetCDReadCallback(CDReadCallback callback);

View File

@ -8,12 +8,14 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using BizHawk.Common;
using System.ComponentModel;
namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
{
[Core("PicoDrive", "notaz", true, true,
"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.CDReadCallback _cdcallback;
@ -22,15 +24,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
private bool _isPal;
[CoreConstructor("GEN")]
public PicoDrive(CoreComm comm, GameInfo game, byte[] rom, bool deterministic)
:this(comm, game, rom, null, deterministic)
public PicoDrive(CoreComm comm, GameInfo game, byte[] rom, bool deterministic, SyncSettings syncSettings)
: this(comm, game, rom, null, deterministic, syncSettings)
{ }
public PicoDrive(CoreComm comm, GameInfo game, Disc cd, bool deterministic)
:this(comm, game, null, cd, deterministic)
public PicoDrive(CoreComm comm, GameInfo game, Disc cd, bool deterministic, SyncSettings syncSettings)
: 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
{
MaxSamples = 2048,
@ -49,6 +51,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
throw new InvalidOperationException("32X BIOS files are required for deterministic mode");
deterministic |= has32xBios;
_syncSettings = syncSettings ?? new SyncSettings();
_core = PreInit<LibPicoDrive>(new PeRunnerOptions
{
Filename = "picodrive.wbx",
@ -83,7 +87,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
_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!");
if (cd != null)
@ -174,6 +183,68 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.PicoDrive
_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
public bool DriveLightEnabled { get; private set; }

View File

@ -7,20 +7,45 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{
public IEmulatorServiceProvider ServiceProvider { get; private set; }
public ControllerDefinition ControllerDefinition { get; private set; }
// TODO: use render and rendersound
public ControllerDefinition ControllerDefinition { get; private set; }
// TODO: use render and rendersound
public void FrameAdvance(IController controller, bool render, bool rendersound = true)
{
if (controller.IsPressed("Reset"))
Core.gpgx_reset(false);
if (controller.IsPressed("Power"))
Core.gpgx_reset(true);
// this shouldn't be needed, as nothing has changed
// if (!Core.gpgx_get_control(input, inputsize))
// throw new Exception("gpgx_get_control() failed!");
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
// if (!Core.gpgx_get_control(input, inputsize))
// throw new Exception("gpgx_get_control() failed!");
ControlConverter.ScreenWidth = vwidth;
ControlConverter.ScreenHeight = vheight;
ControlConverter.Convert(controller, input);
@ -39,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (IsLagFrame)
LagCount++;
if (CD != null)
if (_cds != null)
DriveLightOn = _drivelight;
}
@ -70,8 +95,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{
if (_elf != null)
_elf.Dispose();
if (CD != null)
CD.Dispose();
if (_cds != null)
foreach (var cd in _cds)
cd.Dispose();
_disposed = true;
}
}

View File

@ -36,6 +36,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
Frame = reader.ReadInt32();
LagCount = reader.ReadInt32();
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!
Core.gpgx_set_input_callback(InputCallback);
RefreshMemCallbacks();
@ -51,6 +54,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
writer.Write(Frame);
writer.Write(LagCount);
writer.Write(IsLagFrame);
writer.Write(_discIndex);
writer.Write(_prevDiskPressed);
writer.Write(_nextDiskPressed);
}
public byte[] SaveStateBinary()

View File

@ -7,6 +7,8 @@ using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Waterbox;
using BizHawk.Common;
using BizHawk.Emulation.DiscSystem;
using System.Collections.Generic;
using System.Linq;
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);
// 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);
this.romfile = rom;
this.CD = CD;
if (CD != null)
_romfile = rom;
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);
Core.gpgx_set_cdd_callback(cd_callback_handle);
DriveLightEnabled = true;
}
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);
Core.gpgx_set_input_callback(InputCallback);
if (CD != null)
DriveLightEnabled = true;
// process the non-init settings now
PutSettings(_settings);
@ -154,14 +155,20 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
Tracer = new GPGXTraceBuffer(this, MemoryDomains, this);
(ServiceProvider as BasicServiceProvider).Register<ITraceable>(Tracer);
}
_romfile = null;
}
private LibGPGX Core;
private PeRunner _elf;
DiscSystem.Disc CD;
DiscSystem.DiscSectorReader DiscSectorReader;
byte[] romfile;
private Disc[] _cds;
private int _discIndex;
private DiscSectorReader[] _cdReaders;
private bool _prevDiskPressed;
private bool _nextDiskPressed;
byte[] _romfile;
private bool _disposed = false;
@ -201,28 +208,28 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (filename == "PRIMARY_ROM")
{
if (romfile == null)
if (_romfile == null)
{
Console.WriteLine("Couldn't satisfy firmware request PRIMARY_ROM because none was provided.");
return 0;
}
srcdata = romfile;
srcdata = _romfile;
}
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.");
return 0;
}
else
{
if (CD == null)
if (_cds == null)
{
Console.WriteLine("Couldn't satisfy firmware request {0} because none was provided.", filename);
return 0;
}
srcdata = GetCDData(CD);
srcdata = GetCDData(_cds[0]);
if (srcdata.Length != maxsize)
{
Console.WriteLine("Couldn't satisfy firmware request {0} because of struct size.", filename);
@ -283,36 +290,38 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
void CDRead(int lba, IntPtr dest, bool audio)
{
if (audio)
if ((uint)_discIndex < _cds.Length)
{
byte[] data = new byte[2352];
if (lba < CD.Session1.LeadoutLBA)
if (audio)
{
DiscSectorReader.ReadLBA_2352(lba, data, 0);
byte[] data = new byte[2352];
if (lba < _cds[_discIndex].Session1.LeadoutLBA)
{
_cdReaders[_discIndex].ReadLBA_2352(lba, data, 0);
}
else
{
// audio seems to read slightly past the end of disks; probably innoculous
// just send back 0s.
// Console.WriteLine("!!{0} >= {1}", lba, CD.LBACount);
}
Marshal.Copy(data, 0, dest, 2352);
}
else
{
// audio seems to read slightly past the end of disks; probably innoculous
// just send back 0s.
// Console.WriteLine("!!{0} >= {1}", lba, CD.LBACount);
byte[] data = new byte[2048];
_cdReaders[_discIndex].ReadLBA_2048(lba, data, 0);
Marshal.Copy(data, 0, dest, 2048);
_drivelight = true;
}
Marshal.Copy(data, 0, dest, 2352);
}
else
{
byte[] data = new byte[2048];
DiscSectorReader.ReadLBA_2048(lba, data, 0);
Marshal.Copy(data, 0, dest, 2048);
_drivelight = true;
}
}
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();
int size = Marshal.SizeOf(ret);
var ret = new LibGPGX.CDData();
var ses = cd.Session1;
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];
fixed (byte* p = &retdata[0])
@ -360,7 +376,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
if (!Core.gpgx_get_control(input, inputsize))
throw new Exception("gpgx_get_control() failed");
ControlConverter = new GPGXControlConverter(input);
ControlConverter = new GPGXControlConverter(input, false); // _cds != null);
ControllerDefinition = ControlConverter.ControllerDef;
}
@ -369,7 +385,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
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
{

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:");
foreach (var e in input.system)
@ -189,6 +189,11 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
ControllerDef.BoolButtons.Add("Power");
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++)
{

View File

@ -49,7 +49,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
public uint BackdropColor;
}
[BizImport(CallingConvention.Cdecl, Compatibility=true)]
[BizImport(CallingConvention.Cdecl, Compatibility = true)]
public abstract bool gpgx_init(string feromextension, load_archive_cb feload_archive_cb, bool sixbutton, INPUT_SYSTEM system_a, INPUT_SYSTEM system_b, Region region, [In]InitSettings settings);
[BizImport(CallingConvention.Cdecl)]
@ -84,34 +84,34 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
public enum INPUT_SYSTEM : byte
{
SYSTEM_NONE = 0, // unconnected port
SYSTEM_MD_GAMEPAD = 1, // single 3-buttons or 6-buttons Control Pad
SYSTEM_MOUSE = 2, // Sega Mouse
SYSTEM_MENACER = 3, // Sega Menacer -- port B only
SYSTEM_JUSTIFIER = 4, // Konami Justifiers -- port B only
SYSTEM_XE_A1P = 5, // XE-A1P analog controller -- port A only
SYSTEM_ACTIVATOR = 6, // Sega Activator
SYSTEM_MS_GAMEPAD = 7, // single 2-buttons Control Pad -- Master System
SYSTEM_LIGHTPHASER = 8, // Sega Light Phaser -- Master System
SYSTEM_PADDLE = 9, // Sega Paddle Control -- Master System
SYSTEM_SPORTSPAD = 10, // Sega Sports Pad -- Master System
SYSTEM_TEAMPLAYER = 11, // Multi Tap -- Sega TeamPlayer
SYSTEM_WAYPLAY = 12, // Multi Tap -- EA 4-Way Play -- use both ports
SYSTEM_NONE = 0, // unconnected port
SYSTEM_MD_GAMEPAD = 1, // single 3-buttons or 6-buttons Control Pad
SYSTEM_MOUSE = 2, // Sega Mouse
SYSTEM_MENACER = 3, // Sega Menacer -- port B only
SYSTEM_JUSTIFIER = 4, // Konami Justifiers -- port B only
SYSTEM_XE_A1P = 5, // XE-A1P analog controller -- port A only
SYSTEM_ACTIVATOR = 6, // Sega Activator
SYSTEM_MS_GAMEPAD = 7, // single 2-buttons Control Pad -- Master System
SYSTEM_LIGHTPHASER = 8, // Sega Light Phaser -- Master System
SYSTEM_PADDLE = 9, // Sega Paddle Control -- Master System
SYSTEM_SPORTSPAD = 10, // Sega Sports Pad -- Master System
SYSTEM_TEAMPLAYER = 11, // Multi Tap -- Sega TeamPlayer
SYSTEM_WAYPLAY = 12, // Multi Tap -- EA 4-Way Play -- use both ports
};
public enum INPUT_DEVICE : byte
{
DEVICE_NONE = 0xff, // unconnected device = fixed ID for Team Player)
DEVICE_PAD3B = 0x00, // 3-buttons Control Pad = fixed ID for Team Player)
DEVICE_PAD6B = 0x01, // 6-buttons Control Pad = fixed ID for Team Player)
DEVICE_PAD2B = 0x02, // 2-buttons Control Pad
DEVICE_MOUSE = 0x03, // Sega Mouse
DEVICE_NONE = 0xff, // unconnected device = fixed ID for Team Player)
DEVICE_PAD3B = 0x00, // 3-buttons Control Pad = fixed ID for Team Player)
DEVICE_PAD6B = 0x01, // 6-buttons Control Pad = fixed ID for Team Player)
DEVICE_PAD2B = 0x02, // 2-buttons Control Pad
DEVICE_MOUSE = 0x03, // Sega Mouse
DEVICE_LIGHTGUN = 0x04, // Sega Light Phaser, Menacer or Konami Justifiers
DEVICE_PADDLE = 0x05, // Sega Paddle Control
DEVICE_PADDLE = 0x05, // Sega Paddle Control
DEVICE_SPORTSPAD = 0x06,// Sega Sports Pad
DEVICE_PICO = 0x07, // PICO tablet
DEVICE_TEREBI = 0x08, // Terebi Oekaki tablet
DEVICE_XE_A1P = 0x09, // XE-A1P analog controller
DEVICE_PICO = 0x07, // PICO tablet
DEVICE_TEREBI = 0x08, // Terebi Oekaki tablet
DEVICE_XE_A1P = 0x09, // XE-A1P analog controller
DEVICE_ACTIVATOR = 0x0a,// Activator
};
@ -151,8 +151,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
[BizImport(CallingConvention.Cdecl)]
public abstract void gpgx_set_cd_callback(CDCallback cd);
/// <summary>
/// not every flag is valid for every device!
/// </summary>
@ -277,6 +275,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
[BizImport(CallingConvention.Cdecl)]
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)]
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>
/// Looks up a localized resource of type System.Byte[].
/// </summary>

View File

@ -118,6 +118,12 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<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">
<value>..\Resources\sgb-cart-present.spc.gz;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</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 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)
{
_availableFiles.Add(name, new ReadonlyFirmware(data, name));
@ -704,15 +781,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
public void RemoveReadonlyFile(string name)
{
IFileObject o;
if (!_availableFiles.TryGetValue(name, out o))
throw new InvalidOperationException("Firmware was never registered!");
var f = o as ReadonlyFirmware;
if (f == null)
throw new InvalidOperationException("Object was not a firmware!");
if (_openFiles.Contains(o))
throw new InvalidOperationException("Core never closed the firmware!");
_availableFiles.Remove(name);
RemoveFileInternal<ReadonlyFirmware>(name);
}
public void AddTransientFile(byte[] data, string name)
{
_availableFiles.Add(name, new TransientFile(data, name));
}
public byte[] RemoveTransientFile(string name)
{
return RemoveFileInternal<TransientFile>(name).GetContents();
}
}
@ -1090,6 +1168,24 @@ namespace BizHawk.Emulation.Cores.Waterbox
_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)
{
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);
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();
if (_imports != null)
{
@ -351,6 +358,10 @@ namespace BizHawk.Emulation.Cores.Waterbox
_imports.W = false;
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)
{
_sealed.W = false;

View File

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

View File

@ -618,6 +618,18 @@ namespace Lua511
static void lua_atunlock(IntPtr luaState, LuaCSFunction^ unlockf);
#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)
{
::lua_pushnumber(toState, number);

View File

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

View File

@ -803,6 +803,13 @@ namespace NLua
{
((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
{
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
#define ECL_ENTRY
// mark a visible symbol
#ifdef __cplusplus
#define ECL_EXPORT extern "C" __attribute__((visibility("default")))
#else
#define ECL_EXPORT __attribute__((visibility("default")))
#endif
// 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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -1,106 +1,110 @@
/***************************************************************************************
* Genesis Plus
* CD drive processor & CD-DA fader
*
* Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _HW_CDD_
#define _HW_CDD_
#include "blip_buf.h"
#ifdef USE_LIBTREMOR
#include "tremor/ivorbisfile.h"
#endif
#define cdd scd.cdd_hw
/* CDD status */
#define NO_DISC 0x00
#define CD_PLAY 0x01
#define CD_SEEK 0x02
#define CD_SCAN 0x03
#define CD_READY 0x04
#define CD_OPEN 0x05 /* similar to 0x0E ? */
#define CD_STOP 0x09
#define CD_END 0x0C
/* CD blocks scanning speed */
#define CD_SCAN_SPEED 30
#define CD_MAX_TRACKS 100
/* CD track */
typedef struct
{
int start;
int end;
} track_t;
/* CD TOC */
typedef struct
{
int end;
int last;
track_t tracks[CD_MAX_TRACKS];
} toc_t;
/* CDD hardware */
typedef struct
{
uint32 cycles;
uint32 latency;
int loaded;
int index;
int lba;
int scanOffset;
int volume;
int sampleOffset;
int sampleLba;
uint8 status;
toc_t toc;
int16 audio[2];
} cdd_t;
/* Function prototypes */
extern void cdd_init(blip_t* left, blip_t* right);
extern void cdd_reset(void);
extern int cdd_load(const char *key, char *header);
extern void cdd_unload(void);
extern void cdd_read_data(uint8 *dst);
extern void cdd_read_audio(unsigned int samples);
extern void cdd_update(void);
extern void cdd_process(void);
#endif
/***************************************************************************************
* Genesis Plus
* CD drive processor & CD-DA fader
*
* Copyright (C) 2012-2013 Eke-Eke (Genesis Plus GX)
*
* Redistribution and use of this code or any derivative works are permitted
* provided that the following conditions are met:
*
* - Redistributions may not be sold, nor may they be used in a commercial
* product or activity.
*
* - Redistributions that are modified from the original source must include the
* complete source code, including the source code for all components used by a
* binary built from the modified sources. However, as a special exception, the
* source code distributed need not include anything that is normally distributed
* (in either source or binary form) with the major components (compiler, kernel,
* and so on) of the operating system on which the executable runs, unless that
* component itself accompanies the executable.
*
* - Redistributions must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************************/
#ifndef _HW_CDD_
#define _HW_CDD_
#include "blip_buf.h"
#ifdef USE_LIBTREMOR
#include "tremor/ivorbisfile.h"
#endif
#define cdd scd.cdd_hw
/* CDD status */
#define NO_DISC 0x00
#define CD_PLAY 0x01
#define CD_SEEK 0x02
#define CD_SCAN 0x03
#define CD_READY 0x04
#define CD_OPEN 0x05 /* similar to 0x0E ? */
#define CD_STOP 0x09
#define CD_END 0x0C
/* CD blocks scanning speed */
#define CD_SCAN_SPEED 30
#define CD_MAX_TRACKS 100
/* CD track */
typedef struct
{
int start;
int end;
} track_t;
/* CD TOC */
typedef struct
{
int end;
int last;
track_t tracks[CD_MAX_TRACKS];
} toc_t;
/* CDD hardware */
typedef struct
{
uint32 cycles;
uint32 latency;
int loaded;
int index;
int lba;
int scanOffset;
int volume;
int sampleOffset;
int sampleLba;
uint8 status;
toc_t toc;
int16 audio[2];
} cdd_t;
/* Function prototypes */
extern void cdd_init(blip_t* left, blip_t* right);
extern void cdd_reset(void);
extern int cdd_load(const char *key, char *header);
extern void cdd_unload(void);
extern void cdd_read_data(uint8 *dst);
extern void cdd_read_audio(unsigned int samples);
extern void cdd_update(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

View File

@ -10,6 +10,7 @@
"xiosbase": "cpp",
"iosfwd": "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
// 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.
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
// 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 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;
// These 2 should be overwritten in the big loop below.
espec->x = 0;
espec->w = 256;
espec->y = Setting_SlStart;
@ -3104,7 +3103,6 @@ static void MixLayers(void)
#undef YUV888_TO_xxx
}
Ess->w = fx_vce.dot_clock ? HighDotClockWidth : 256;
Ess->x = 0;
// FIXME
if (fx_vce.frame_interlaced)

View File

@ -706,6 +706,90 @@ EXPORT bool Init(int numDisks, const uint8_t *bios)
static int ActiveDisk;
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)
{
for (int i = 0; i < 2; i++)
@ -733,20 +817,10 @@ EXPORT void FrameAdvance(MyFrameInfo &f)
Ess.SoundBuf = f.SoundBuffer;
Emulate(&Ess);
f.Cycles = Ess.MasterCycles;
f.Width = Ess.w;
f.Height = Ess.h;
f.Samples = Ess.SoundBufSize;
f.Lagged = Lagged;
const uint32_t *src = FrameBuffer;
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));
}
Blit(f);
}
EXPORT void GetMemoryAreas(MemoryArea *m)
@ -821,6 +895,8 @@ ECL_SEALED bool Setting_ChromaInterpolate = false;
ECL_SEALED int Setting_PortDevice[2];
ECL_SEALED bool Setting_PixelPro;
struct FrontendSettings
{
int32_t AdpcmEmulateBuggyCodec;
@ -834,13 +910,14 @@ struct FrontendSettings
int32_t CpuEmulation;
int32_t Port1;
int32_t Port2;
int32_t PixelPro;
};
EXPORT void PutSettingsBeforeInit(const FrontendSettings &s)
{
Setting_AdpcmBuggy = s.AdpcmEmulateBuggyCodec;
Setting_AdpcmNoClicks = s.AdpcmSuppressChannelResetClicks;
Setting_HighDotclockWidth = s.HiResEmulation;
Setting_HighDotclockWidth = s.PixelPro ? 1024 : s.HiResEmulation;
Setting_NoSpriteLimit = s.DisableSpriteLimit;
Setting_ChromaInterpolate = s.ChromaInterpolation;
Setting_SlStart = s.ScanlineStart;
@ -849,6 +926,7 @@ EXPORT void PutSettingsBeforeInit(const FrontendSettings &s)
Setting_CpuEmulation = s.CpuEmulation;
Setting_PortDevice[0] = s.Port1;
Setting_PortDevice[1] = s.Port2;
Setting_PixelPro = s.PixelPro;
}
/*MDFNGI EmulatedPCFX =

View File

@ -138,8 +138,11 @@ static const uint8_t *TryLoadBios(const char *name)
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_m = TryLoadBios("32x.m");
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