commit
77c20a6776
|
@ -0,0 +1,156 @@
|
|||
;;NOTE: These hashes were generated using trimmed ROM headers
|
||||
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: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: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: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: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: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
|
||||
md5:408dca9fc40e2b5d805f403fa0509436 Dig Dug A78 PAL=true;board=0
|
||||
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: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
|
||||
md5:fb8d803b328b2e442548f7799cfa9a4a Galaga A78 NTSC=true;board=0
|
||||
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: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: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: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: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: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: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:66ecaafe1b82ae68ffc96267aaf7a4d7 Robotron 2084 A78 NTSC=true;board=0
|
||||
md5:ae85689b21bdf85cb9dc57c3b1fec9db Santa Simon A78 NTSC=true;board=A7848
|
||||
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:a84c1b2300fbfbf21b1c02387f613dad Space Duel A78 PAL=true;board=0
|
||||
md5:771cb4609347657f63e6f0eb26036e35 Space Duel A78 NTSC=true;board=A7832
|
||||
md5:6adf79558a3d7f5beca1bb8d34337417 Space Invaders A78 NTSC=true;board=0
|
||||
md5:cbb0746192540a13b4c7775c7ce2021f Summer Games A78 NTSC=true;board=A78SGR
|
||||
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: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:d7dc17379aa25e5ae3c14b9e780c6f6d Xevious A78 NTSC=true;board=0
|
||||
md5:b1a9f196ce5f47ca8caf8fa7bc4ca46c Xevious A78 PAL=true;board=0
|
||||
md5:ce6fbdc7b037a4efdaf87267f5f292cc b*nQ A78 NTSC=true;board=0
|
|
@ -362,6 +362,35 @@
|
|||
<Compile Include="Consoles\Atari\2600\Tia\Tia.PlayerData.cs" />
|
||||
<Compile Include="Consoles\Atari\2600\Tia\Tia.PlayfieldData.cs" />
|
||||
<Compile Include="Consoles\Atari\2600\Tia\Tia.SyncState.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.IDebuggable.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.IEmulator.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.IInputPollable.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.IMemoryDomains.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.IStatable.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800Hawk.ISaveRam.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\MemoryMap.cs">
|
||||
<DependentUpon>A7800Hawk.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\A7800HawkControl.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\M6532.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\Maria.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\Tia.Audio.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\TIA.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\Tia.ISoundProvider.cs" />
|
||||
<Compile Include="Consoles\Atari\A7800Hawk\TIA_Sound\Tia.SyncState.cs" />
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.cs" />
|
||||
<Compile Include="Consoles\Atari\7800\Atari7800.IDebuggable.cs">
|
||||
<DependentUpon>Atari7800.cs</DependentUpon>
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IDebuggable
|
||||
{
|
||||
public IDictionary<string, RegisterValue> GetCpuFlagsAndRegisters()
|
||||
{
|
||||
return new Dictionary<string, RegisterValue>
|
||||
{
|
||||
["A"] = cpu.A,
|
||||
["X"] = cpu.X,
|
||||
["Y"] = cpu.Y,
|
||||
["S"] = cpu.S,
|
||||
["PC"] = cpu.PC,
|
||||
["Flag C"] = cpu.FlagC,
|
||||
["Flag Z"] = cpu.FlagZ,
|
||||
["Flag I"] = cpu.FlagI,
|
||||
["Flag D"] = cpu.FlagD,
|
||||
["Flag B"] = cpu.FlagB,
|
||||
["Flag V"] = cpu.FlagV,
|
||||
["Flag N"] = cpu.FlagN,
|
||||
["Flag T"] = cpu.FlagT
|
||||
};
|
||||
}
|
||||
|
||||
public void SetCpuRegister(string register, int value)
|
||||
{
|
||||
switch (register)
|
||||
{
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
case "A":
|
||||
cpu.A = (byte)value;
|
||||
break;
|
||||
case "X":
|
||||
cpu.X = (byte)value;
|
||||
break;
|
||||
case "Y":
|
||||
cpu.Y = (byte)value;
|
||||
break;
|
||||
case "S":
|
||||
cpu.S = (byte)value;
|
||||
break;
|
||||
case "PC":
|
||||
cpu.PC = (ushort)value;
|
||||
break;
|
||||
case "Flag I":
|
||||
cpu.FlagI = value > 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public IMemoryCallbackSystem MemoryCallbacks
|
||||
{
|
||||
[FeatureNotImplemented]
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public bool CanStep(StepType type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
[FeatureNotImplemented]
|
||||
public void Step(StepType type)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int TotalExecutedCycles
|
||||
{
|
||||
get { return cpu.TotalExecutedCycles; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IEmulator
|
||||
{
|
||||
public IEmulatorServiceProvider ServiceProvider { get; }
|
||||
|
||||
public ControllerDefinition ControllerDefinition { get; private set; }
|
||||
|
||||
public void FrameAdvance(IController controller, bool render, bool rendersound)
|
||||
{
|
||||
_frame++;
|
||||
|
||||
if (controller.IsPressed("Power"))
|
||||
{
|
||||
// it seems that theMachine.Reset() doesn't clear ram, etc
|
||||
// this should leave hsram intact but clear most other things
|
||||
HardReset();
|
||||
}
|
||||
|
||||
if (_islag)
|
||||
{
|
||||
_lagcount++;
|
||||
}
|
||||
|
||||
maria.FrameAdvance();
|
||||
|
||||
}
|
||||
|
||||
public int Frame => _frame;
|
||||
|
||||
public string SystemId => "A7800";
|
||||
|
||||
public bool DeterministicEmulation { get; set; }
|
||||
|
||||
public void ResetCounters()
|
||||
{
|
||||
_frame = 0;
|
||||
_lagcount = 0;
|
||||
_islag = false;
|
||||
}
|
||||
|
||||
public CoreComm CoreComm { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
maria = null;
|
||||
tia = null;
|
||||
m6532 = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IInputPollable
|
||||
{
|
||||
public int LagCount
|
||||
{
|
||||
get { return _lagcount; }
|
||||
set { _lagcount = value; }
|
||||
}
|
||||
|
||||
public bool IsLagFrame
|
||||
{
|
||||
get { return _islag; }
|
||||
set { _islag = value; }
|
||||
}
|
||||
|
||||
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
|
||||
|
||||
private bool _islag = true;
|
||||
private int _lagcount;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk
|
||||
{
|
||||
private IMemoryDomains MemoryDomains;
|
||||
|
||||
public void SetupMemoryDomains()
|
||||
{
|
||||
var domains = new List<MemoryDomain>
|
||||
{
|
||||
new MemoryDomainDelegate(
|
||||
"Main RAM",
|
||||
RAM.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr],
|
||||
(addr, value) => RAM[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"TIA Registers",
|
||||
TIA_regs.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => TIA_regs[addr],
|
||||
(addr, value) => TIA_regs[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"Maria Registers",
|
||||
Maria_regs.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => Maria_regs[addr],
|
||||
(addr, value) => Maria_regs[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"6532 Registers",
|
||||
regs_6532.Length,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => regs_6532[addr],
|
||||
(addr, value) => regs_6532[addr] = value,
|
||||
1),
|
||||
new MemoryDomainDelegate(
|
||||
"Ram Block 0",
|
||||
0xB,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr-0x840],
|
||||
(addr, value) => RAM[addr-0x840] = value,
|
||||
1
|
||||
),
|
||||
new MemoryDomainDelegate(
|
||||
"Ram Block 1",
|
||||
0xB,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => RAM[addr-0x940],
|
||||
(addr, value) => RAM[addr-0x940] = value,
|
||||
1
|
||||
),
|
||||
new MemoryDomainDelegate(
|
||||
"System Bus",
|
||||
0X10000,
|
||||
MemoryDomain.Endian.Little,
|
||||
addr => PeekSystemBus(addr),
|
||||
(addr, value) => PokeSystemBus(addr, value),
|
||||
1
|
||||
)
|
||||
};
|
||||
|
||||
MemoryDomains = new MemoryDomainList(domains);
|
||||
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
|
||||
}
|
||||
|
||||
private byte PeekSystemBus(long addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void PokeSystemBus(long addr, byte value)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : ISaveRam
|
||||
{
|
||||
public byte[] CloneSaveRam()
|
||||
{
|
||||
return (byte[])_hsram.Clone();
|
||||
}
|
||||
|
||||
public void StoreSaveRam(byte[] data)
|
||||
{
|
||||
Buffer.BlockCopy(data, 0, _hsram, 0, data.Length);
|
||||
}
|
||||
|
||||
public bool SaveRamModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
using System.IO;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk : IStatable
|
||||
{
|
||||
public bool BinarySaveStatesPreferred => true;
|
||||
|
||||
public void SaveStateText(TextWriter writer)
|
||||
{
|
||||
SyncState(new Serializer(writer));
|
||||
}
|
||||
|
||||
public void LoadStateText(TextReader reader)
|
||||
{
|
||||
SyncState(new Serializer(reader));
|
||||
}
|
||||
|
||||
public void SaveStateBinary(BinaryWriter bw)
|
||||
{
|
||||
SyncState(new Serializer(bw));
|
||||
}
|
||||
|
||||
public void LoadStateBinary(BinaryReader br)
|
||||
{
|
||||
SyncState(new Serializer(br));
|
||||
}
|
||||
|
||||
public byte[] SaveStateBinary()
|
||||
{
|
||||
MemoryStream ms = new MemoryStream();
|
||||
BinaryWriter bw = new BinaryWriter(ms);
|
||||
SaveStateBinary(bw);
|
||||
bw.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
private void SyncState(Serializer ser)
|
||||
{
|
||||
byte[] core = null;
|
||||
if (ser.IsWriter)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
ms.Close();
|
||||
core = ms.ToArray();
|
||||
}
|
||||
|
||||
ser.BeginSection("Atari7800");
|
||||
ser.Sync("core", ref core, false);
|
||||
ser.Sync("Lag", ref _lagcount);
|
||||
ser.Sync("Frame", ref _frame);
|
||||
ser.Sync("IsLag", ref _islag);
|
||||
ser.EndSection();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,307 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.M6502;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
[CoreAttributes(
|
||||
"A7800Hawk",
|
||||
"",
|
||||
isPorted: false,
|
||||
isReleased: true)]
|
||||
[ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))]
|
||||
public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable
|
||||
{
|
||||
// this register selects between 2600 and 7800 mode in the A7800
|
||||
// however, we already have a 2600 emulator so this core will only be loading A7800 games
|
||||
// furthermore, the location of the register is in the same place as TIA registers (0x0-0x1F)
|
||||
// any writes to this location before the register is 'locked' will go to the register and not the TIA
|
||||
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[] regs_6532 = new byte[0x80];
|
||||
|
||||
private readonly byte[] _rom;
|
||||
private readonly byte[] _hsbios;
|
||||
private readonly byte[] _bios;
|
||||
private readonly byte[] _hsram = new byte[2048];
|
||||
|
||||
private int _frame = 0;
|
||||
|
||||
public MOS6502X cpu;
|
||||
public Maria maria;
|
||||
private bool _isPAL;
|
||||
public M6532 m6532;
|
||||
public TIA tia;
|
||||
|
||||
public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn)
|
||||
{
|
||||
var ser = new BasicServiceProvider(this);
|
||||
ser.Register<IVideoProvider>(maria);
|
||||
ser.Register<ISoundProvider>(tia);
|
||||
ServiceProvider = ser;
|
||||
|
||||
CoreComm = comm;
|
||||
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.");
|
||||
|
||||
if (rom.Length % 1024 == 128)
|
||||
{
|
||||
Console.WriteLine("Trimming 128 byte .a78 header...");
|
||||
byte[] newrom = new byte[rom.Length - 128];
|
||||
Buffer.BlockCopy(rom, 128, newrom, 0, newrom.Length);
|
||||
rom = newrom;
|
||||
}
|
||||
|
||||
_isPAL = false;
|
||||
|
||||
// look up hash in gamedb to see what mapper to use
|
||||
// if none found default is zero
|
||||
// also check for PAL region
|
||||
string hash_md5 = null;
|
||||
string s_mapper = null;
|
||||
hash_md5 = "md5:" + rom.HashMD5(0, rom.Length);
|
||||
|
||||
var gi = Database.CheckDatabase(hash_md5);
|
||||
|
||||
if (gi != null)
|
||||
{
|
||||
var dict = gi.GetOptionsDict();
|
||||
if (!dict.ContainsKey("PAL"))
|
||||
{
|
||||
_isPAL = true;
|
||||
}
|
||||
if (!dict.ContainsKey("board"))
|
||||
{
|
||||
s_mapper = dict["board"];
|
||||
}
|
||||
else
|
||||
throw new Exception("No Board selected for this mapper");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("ROM not in gamedb");
|
||||
}
|
||||
|
||||
_rom = rom;
|
||||
_hsbios = highscoreBios;
|
||||
_bios = _isPAL ? palBios : ntscBios;
|
||||
|
||||
if (_bios == null)
|
||||
{
|
||||
throw new MissingFirmwareException("The BIOS corresponding to the region of the game you loaded is required to run Atari 7800 games.");
|
||||
}
|
||||
|
||||
// set up palette and frame rate
|
||||
if (_isPAL)
|
||||
{
|
||||
maria._frameHz = 50;
|
||||
maria._palette = PALPalette;
|
||||
}
|
||||
else
|
||||
{
|
||||
maria._frameHz = 60;
|
||||
maria._palette = NTSCPalette;
|
||||
}
|
||||
|
||||
|
||||
HardReset();
|
||||
}
|
||||
|
||||
public DisplayType Region => _isPAL ? DisplayType.PAL : DisplayType.NTSC;
|
||||
|
||||
public A7800HawkControl ControlAdapter { get; private set; }
|
||||
|
||||
private void HardReset()
|
||||
{
|
||||
A7800_control_register = 0;
|
||||
|
||||
tia.Reset();
|
||||
cpu.Reset();
|
||||
maria.Reset();
|
||||
m6532 = new M6532();
|
||||
}
|
||||
|
||||
/*
|
||||
* MariaTables.cs
|
||||
*
|
||||
* Palette tables for the Maria class.
|
||||
* All derived from Dan Boris' 7800/MAME code.
|
||||
*
|
||||
* Copyright © 2004 Mike Murphy
|
||||
*
|
||||
*/
|
||||
|
||||
public static readonly int[] NTSCPalette =
|
||||
{
|
||||
0x000000, 0x1c1c1c, 0x393939, 0x595959, // Grey
|
||||
0x797979, 0x929292, 0xababab, 0xbcbcbc,
|
||||
0xcdcdcd, 0xd9d9d9, 0xe6e6e6, 0xececec,
|
||||
0xf2f2f2, 0xf8f8f8, 0xffffff, 0xffffff,
|
||||
|
||||
0x391701, 0x5e2304, 0x833008, 0xa54716, // Gold
|
||||
0xc85f24, 0xe37820, 0xff911d, 0xffab1d,
|
||||
0xffc51d, 0xffce34, 0xffd84c, 0xffe651,
|
||||
0xfff456, 0xfff977, 0xffff98, 0xffff98,
|
||||
|
||||
0x451904, 0x721e11, 0x9f241e, 0xb33a20, // Orange
|
||||
0xc85122, 0xe36920, 0xff811e, 0xff8c25,
|
||||
0xff982c, 0xffae38, 0xffc545, 0xffc559,
|
||||
0xffc66d, 0xffd587, 0xffe4a1, 0xffe4a1,
|
||||
|
||||
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119, // Red Orange
|
||||
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
|
||||
0xff706e, 0xff7f7e, 0xff8f8f, 0xff9d9e,
|
||||
0xffabad, 0xffb9bd, 0xffc7ce, 0xffc7ce,
|
||||
|
||||
0x050568, 0x3b136d, 0x712272, 0x8b2a8c, // Pink
|
||||
0xa532a6, 0xb938ba, 0xcd3ecf, 0xdb47dd,
|
||||
0xea51eb, 0xf45ff5, 0xfe6dff, 0xfe7afd,
|
||||
0xff87fb, 0xff95fd, 0xffa4ff, 0xffa4ff,
|
||||
|
||||
0x280479, 0x400984, 0x590f90, 0x70249d, // Purple
|
||||
0x8839aa, 0xa441c3, 0xc04adc, 0xd054ed,
|
||||
0xe05eff, 0xe96dff, 0xf27cff, 0xf88aff,
|
||||
0xff98ff, 0xfea1ff, 0xfeabff, 0xfeabff,
|
||||
|
||||
0x35088a, 0x420aad, 0x500cd0, 0x6428d0, // Purple Blue
|
||||
0x7945d0, 0x8d4bd4, 0xa251d9, 0xb058ec,
|
||||
0xbe60ff, 0xc56bff, 0xcc77ff, 0xd183ff,
|
||||
0xd790ff, 0xdb9dff, 0xdfaaff, 0xdfaaff,
|
||||
|
||||
0x051e81, 0x0626a5, 0x082fca, 0x263dd4, // Blue1
|
||||
0x444cde, 0x4f5aee, 0x5a68ff, 0x6575ff,
|
||||
0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff,
|
||||
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xc0cbff,
|
||||
|
||||
0x0c048b, 0x2218a0, 0x382db5, 0x483ec7, // Blue2
|
||||
0x584fda, 0x6159ec, 0x6b64ff, 0x7a74ff,
|
||||
0x8a84ff, 0x918eff, 0x9998ff, 0xa5a3ff,
|
||||
0xb1aeff, 0xb8b8ff, 0xc0c2ff, 0xc0c2ff,
|
||||
|
||||
0x1d295a, 0x1d3876, 0x1d4892, 0x1c5cac, // Light Blue
|
||||
0x1c71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
|
||||
0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff,
|
||||
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xc3e9ff,
|
||||
|
||||
0x2f4302, 0x395202, 0x446103, 0x417a12, // Turquoise
|
||||
0x3e9421, 0x4a9f2e, 0x57ab3b, 0x5cbd55,
|
||||
0x61d070, 0x69e27a, 0x72f584, 0x7cfa8d,
|
||||
0x87ff97, 0x9affa6, 0xadffb6, 0xadffb6,
|
||||
|
||||
0x0a4108, 0x0d540a, 0x10680d, 0x137d0f, // Green Blue
|
||||
0x169212, 0x19a514, 0x1cb917, 0x1ec919,
|
||||
0x21d91b, 0x47e42d, 0x6ef040, 0x78f74d,
|
||||
0x83ff5b, 0x9aff7a, 0xb2ff9a, 0xb2ff9a,
|
||||
|
||||
0x04410b, 0x05530e, 0x066611, 0x077714, // Green
|
||||
0x088817, 0x099b1a, 0x0baf1d, 0x48c41f,
|
||||
0x86d922, 0x8fe924, 0x99f927, 0xa8fc41,
|
||||
0xb7ff5b, 0xc9ff6e, 0xdcff81, 0xdcff81,
|
||||
|
||||
0x02350f, 0x073f15, 0x0c4a1c, 0x2d5f1e, // Yellow Green
|
||||
0x4f7420, 0x598324, 0x649228, 0x82a12e,
|
||||
0xa1b034, 0xa9c13a, 0xb2d241, 0xc4d945,
|
||||
0xd6e149, 0xe4f04e, 0xf2ff53, 0xf2ff53,
|
||||
|
||||
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
|
||||
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
|
||||
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
|
||||
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
|
||||
|
||||
0x401a02, 0x581f05, 0x702408, 0x8d3a13, // Light Orange
|
||||
0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
|
||||
0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c,
|
||||
0xffc160, 0xffc671, 0xffcb83, 0xffcb83
|
||||
};
|
||||
|
||||
public static readonly int[] PALPalette =
|
||||
{
|
||||
0x000000, 0x1c1c1c, 0x393939, 0x595959, // Grey
|
||||
0x797979, 0x929292, 0xababab, 0xbcbcbc,
|
||||
0xcdcdcd, 0xd9d9d9, 0xe6e6e6, 0xececec,
|
||||
0xf2f2f2, 0xf8f8f8, 0xffffff, 0xffffff,
|
||||
|
||||
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
|
||||
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
|
||||
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
|
||||
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
|
||||
|
||||
0x263001, 0x243803, 0x234005, 0x51541b, // Orange Green
|
||||
0x806931, 0x978135, 0xaf993a, 0xc2a73e,
|
||||
0xd5b543, 0xdbc03d, 0xe1cb38, 0xe2d836,
|
||||
0xe3e534, 0xeff258, 0xfbff7d, 0xfbff7d,
|
||||
|
||||
0x401a02, 0x581f05, 0x702408, 0x8d3a13, // Light Orange
|
||||
0xab511f, 0xb56427, 0xbf7730, 0xd0853a,
|
||||
0xe19344, 0xeda04e, 0xf9ad58, 0xfcb75c,
|
||||
0xffc160, 0xffc671, 0xffcb83, 0xffcb83,
|
||||
|
||||
0x391701, 0x5e2304, 0x833008, 0xa54716, // Gold
|
||||
0xc85f24, 0xe37820, 0xff911d, 0xffab1d,
|
||||
0xffc51d, 0xffce34, 0xffd84c, 0xffe651,
|
||||
0xfff456, 0xfff977, 0xffff98, 0xffff98,
|
||||
|
||||
0x451904, 0x721e11, 0x9f241e, 0xb33a20, // Orange
|
||||
0xc85122, 0xe36920, 0xff811e, 0xff8c25,
|
||||
0xff982c, 0xffae38, 0xffc545, 0xffc559,
|
||||
0xffc66d, 0xffd587, 0xffe4a1, 0xffe4a1,
|
||||
|
||||
0x4a1704, 0x7e1a0d, 0xb21d17, 0xc82119, // Red Orange
|
||||
0xdf251c, 0xec3b38, 0xfa5255, 0xfc6161,
|
||||
0xff706e, 0xff7f7e, 0xff8f8f, 0xff9d9e,
|
||||
0xffabad, 0xffb9bd, 0xffc7ce, 0xffc7ce,
|
||||
|
||||
0x050568, 0x3b136d, 0x712272, 0x8b2a8c, // Pink
|
||||
0xa532a6, 0xb938ba, 0xcd3ecf, 0xdb47dd,
|
||||
0xea51eb, 0xf45ff5, 0xfe6dff, 0xfe7afd,
|
||||
0xff87fb, 0xff95fd, 0xffa4ff, 0xffa4ff,
|
||||
|
||||
0x280479, 0x400984, 0x590f90, 0x70249d, // Purple
|
||||
0x8839aa, 0xa441c3, 0xc04adc, 0xd054ed,
|
||||
0xe05eff, 0xe96dff, 0xf27cff, 0xf88aff,
|
||||
0xff98ff, 0xfea1ff, 0xfeabff, 0xfeabff,
|
||||
|
||||
0x051e81, 0x0626a5, 0x082fca, 0x263dd4, // Blue1
|
||||
0x444cde, 0x4f5aee, 0x5a68ff, 0x6575ff,
|
||||
0x7183ff, 0x8091ff, 0x90a0ff, 0x97a9ff,
|
||||
0x9fb2ff, 0xafbeff, 0xc0cbff, 0xc0cbff,
|
||||
|
||||
0x0c048b, 0x2218a0, 0x382db5, 0x483ec7, // Blue2
|
||||
0x584fda, 0x6159ec, 0x6b64ff, 0x7a74ff,
|
||||
0x8a84ff, 0x918eff, 0x9998ff, 0xa5a3ff,
|
||||
0xb1aeff, 0xb8b8ff, 0xc0c2ff, 0xc0c2ff,
|
||||
|
||||
0x1d295a, 0x1d3876, 0x1d4892, 0x1c5cac, // Light Blue
|
||||
0x1c71c6, 0x3286cf, 0x489bd9, 0x4ea8ec,
|
||||
0x55b6ff, 0x70c7ff, 0x8cd8ff, 0x93dbff,
|
||||
0x9bdfff, 0xafe4ff, 0xc3e9ff, 0xc3e9ff,
|
||||
|
||||
0x2f4302, 0x395202, 0x446103, 0x417a12, // Turquoise
|
||||
0x3e9421, 0x4a9f2e, 0x57ab3b, 0x5cbd55,
|
||||
0x61d070, 0x69e27a, 0x72f584, 0x7cfa8d,
|
||||
0x87ff97, 0x9affa6, 0xadffb6, 0xadffb6,
|
||||
|
||||
0x0a4108, 0x0d540a, 0x10680d, 0x137d0f, // Green Blue
|
||||
0x169212, 0x19a514, 0x1cb917, 0x1ec919,
|
||||
0x21d91b, 0x47e42d, 0x6ef040, 0x78f74d,
|
||||
0x83ff5b, 0x9aff7a, 0xb2ff9a, 0xb2ff9a,
|
||||
|
||||
0x04410b, 0x05530e, 0x066611, 0x077714, // Green
|
||||
0x088817, 0x099b1a, 0x0baf1d, 0x48c41f,
|
||||
0x86d922, 0x8fe924, 0x99f927, 0xa8fc41,
|
||||
0xb7ff5b, 0xc9ff6e, 0xdcff81, 0xdcff81,
|
||||
|
||||
0x02350f, 0x073f15, 0x0c4a1c, 0x2d5f1e, // Yellow Green
|
||||
0x4f7420, 0x598324, 0x649228, 0x82a12e,
|
||||
0xa1b034, 0xa9c13a, 0xb2d241, 0xc4d945,
|
||||
0xd6e149, 0xe4f04e, 0xf2ff53, 0xf2ff53
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,409 @@
|
|||
using System;
|
||||
|
||||
using EMU7800.Core;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public class A7800HawkControl
|
||||
{
|
||||
private static readonly ControllerDefinition Joystick = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Joystick Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Paddles = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Paddle Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger",
|
||||
"P3 Trigger",
|
||||
"P4 Trigger"
|
||||
},
|
||||
FloatControls = // should be in [0..700000]
|
||||
{
|
||||
"P1 Paddle",
|
||||
"P2 Paddle",
|
||||
"P3 Paddle",
|
||||
"P4 Paddle"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
// what is the center point supposed to be here?
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f },
|
||||
new[] { 0.0f, 0.0f, 700000.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Keypad = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Keypad Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Keypad1", "P1 Keypad2", "P1 Keypad3",
|
||||
"P1 Keypad4", "P1 Keypad5", "P1 Keypad6",
|
||||
"P1 Keypad7", "P1 Keypad8", "P1 Keypad9",
|
||||
"P1 KeypadA", "P1 Keypad0", "P1 KeypadP",
|
||||
"P2 Keypad1", "P2 Keypad2", "P2 Keypad3",
|
||||
"P2 Keypad4", "P2 Keypad5", "P2 Keypad6",
|
||||
"P2 Keypad7", "P2 Keypad8", "P2 Keypad9",
|
||||
"P2 KeypadA", "P2 Keypad0", "P2 KeypadP",
|
||||
"P3 Keypad1", "P3 Keypad2", "P3 Keypad3",
|
||||
"P3 Keypad4", "P3 Keypad5", "P3 Keypad6",
|
||||
"P3 Keypad7", "P3 Keypad8", "P3 Keypad9",
|
||||
"P3 KeypadA", "P3 Keypad0", "P3 KeypadP",
|
||||
"P4 Keypad1", "P4 Keypad2", "P4 Keypad3",
|
||||
"P4 Keypad4", "P4 Keypad5", "P4 Keypad6",
|
||||
"P4 Keypad7", "P4 Keypad8", "P4 Keypad9",
|
||||
"P4 KeypadA", "P4 Keypad0", "P4 KeypadP"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Driving = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Driving Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger"
|
||||
},
|
||||
FloatControls = // should be in [0..3]
|
||||
{
|
||||
"P1 Driving",
|
||||
"P2 Driving"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
new[] { 0.0f, 0.0f, 3.0f },
|
||||
new[] { 0.0f, 0.0f, 3.0f },
|
||||
new[] { 0.0f, 0.0f, 3.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition BoosterGrip = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Booster Grip Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"BW", // should be "Color"??
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
// NB: as referenced by the emu, p1t2 = p1t2, p1t3 = p2t2, p2t2 = p3t2, p2t3 = p4t2
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger", "P1 Trigger 2", "P1 Trigger 3",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger", "P2 Trigger 2", "P2 Trigger 3"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition ProLineJoystick = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 ProLine Joystick Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"Pause",
|
||||
"Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Toggle Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 Trigger", "P1 Trigger 2",
|
||||
"P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 Trigger", "P2 Trigger 2"
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly ControllerDefinition Lightgun = new ControllerDefinition
|
||||
{
|
||||
Name = "Atari 7800 Light Gun Controller",
|
||||
BoolButtons =
|
||||
{
|
||||
// hard reset, not passed to EMU7800
|
||||
"Power",
|
||||
|
||||
// on the console
|
||||
"Reset",
|
||||
"Select",
|
||||
"Pause",
|
||||
"Left Difficulty", // better not put P# on these as they might not correspond to player numbers
|
||||
"Right Difficulty",
|
||||
|
||||
// ports
|
||||
"P1 Trigger",
|
||||
"P2 Trigger"
|
||||
},
|
||||
FloatControls = // vpos should be actual scanline number. hpos should be in [0..319]??
|
||||
{
|
||||
"P1 VPos", "P1 HPos",
|
||||
"P2 VPos", "P2 HPos"
|
||||
},
|
||||
FloatRanges =
|
||||
{
|
||||
// how many scanlines are there again??
|
||||
new[] { 0.0f, 0.0f, 240.0f },
|
||||
new[] { 0.0f, 0.0f, 319.0f },
|
||||
new[] { 0.0f, 0.0f, 240.0f },
|
||||
new[] { 0.0f, 0.0f, 319.0f }
|
||||
}
|
||||
};
|
||||
|
||||
private struct ControlAdapter
|
||||
{
|
||||
public readonly ControllerDefinition Type;
|
||||
public readonly Controller Left;
|
||||
public readonly Controller Right;
|
||||
public readonly Action<IController, InputState> Convert;
|
||||
|
||||
public ControlAdapter(ControllerDefinition type, Controller left, Controller right, Action<IController, InputState> convert)
|
||||
{
|
||||
Type = type;
|
||||
Left = left;
|
||||
Right = right;
|
||||
Convert = convert;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ControlAdapter[] Adapters =
|
||||
{
|
||||
new ControlAdapter(Joystick, Controller.Joystick, Controller.Joystick, ConvertJoystick),
|
||||
new ControlAdapter(Paddles, Controller.Paddles, Controller.Paddles, ConvertPaddles),
|
||||
new ControlAdapter(Keypad, Controller.Keypad, Controller.Keypad, ConvertKeypad),
|
||||
new ControlAdapter(Driving, Controller.Driving, Controller.Driving, ConvertDriving),
|
||||
new ControlAdapter(BoosterGrip, Controller.BoosterGrip, Controller.BoosterGrip, ConvertBoosterGrip),
|
||||
new ControlAdapter(ProLineJoystick, Controller.ProLineJoystick, Controller.ProLineJoystick, ConvertProLineJoystick),
|
||||
new ControlAdapter(Lightgun, Controller.Lightgun, Controller.Lightgun, ConvertLightgun),
|
||||
};
|
||||
|
||||
private static void ConvertConsoleButtons(IController c, InputState s)
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.Reset, c.IsPressed("Reset"));
|
||||
s.RaiseInput(0, MachineInput.Select, c.IsPressed("Select"));
|
||||
s.RaiseInput(0, MachineInput.Color, c.IsPressed("BW"));
|
||||
if (c.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.LeftDifficulty, c.IsPressed("Toggle Left Difficulty"));
|
||||
}
|
||||
|
||||
if (c.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.RightDifficulty, c.IsPressed("Toggle Right Difficulty"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertConsoleButtons7800(IController c, InputState s)
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.Reset, c.IsPressed("Reset"));
|
||||
s.RaiseInput(0, MachineInput.Select, c.IsPressed("Select"));
|
||||
s.RaiseInput(0, MachineInput.Color, c.IsPressed("Pause"));
|
||||
if (c.IsPressed("Toggle Left Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.LeftDifficulty, c.IsPressed("Toggle Left Difficulty"));
|
||||
}
|
||||
|
||||
if (c.IsPressed("Toggle Right Difficulty"))
|
||||
{
|
||||
s.RaiseInput(0, MachineInput.RightDifficulty, c.IsPressed("Toggle Right Difficulty"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertDirections(IController c, InputState s, int p)
|
||||
{
|
||||
string ps = $"P{p + 1} ";
|
||||
s.RaiseInput(p, MachineInput.Up, c.IsPressed(ps + "Up"));
|
||||
s.RaiseInput(p, MachineInput.Down, c.IsPressed(ps + "Down"));
|
||||
s.RaiseInput(p, MachineInput.Left, c.IsPressed(ps + "Left"));
|
||||
s.RaiseInput(p, MachineInput.Right, c.IsPressed(ps + "Right"));
|
||||
}
|
||||
|
||||
private static void ConvertTrigger(IController c, InputState s, int p)
|
||||
{
|
||||
string ps = $"P{p + 1} ";
|
||||
s.RaiseInput(p, MachineInput.Fire, c.IsPressed(ps + "Trigger"));
|
||||
}
|
||||
|
||||
private static void ConvertJoystick(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
}
|
||||
|
||||
private static void ConvertPaddles(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
string ps = $"P{i + 1} ";
|
||||
ConvertTrigger(c, s, i);
|
||||
s.RaisePaddleInput(i, 700000, (int)c.GetFloat(ps + "Trigger"));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConvertKeypad(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
string ps = $"P{i + 1} ";
|
||||
s.RaiseInput(i, MachineInput.NumPad1, c.IsPressed(ps + "Keypad1"));
|
||||
s.RaiseInput(i, MachineInput.NumPad2, c.IsPressed(ps + "Keypad2"));
|
||||
s.RaiseInput(i, MachineInput.NumPad3, c.IsPressed(ps + "Keypad3"));
|
||||
s.RaiseInput(i, MachineInput.NumPad4, c.IsPressed(ps + "Keypad4"));
|
||||
s.RaiseInput(i, MachineInput.NumPad5, c.IsPressed(ps + "Keypad5"));
|
||||
s.RaiseInput(i, MachineInput.NumPad6, c.IsPressed(ps + "Keypad6"));
|
||||
s.RaiseInput(i, MachineInput.NumPad7, c.IsPressed(ps + "Keypad7"));
|
||||
s.RaiseInput(i, MachineInput.NumPad8, c.IsPressed(ps + "Keypad8"));
|
||||
s.RaiseInput(i, MachineInput.NumPad9, c.IsPressed(ps + "Keypad9"));
|
||||
s.RaiseInput(i, MachineInput.NumPadMult, c.IsPressed(ps + "KeypadA"));
|
||||
s.RaiseInput(i, MachineInput.NumPad0, c.IsPressed(ps + "Keypad0"));
|
||||
s.RaiseInput(i, MachineInput.NumPadHash, c.IsPressed(ps + "KeypadP"));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly MachineInput[] Drvlut =
|
||||
{
|
||||
MachineInput.Driving0,
|
||||
MachineInput.Driving1,
|
||||
MachineInput.Driving2,
|
||||
MachineInput.Driving3
|
||||
};
|
||||
|
||||
private static void ConvertDriving(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
s.RaiseInput(0, Drvlut[(int)c.GetFloat("P1 Driving")], true);
|
||||
s.RaiseInput(1, Drvlut[(int)c.GetFloat("P2 Driving")], true);
|
||||
}
|
||||
|
||||
private static void ConvertBoosterGrip(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
|
||||
// weird mapping is intentional
|
||||
s.RaiseInput(0, MachineInput.Fire, c.IsPressed("P1 Trigger"));
|
||||
s.RaiseInput(0, MachineInput.Fire2, c.IsPressed("P1 Trigger 2"));
|
||||
s.RaiseInput(1, MachineInput.Fire2, c.IsPressed("P1 Trigger 3"));
|
||||
s.RaiseInput(1, MachineInput.Fire, c.IsPressed("P2 Trigger"));
|
||||
s.RaiseInput(2, MachineInput.Fire2, c.IsPressed("P2 Trigger 2"));
|
||||
s.RaiseInput(3, MachineInput.Fire2, c.IsPressed("P2 Trigger 3"));
|
||||
}
|
||||
|
||||
private static void ConvertProLineJoystick(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons7800(c, s);
|
||||
ConvertDirections(c, s, 0);
|
||||
ConvertDirections(c, s, 1);
|
||||
s.RaiseInput(0, MachineInput.Fire, c.IsPressed("P1 Trigger"));
|
||||
s.RaiseInput(0, MachineInput.Fire2, c.IsPressed("P1 Trigger 2"));
|
||||
s.RaiseInput(1, MachineInput.Fire, c.IsPressed("P2 Trigger"));
|
||||
s.RaiseInput(1, MachineInput.Fire2, c.IsPressed("P2 Trigger 2"));
|
||||
}
|
||||
|
||||
private static void ConvertLightgun(IController c, InputState s)
|
||||
{
|
||||
s.ClearControllerInput();
|
||||
ConvertConsoleButtons7800(c, s);
|
||||
ConvertTrigger(c, s, 0);
|
||||
ConvertTrigger(c, s, 1);
|
||||
s.RaiseLightgunPos(0, (int)c.GetFloat("P1 VPos"), (int)c.GetFloat("P1 HPos"));
|
||||
s.RaiseLightgunPos(1, (int)c.GetFloat("P2 VPos"), (int)c.GetFloat("P2 HPos"));
|
||||
}
|
||||
|
||||
public Action<IController, InputState> Convert { get; private set; }
|
||||
|
||||
public ControllerDefinition ControlType { get; private set; }
|
||||
|
||||
public A7800HawkControl(MachineBase mac)
|
||||
{
|
||||
var l = mac.InputState.LeftControllerJack;
|
||||
var r = mac.InputState.RightControllerJack;
|
||||
|
||||
foreach (var a in Adapters)
|
||||
{
|
||||
if (a.Left == l && a.Right == r)
|
||||
{
|
||||
Convert = a.Convert;
|
||||
ControlType = a.Type;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Couldn't connect Atari 7800 controls \"{l}\" and \"{r}\"");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// Emulates the M6532 RIOT Chip
|
||||
public class M6532
|
||||
{
|
||||
private byte _ddRa = 0x00;
|
||||
private byte _ddRb = 0x00;
|
||||
private byte _outputA = 0x00;
|
||||
|
||||
public TimerData Timer;
|
||||
|
||||
public M6532()
|
||||
{
|
||||
|
||||
// arbitrary value to start with.
|
||||
Timer.Value = 0x73;
|
||||
Timer.PrescalerShift = 10;
|
||||
Timer.PrescalerCount = 1 << Timer.PrescalerShift;
|
||||
}
|
||||
|
||||
public byte ReadMemory(ushort addr, bool peek)
|
||||
{
|
||||
if ((addr & 0x0200) == 0) // If not register select, read Ram
|
||||
{
|
||||
//return _core.Ram[(ushort)(addr & 0x007f)];
|
||||
return 0;
|
||||
}
|
||||
|
||||
var registerAddr = (ushort)(addr & 0x0007);
|
||||
if (registerAddr == 0x00)
|
||||
{
|
||||
// Read Output reg A
|
||||
// Combine readings from player 1 and player 2
|
||||
// actually depends on setting in SWCHCNTA (aka DDRa)
|
||||
byte temp = 0;// (byte)(_core.ReadControls1(peek) & 0xF0 | ((_core.ReadControls2(peek) >> 4) & 0x0F));
|
||||
temp = (byte)(temp & ~_ddRa);
|
||||
temp = (byte)(temp + (_outputA & _ddRa));
|
||||
return temp;
|
||||
}
|
||||
|
||||
if (registerAddr == 0x01)
|
||||
{
|
||||
// Read DDRA
|
||||
return _ddRa;
|
||||
}
|
||||
|
||||
if (registerAddr == 0x02)
|
||||
{
|
||||
// Read Output reg B
|
||||
byte temp = 0;// _core.ReadConsoleSwitches(peek);
|
||||
temp = (byte)(temp & ~_ddRb);
|
||||
return temp;
|
||||
}
|
||||
|
||||
if (registerAddr == 0x03) // Read DDRB
|
||||
{
|
||||
return _ddRb;
|
||||
}
|
||||
|
||||
if ((registerAddr & 0x5) == 0x4)
|
||||
{
|
||||
// Bit 0x0080 contains interrupt enable/disable
|
||||
Timer.InterruptEnabled = (addr & 0x0080) != 0;
|
||||
|
||||
// The interrupt flag will be reset whenever the Timer is access by a read or a write
|
||||
// However, the reading of the timer at the same time the interrupt occurs will not reset the interrupt flag
|
||||
// (M6532 Datasheet)
|
||||
if (!(Timer.PrescalerCount == 0 && Timer.Value == 0))
|
||||
{
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
|
||||
return Timer.Value;
|
||||
}
|
||||
|
||||
// TODO: fix this to match real behaviour
|
||||
// This is an undocumented instruction whose behaviour is more dynamic then indicated here
|
||||
if ((registerAddr & 0x5) == 0x5)
|
||||
{
|
||||
// Read interrupt flag
|
||||
if (Timer.InterruptFlag) // Timer.InterruptEnabled && )
|
||||
{
|
||||
return 0xC0;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
return 0x3A;
|
||||
}
|
||||
|
||||
public void WriteMemory(ushort addr, byte value)
|
||||
{
|
||||
if ((addr & 0x0200) == 0) // If the RS bit is not set, this is a ram write
|
||||
{
|
||||
//_core.Ram[(ushort)(addr & 0x007f)] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If bit 0x0010 is set, and bit 0x0004 is set, this is a timer write
|
||||
if ((addr & 0x0014) == 0x0014)
|
||||
{
|
||||
var registerAddr = (ushort)(addr & 0x0007);
|
||||
|
||||
// Bit 0x0080 contains interrupt enable/disable
|
||||
Timer.InterruptEnabled = (addr & 0x0080) != 0;
|
||||
|
||||
// The interrupt flag will be reset whenever the Timer is access by a read or a write
|
||||
// (M6532 datasheet)
|
||||
if (registerAddr == 0x04)
|
||||
{
|
||||
// Write to Timer/1
|
||||
Timer.PrescalerShift = 0;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
else if (registerAddr == 0x05)
|
||||
{
|
||||
// Write to Timer/8
|
||||
Timer.PrescalerShift = 3;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
else if (registerAddr == 0x06)
|
||||
{
|
||||
// Write to Timer/64
|
||||
Timer.PrescalerShift = 6;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
else if (registerAddr == 0x07)
|
||||
{
|
||||
// Write to Timer/1024
|
||||
Timer.PrescalerShift = 10;
|
||||
Timer.Value = value;
|
||||
Timer.PrescalerCount = 0; // 1 << Timer.PrescalerShift;
|
||||
Timer.InterruptFlag = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If bit 0x0004 is not set, bit 0x0010 is ignored and
|
||||
// these are register writes
|
||||
else if ((addr & 0x0004) == 0)
|
||||
{
|
||||
var registerAddr = (ushort)(addr & 0x0007);
|
||||
|
||||
if (registerAddr == 0x00)
|
||||
{
|
||||
// Write Output reg A
|
||||
_outputA = value;
|
||||
}
|
||||
else if (registerAddr == 0x01)
|
||||
{
|
||||
// Write DDRA
|
||||
_ddRa = value;
|
||||
}
|
||||
else if (registerAddr == 0x02)
|
||||
{
|
||||
// Write Output reg B
|
||||
// But is read only
|
||||
}
|
||||
else if (registerAddr == 0x03)
|
||||
{
|
||||
// Write DDRB
|
||||
_ddRb = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("M6532");
|
||||
ser.Sync("ddra", ref _ddRa);
|
||||
ser.Sync("ddrb", ref _ddRb);
|
||||
ser.Sync("OutputA", ref _outputA);
|
||||
Timer.SyncState(ser);
|
||||
ser.EndSection();
|
||||
}
|
||||
|
||||
public struct TimerData
|
||||
{
|
||||
public int PrescalerCount;
|
||||
public byte PrescalerShift;
|
||||
|
||||
public byte Value;
|
||||
|
||||
public bool InterruptEnabled;
|
||||
public bool InterruptFlag;
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
if (PrescalerCount == 0)
|
||||
{
|
||||
Value--;
|
||||
PrescalerCount = 1 << PrescalerShift;
|
||||
}
|
||||
|
||||
PrescalerCount--;
|
||||
if (PrescalerCount == 0)
|
||||
{
|
||||
if (Value == 0)
|
||||
{
|
||||
InterruptFlag = true;
|
||||
PrescalerShift = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("prescalerCount", ref PrescalerCount);
|
||||
ser.Sync("prescalerShift", ref PrescalerShift);
|
||||
ser.Sync("value", ref Value);
|
||||
ser.Sync("interruptEnabled", ref InterruptEnabled);
|
||||
ser.Sync("interruptFlag", ref InterruptFlag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// Emulates the Atari 7800 Maria graphics chip
|
||||
public class Maria : IVideoProvider
|
||||
{
|
||||
public int _frameHz;
|
||||
|
||||
public int[] _vidbuffer;
|
||||
public int[] _palette;
|
||||
|
||||
public int[] GetVideoBuffer()
|
||||
{
|
||||
return _vidbuffer;
|
||||
}
|
||||
|
||||
public int VirtualWidth => 275;
|
||||
public int VirtualHeight => BufferHeight;
|
||||
public int BufferWidth { get; private set; }
|
||||
public int BufferHeight { get; private set; }
|
||||
public int BackgroundColor => unchecked((int)0xff000000);
|
||||
public int VsyncNumerator => _frameHz;
|
||||
public int VsyncDenominator => 1;
|
||||
|
||||
//Maria related variables
|
||||
public int cycle;
|
||||
|
||||
public void FrameAdvance()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
cycle = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Components.M6502;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class A7800Hawk
|
||||
{
|
||||
public byte ReadMemory(int addr)
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
|
||||
if (addr < 0x0400) {
|
||||
if ((addr & 0xFF) < 0x20)
|
||||
{
|
||||
// return TIA registers or control register if it is still unlocked
|
||||
if ((A7800_control_register & 0x1) == 0 && (addr < 0x20))
|
||||
{
|
||||
return 0xFF; // TODO: what to return here?
|
||||
}
|
||||
else
|
||||
{
|
||||
return TIA_regs[addr]; // TODO: what to return here?
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xFF) < 0x40)
|
||||
{
|
||||
return Maria_regs[(addr & 0x3F) - 0x20];
|
||||
}
|
||||
else if (addr < 0x100)
|
||||
{
|
||||
// RAM block 0
|
||||
return RAM[addr - 0x40 + 0x840];
|
||||
}
|
||||
else if (addr < 0x200)
|
||||
{
|
||||
// RAM block 1
|
||||
return RAM[addr - 0x140 + 0x940];
|
||||
}
|
||||
else if (addr < 0x300)
|
||||
{
|
||||
return regs_6532[addr - 0x240];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF; // what is mapped here?
|
||||
}
|
||||
}
|
||||
else if (addr < 0x480)
|
||||
{
|
||||
return 0xFF; // cartridge space available
|
||||
}
|
||||
else if (addr < 0x500)
|
||||
{
|
||||
// this is where RAM for the 6532 resides for use in 2600 mode
|
||||
return 0xFF;
|
||||
}
|
||||
else if (addr < 0x1800)
|
||||
{
|
||||
return 0xFF; // cartridge space available
|
||||
}
|
||||
else if (addr < 0x2800)
|
||||
{
|
||||
return RAM[addr - 0x1800];
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
return RAM[addr - 0x2800 + 0x800];
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xFF; // cartridge and other OPSYS
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteMemory(int addr, byte value)
|
||||
{
|
||||
addr &= 0xFFFF;
|
||||
|
||||
if (addr < 0x0400)
|
||||
{
|
||||
if ((addr & 0xFF) < 0x20)
|
||||
{
|
||||
// return TIA registers or control register if it is still unlocked
|
||||
if ((A7800_control_register & 0x1) == 0 && (addr < 0x20))
|
||||
{
|
||||
A7800_control_register = value; // TODO: what to return here?
|
||||
}
|
||||
else
|
||||
{
|
||||
TIA_regs[addr] = value; // TODO: what to return here?
|
||||
}
|
||||
}
|
||||
else if ((addr & 0xFF) < 0x40)
|
||||
{
|
||||
Maria_regs[(addr & 0x3F) - 0x20] = value;
|
||||
}
|
||||
else if (addr < 0x100)
|
||||
{
|
||||
// RAM block 0
|
||||
RAM[addr - 0x40 + 0x840] = value;
|
||||
}
|
||||
else if (addr < 0x200)
|
||||
{
|
||||
// RAM block 1
|
||||
RAM[addr - 0x140 + 0x940] = value;
|
||||
}
|
||||
else if (addr < 0x300)
|
||||
{
|
||||
regs_6532[addr - 0x240] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// what is mapped here?
|
||||
}
|
||||
}
|
||||
else if (addr < 0x480)
|
||||
{
|
||||
// cartridge space available
|
||||
}
|
||||
else if (addr < 0x500)
|
||||
{
|
||||
// this is where RAM for the 6532 resides for use in 2600 mode
|
||||
// is it accessible in 7800 mode?
|
||||
}
|
||||
else if (addr < 0x1800)
|
||||
{
|
||||
// cartridge space available
|
||||
}
|
||||
else if (addr < 0x2800)
|
||||
{
|
||||
RAM[addr - 0x1800] = value;
|
||||
}
|
||||
else if (addr < 0x4000)
|
||||
{
|
||||
RAM[addr - 0x2800 + 0x800] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// cartridge and other OPSYS
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
todo:
|
|
@ -0,0 +1,334 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
// Emulates the TIA
|
||||
public partial class TIA : ISoundProvider
|
||||
{
|
||||
public byte BusState;
|
||||
|
||||
private bool _doTicks;
|
||||
|
||||
private byte _hsyncCnt;
|
||||
private int _capChargeStart;
|
||||
private bool _capCharging;
|
||||
public int AudioClocks; // not savestated
|
||||
|
||||
private readonly Audio[] AUD = { new Audio(), new Audio() };
|
||||
|
||||
// current audio register state used to sample correct positions in the scanline (clrclk 0 and 114)
|
||||
////public byte[] current_audio_register = new byte[6];
|
||||
public readonly short[] LocalAudioCycles = new short[2000];
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_hsyncCnt = 0;
|
||||
_capChargeStart = 0;
|
||||
_capCharging = false;
|
||||
AudioClocks = 0;
|
||||
|
||||
_doTicks = false;
|
||||
}
|
||||
|
||||
// Execute TIA cycles
|
||||
public void Execute(int cycles)
|
||||
{
|
||||
// do the audio sampling
|
||||
if (_hsyncCnt == 36 || _hsyncCnt == 148)
|
||||
{
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2);
|
||||
LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2);
|
||||
AudioClocks++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public byte ReadMemory(ushort addr, bool peek)
|
||||
{
|
||||
var maskedAddr = (ushort)(addr & 0x000F);
|
||||
byte coll = 0;
|
||||
int mask = 0;
|
||||
|
||||
if (maskedAddr == 0x00) // CXM0P
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x01) // CXM1P
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x02) // CXP0FB
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x03) // CXP1FB
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x04) // CXM0FB
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x05) // CXM1FB
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x06) // CXBLPF
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x07) // CXPPMM
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
if (maskedAddr == 0x08) // INPT0
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x09) // INPT1
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x0A) // INPT2
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x0B) // INPT3
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x0C) // INPT4
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x0D) // INPT5
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// some bits of the databus will be undriven when a read call is made. Our goal here is to sort out what
|
||||
// happens to the undriven pins. Most of the time, they will be in whatever state they were when previously
|
||||
// assigned in some other bus access, so let's go with that.
|
||||
coll += (byte)(mask & BusState);
|
||||
|
||||
if (!peek)
|
||||
{
|
||||
BusState = coll;
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
public void WriteMemory(ushort addr, byte value, bool poke)
|
||||
{
|
||||
var maskedAddr = (ushort)(addr & 0x3f);
|
||||
if (!poke)
|
||||
{
|
||||
BusState = value;
|
||||
}
|
||||
|
||||
if (maskedAddr == 0x00) // VSYNC
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x01) // VBLANK
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x02) // WSYNC
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x04) // NUSIZ0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x05) // NUSIZ1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x06) // COLUP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x07) // COLUP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x08) // COLUPF
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x09) // COLUBK
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x0A) // CTRLPF
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x0B) // REFP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x0C) // REFP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x0D) // PF0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x0E) // PF1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x0F) // PF2
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x10) // RESP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x11) // RESP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x12) // RESM0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x13) // RESM1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x14) // RESBL
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x15) // AUDC0
|
||||
{
|
||||
AUD[0].AUDC = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x16) // AUDC1
|
||||
{
|
||||
AUD[1].AUDC = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x17) // AUDF0
|
||||
{
|
||||
AUD[0].AUDF = (byte)((value & 31) + 1);
|
||||
}
|
||||
else if (maskedAddr == 0x18) // AUDF1
|
||||
{
|
||||
AUD[1].AUDF = (byte)((value & 31) + 1);
|
||||
}
|
||||
else if (maskedAddr == 0x19) // AUDV0
|
||||
{
|
||||
AUD[0].AUDV = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x1A) // AUDV1
|
||||
{
|
||||
AUD[1].AUDV = (byte)(value & 15);
|
||||
}
|
||||
else if (maskedAddr == 0x1B) // GRP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x1C) // GRP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x1D) // ENAM0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x1E) // ENAM1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x1F) // ENABL
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x20) // HMP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x21) // HMP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x22) // HMM0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x23) // HMM1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x24) // HMBL
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x25) // VDELP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x26) // VDELP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x27) // VDELBL
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x28) // RESMP0
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x29) // RESMP1
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x2A) // HMOVE
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x2B) // HMCLR
|
||||
{
|
||||
|
||||
}
|
||||
else if (maskedAddr == 0x2C) // CXCLR
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private enum AudioRegister : byte
|
||||
{
|
||||
AUDC, AUDF, AUDV
|
||||
}
|
||||
|
||||
private int _frameStartCycles, _frameEndCycles;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
using System;
|
||||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class TIA
|
||||
{
|
||||
public class Audio
|
||||
{
|
||||
// noise/division control
|
||||
public byte AUDC = 0;
|
||||
|
||||
// frequency divider
|
||||
public byte AUDF = 1;
|
||||
|
||||
// volume
|
||||
public byte AUDV = 0;
|
||||
|
||||
// 2 state counter
|
||||
private bool sr1 = true;
|
||||
|
||||
// 4 bit shift register
|
||||
private int sr4 = 0x0f;
|
||||
|
||||
// 5 bit shift register
|
||||
private int sr5 = 0x1f;
|
||||
|
||||
// 9 bit shift register
|
||||
private int sr9 = 0x1ff;
|
||||
|
||||
// 3 state counter
|
||||
private int sr3 = 2;
|
||||
|
||||
// counter based off AUDF
|
||||
private byte freqcnt;
|
||||
|
||||
// latched audio value
|
||||
private bool on = true;
|
||||
|
||||
private bool Run3()
|
||||
{
|
||||
sr3++;
|
||||
if (sr3 == 3)
|
||||
{
|
||||
sr3 = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Run4()
|
||||
{
|
||||
bool ret = (sr4 & 1) != 0;
|
||||
bool c = ((sr4 & 1) != 0) ^ ((sr4 & 2) != 0);
|
||||
sr4 = (sr4 >> 1) | (c ? 8 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool Run5()
|
||||
{
|
||||
bool ret = (sr5 & 1) != 0;
|
||||
bool c = ((sr5 & 1) != 0) ^ ((sr5 & 4) != 0);
|
||||
sr5 = (sr5 >> 1) | (c ? 16 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool One4()
|
||||
{
|
||||
bool ret = (sr4 & 1) != 0;
|
||||
sr4 = (sr4 >> 1) | 8;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool One5()
|
||||
{
|
||||
bool ret = (sr5 & 1) != 0;
|
||||
sr5 = (sr5 >> 1) | 16;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool Run1()
|
||||
{
|
||||
sr1 = !sr1;
|
||||
return !sr1;
|
||||
}
|
||||
|
||||
private bool Run9()
|
||||
{
|
||||
bool ret = (sr9 & 1) != 0;
|
||||
bool c = ((sr9 & 1) != 0) ^ ((sr9 & 16) != 0);
|
||||
sr9 = (sr9 >> 1) | (c ? 256 : 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// call me approx 31k times a second
|
||||
/// </summary>
|
||||
/// <returns>16 bit audio sample</returns>
|
||||
public short Cycle()
|
||||
{
|
||||
if (++freqcnt >= AUDF)
|
||||
{
|
||||
freqcnt = 0;
|
||||
switch (AUDC)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x0b:
|
||||
// Both have a 1 s
|
||||
One5();
|
||||
on = One4();
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
// Both run, but the 5 bit is ignored
|
||||
on = Run4();
|
||||
//Run5();
|
||||
break;
|
||||
case 0x02:
|
||||
if ((sr5 & 0x0f) == 0 || (sr5 & 0x0f) == 0x0f)
|
||||
{
|
||||
on = Run4();
|
||||
}
|
||||
|
||||
Run5();
|
||||
break;
|
||||
case 0x03:
|
||||
if (Run5())
|
||||
{
|
||||
on = Run4();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
Run5();
|
||||
One4();
|
||||
on = Run1();
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
One5();
|
||||
Run4();
|
||||
on = Run1();
|
||||
break;
|
||||
|
||||
case 0x06:
|
||||
case 0x0a:
|
||||
Run5();
|
||||
if ((sr5 & 0x0f) == 0)
|
||||
{
|
||||
on = false;
|
||||
}
|
||||
else if ((sr5 & 0x0f) == 0x0f)
|
||||
{
|
||||
on = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0x07:
|
||||
case 0x09:
|
||||
on = Run5();
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
on = Run9();
|
||||
break;
|
||||
case 0x0c:
|
||||
case 0x0d:
|
||||
if (Run3())
|
||||
{
|
||||
on = Run1();
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0e:
|
||||
if (Run3())
|
||||
{
|
||||
goto case 0x06;
|
||||
}
|
||||
|
||||
break;
|
||||
case 0x0f:
|
||||
if (Run3())
|
||||
{
|
||||
goto case 0x07;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (short)(on ? AUDV * 1092 : 0);
|
||||
}
|
||||
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.Sync("AUDC", ref AUDC);
|
||||
ser.Sync("AUDF", ref AUDF);
|
||||
ser.Sync("AUDV", ref AUDV);
|
||||
ser.Sync("sr1", ref sr1);
|
||||
ser.Sync("sr3", ref sr3);
|
||||
ser.Sync("sr4", ref sr4);
|
||||
ser.Sync("sr5", ref sr5);
|
||||
ser.Sync("sr9", ref sr9);
|
||||
ser.Sync("freqcnt", ref freqcnt);
|
||||
ser.Sync("on", ref on);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class TIA : ISoundProvider
|
||||
{
|
||||
public bool CanProvideAsync => false;
|
||||
|
||||
public void SetSyncMode(SyncSoundMode mode)
|
||||
{
|
||||
if (mode != SyncSoundMode.Sync)
|
||||
{
|
||||
throw new InvalidOperationException("Only Sync mode is supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public SyncSoundMode SyncMode => SyncSoundMode.Sync;
|
||||
|
||||
public void GetSamplesSync(out short[] samples, out int nsamp)
|
||||
{
|
||||
short[] ret = new short[_spf * 2];
|
||||
GetSamples(ret);
|
||||
samples = ret;
|
||||
nsamp = _spf;
|
||||
}
|
||||
|
||||
public void GetSamplesAsync(short[] samples)
|
||||
{
|
||||
throw new NotSupportedException("Async is not available");
|
||||
}
|
||||
|
||||
public void DiscardSamples()
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (AudioClocks > 0)
|
||||
{
|
||||
var samples31Khz = new short[AudioClocks]; // mono
|
||||
|
||||
for (int i = 0; i < AudioClocks; i++)
|
||||
{
|
||||
samples31Khz[i] = LocalAudioCycles[i];
|
||||
LocalAudioCycles[i] = 0;
|
||||
}
|
||||
|
||||
// convert from 31khz to 44khz
|
||||
for (var i = 0; i < samples.Length / 2; i++)
|
||||
{
|
||||
samples[i * 2] = samples31Khz[(int)(((double)samples31Khz.Length / (double)(samples.Length / 2)) * i)];
|
||||
samples[(i * 2) + 1] = samples[i * 2];
|
||||
}
|
||||
}
|
||||
|
||||
AudioClocks = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using BizHawk.Common;
|
||||
|
||||
namespace BizHawk.Emulation.Cores.Atari.A7800Hawk
|
||||
{
|
||||
public partial class TIA
|
||||
{
|
||||
public void SyncState(Serializer ser)
|
||||
{
|
||||
ser.BeginSection("TIA");
|
||||
|
||||
ser.Sync("hsyncCnt", ref _hsyncCnt);
|
||||
|
||||
// add everything to the state
|
||||
ser.Sync("Bus_State", ref BusState);
|
||||
|
||||
ser.Sync("Ticks", ref _doTicks);
|
||||
|
||||
// some of these things weren't in the state because they weren't needed if
|
||||
// states were always taken at frame boundaries
|
||||
ser.Sync("capChargeStart", ref _capChargeStart);
|
||||
ser.Sync("capCharging", ref _capCharging);
|
||||
ser.Sync("AudioClocks", ref AudioClocks);
|
||||
ser.Sync("FrameStartCycles", ref _frameStartCycles);
|
||||
ser.Sync("FrameEndCycles", ref _frameEndCycles);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue