diff --git a/Assets/NES/Palettes/FCEUX.pal b/Assets/NES/Palettes/FCEUX (2.2.0).pal similarity index 66% rename from Assets/NES/Palettes/FCEUX.pal rename to Assets/NES/Palettes/FCEUX (2.2.0).pal index 2b8ea5d63e..7bf9128fb5 100644 Binary files a/Assets/NES/Palettes/FCEUX.pal and b/Assets/NES/Palettes/FCEUX (2.2.0).pal differ diff --git a/Assets/defctrl.json b/Assets/defctrl.json index 65c84b7fdb..e213cfae5f 100644 --- a/Assets/defctrl.json +++ b/Assets/defctrl.json @@ -743,6 +743,34 @@ "P2 B1": "", "P2 B2": "" }, + "SMS Paddle Controller": { + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" + }, + "SMS Light Phaser Controller": { + "P1 Trigger": "Z, J1 B1, X1 X, WMouse L", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start" + }, + "SMS Sports Pad Controller": { + "P1 Up": "UpArrow, J1 POV1U", + "P1 Down": "DownArrow, J1 POV1D", + "P1 Left": "LeftArrow, J1 POV1L", + "P1 Right": "RightArrow, J1 POV1R", + "P1 B1": "Z, J1 B1, X1 X", + "P1 B2": "X, J1 B2, X1 A", + "Reset": "J1 B9, X1 Back", + "Pause": "J1 B10, X1 Start", + "P2 Up": "", + "P2 Down": "", + "P2 Left": "", + "P2 Right": "", + "P2 B1": "", + "P2 B2": "" + }, "GG Controller": { "P1 Up": "UpArrow, J1 POV1U, X1 DpadUp, X1 LStickUp", "P1 Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown", @@ -1567,6 +1595,47 @@ "Mult": 1.0, "Deadzone": 0.1 } + }, + "SMS Paddle Controller": { + "P1 Paddle": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + } + }, + "SMS Light Phaser Controller": { + "P1 X": { + "Value": "WMouse X", + "Mult": 1.0, + "Deadzone": 0.0 + }, + "P1 Y": { + "Value": "WMouse Y", + "Mult": 1.0, + "Deadzone": 0.0 + } + }, + "SMS Sports Pad Controller": { + "P1 X": { + "Value": "X1 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "P1 Y": { + "Value": "X1 LeftThumbY", + "Mult": -1.0, + "Deadzone": 0.1 + }, + "P2 X": { + "Value": "X2 LeftThumbX", + "Mult": 1.0, + "Deadzone": 0.1 + }, + "P2 Y": { + "Value": "X2 LeftThumbY", + "Mult": -1.0, + "Deadzone": 0.1 + } } } } \ No newline at end of file diff --git a/Assets/gamedb/EMU7800.csv b/Assets/gamedb/EMU7800.csv deleted file mode 100644 index 2bc1e694ec..0000000000 --- a/Assets/gamedb/EMU7800.csv +++ /dev/null @@ -1,2005 +0,0 @@ -Title,Manufacturer,Author,Qualifier,Year,ModelNo,Rarity,CartType,MachineType,LController,RController,MD5,HelpUri -11 Sprite Demo (Piero Cavina),,Piero Cavina,Homebrew,,,,,A2600NTSC,,,0685bd0bcb975ceef7041749a5454a48, -128-in-1 Junior Console (Chip 1) (64K),,,,,,,,A2600PAL,,,1862fca4f98e66f363308b859b5863af, -128-in-1 Junior Console (Chip 2) (64K),,,,,,,,A2600PAL,,,715dd9e0240638d441a3add49316c018, -128-in-1 Junior Console (Chip 3) (64K),,,,,,,,A2600PAL,,,0d6b974fe58a1bdd453600401c407856, -128-in-1 Junior Console (Chip 4) (64K),,,,,,,,A2600PAL,,,7f525b07bc98080cc8950f7284e52ede, -2 Pak Special - Dolphin - Pigs 'N' Wolf,HES,,,1990,,,,A2600PAL,,,8c8a26ed57870daba8e13162d497bad1, -2 Pak Special Black - Challenge - Surfing,HES,,,,,,,A2600PAL,,,fd7464edaa8cc264b97ba0d13e7f0678, -2 Pak Special Dark Blue - Planet Patrol - Wall Defender,HES,,,1990,,,,A2600PAL,,,72fd08deed1d6195942e0c6f392e9848, -2 Pak Special Green - Hoppy - Alien Force,HES,,,,,,,A2600PAL,,,5b9c2e0012fbfd29efd3306359bbfc4a, -2 Pak Special Green - Hoppy - Alien Force,HES,,,,,,,A2600PAL,,,ab434f4c942d6472e75d5490cc4dd128, -2 Pak Special Magenta - CaveBlast -City War,HES,,,1992,,,,A2600PAL,,,7f430c33044e0354815392b53a9a772d, -2 Pak Special Yellow - Star Warrior - Frogger,HES,,,1990,,,,A2600PAL,,,02a5fc90a0d183f870e8eebac1f16591, -2 Pak Special Yellow - Star Warrior - Frogger,HES,,,1990,,,,A2600PAL,,,4d2cef8f19cafeec72d142e34a1bbc03, -2-in-1 - Freeway and Tennis,,,,,,,,A2600NTSC,,,94e3fbc19107a169909e274187247a9d, -2-in-1 - Frostbite and River Raid,,,,,,,,A2600NTSC,,,9c40bf810f761ffc9c1b69c4647a8b84, -20 Sprites at Once Demo 1,,,,,,,,A2600NTSC,,,fa529ec88eca679f6d5fd0ccb2120e46, -20 Sprites at Once Demo 2,,,,,,,,A2600NTSC,,,7a93d0c029eaa72236523eedc3f19645, -20 Sprites at Once Demo 3,,,,,,,,A2600NTSC,,,6c449db9bbbd90972ad1932d6af87330, -20 Sprites at Once Demo 4,,,,,,,,A2600NTSC,,,bfa58198c6b9cd8062ee76a2b38e9b33, -20 Sprites at Once Demo 5,,,,,,,,A2600NTSC,,,d2d8c4f1ea7f347c8bcc7d24f45aa338, -2600 Collison Demo 1,,,,,,,,A2600NTSC,,,ad2e6bfb3b9b9b36ba8bf493ce764c49, -2600 Collison Demo 2,,,,,,,,A2600NTSC,,,777aece98d7373998ffb8bc0b5eff1a2, -2600 Digital Clock (Demo 1),,,,,,,,A2600NTSC,,,eada0dd61ce13f8317de774dc1e68604, -2600 Digital Clock (Demo 2),,,,,,,,A2600NTSC,,,3e5ca1afaa27c5da3c54c9942fec528b, -2600 Digital Clock (Demo 3),,,,,,,,A2600NTSC,,,f6efa00ae99aaf33e427b674bcfd834d, -2600 Digital Clock (V b1),,,,,,,,A2600NTSC,,,75e8d8b9e9c5c67c2226dbfd77dcfa7d, -2600 Digital Clock (V b2),,,,,,,,A2600NTSC,,,5e99aa93d0acc741dcda8752c4e813ce, -2600 Digital Clock (V x.xx),,,,,,,,A2600NTSC,,,4faeb04b1b7fb0fa25db05753182a898, -2600 Digital Clock (V x.xx),,,,,,,,A2600NTSC,,,62ffd175cac3f781ef6e4870136a2520, -2Pak Black - Challenge - Surfing,HES,,,,,,,A2600PAL,,,7732e4e4cc2644f163d6650ddcc9d9df, -3-D Tic-Tac-Toe (32-in-1),Atari,Carol Shaw,,,,,,A2600PAL,,,7b5207e68ee85b16998bea861987c690,http://www.atariage.com/manual_thumbs.html?SoftwareID=798 -3-D Tic-Tac-Toe,Atari,Carol Shaw,,1978,,,,A2600PAL,,,402b1ca3c230a60fb279d4a2a10fa677,http://www.atariage.com/manual_thumbs.html?SoftwareID=798 -3-D Tic-Tac-Toe,Atari,Carol Shaw,,1978,CX2618,Uncommon,,A2600NTSC,,,0db4f4150fecf77e4ce72ca4d04c052f,http://www.atariage.com/manual_thumbs.html?SoftwareID=798 -3-D Tic-Tac-Toe,Atari,Carol Shaw,,1978,CX2618,Uncommon,,A2600NTSC,,,f3213a8a702b0646d2eaf9ee0722b51c,http://www.atariage.com/manual_thumbs.html?SoftwareID=798 -3-D Tic-Tac-Toe,Atari,Carol Shaw,,1978,CX2618,Uncommon,,A2600PAL,,,e3600be9eb98146adafdc12d91323d0f,http://www.atariage.com/manual_thumbs.html?SoftwareID=798 -32-in-1,Atari,,,,CX26163P,,M32N12K,A2600PAL,,,291bcdb05f2b37cdf9452d2bf08e0321,http://www.atariage.com/manual_html_page.html?SoftwareLabelID=899 -3D Asteroids,Atari,,Prototype,,,,,A7800NTSC,,,4332c24e4f3bc72e7fe1b77adf66c2b7, -4 Pak (Dark Green),,,,,,,,A2600PAL,,,703f0f7af350b0fa29dfe5fbf45d0d75, -4 Pak (Light Green),,,,,,,,A2600NTSC,,,31bb9b8ceed46cb3e506777a9e65f3ce, -A-Team,Atari,,Prototype,,CX26133,,,A2600NTSC,,,c00734a2233ef683d9b6e622ac97a5c8, -A-Team,Atari,Manuel Polik & Fabrizio Zavagli,Prototype,,,,,A2600NTSC,,,2cefa695df2ed020899a7df7bb1e3a95, -A-Team,Atari,Manuel Polik & Fabrizio Zavagli,Prototype,,,,,A2600PAL,,,c02e1afa0671e438fd526055c556d231, -A-Team,Atari,Manuel Polik & Fabrizio Zavagli,Prototype,,,,,A2600PAL,,,dafc3945677ccc322ce323d1e9930beb, -Ace of Aces,Atari,,,1988,CX7846,Common,A78SG,A7800NTSC,,,0be996d25144966d5541c9eb4919b289,http://www.atariage.com/manual_thumbs.html?SoftwareID=2116 -Ace of Aces,Atari,,,1988,CX7846,Common,A78SG,A7800PAL,,,aadde920b3aaba03bc10b40bd0619c94,http://www.atariage.com/manual_thumbs.html?SoftwareID=2116 -Acid Drop (non-working 8K single bank dump),Salu,,,,,Extremely Rare,A16K,A2600PAL,,,5f17fef8a64d64d119f8e76c50238762, -Acid Drop,,Thomas Jentzsch,Hack,,,,A16K,A2600NTSC,,,09274c3fc1c43bf1e362fda436651fd8, -Acid Drop,Salu,Dennis M. Kiss,,1992,,Extremely Rare,A16K,A2600PAL,,,17ee23e5da931be82f733917adcb6386, -Action Force - Action Man,Parker Bros,,,1983,,,,A2600PAL,Paddles,Paddles,b9f6fa399b8cd386c235983ec45e4355, -Action Force - Action Man,Parker Bros,,,1983,,,,A2600PAL,Paddles,Paddles,d573089534ca596e64efef474be7b6bc, -Adventure,Atari,Warren Robinett,,1978,CX2613,Common,,A2600NTSC,,,157bddb7192754a45372be196797f284,http://www.atariage.com/manual_thumbs.html?SystemID=2600&SoftwareID=802&ItemTypeID=MANUAL -Adventure,Atari,Warren Robinett,,1978,CX2613,Common,,A2600PAL,,,4b27f5397c442d25f0c418ccdacf1926,http://www.atariage.com/manual_thumbs.html?SystemID=2600&SoftwareID=802&ItemTypeID=MANUAL -Adventure34,Atari,Kurt Howe,Hack,,,,,A2600NTSC,,,171cd6b55267573e6a9c2921fb720794,http://www.atariage.com/manual_thumbs.html?SystemID=2600&SoftwareID=802&ItemTypeID=MANUAL -Adventures of Tron,Mattel,,,1983,MT4317,Uncommon,,A2600NTSC,,,ca4f8c5b4d6fb9d608bb96bc7ebd26c7, -Adventures on GX-12,Telegames,,,,,,,A2600PAL,,,06cfd57f0559f38b9293adae9128ff88, -Air Raid,MenAvision,,,,C-817,Extremely Rare,,A2600NTSC,,,35be55426c1fec32dfb503b4f0651572, -Air Raiders,Mattel,,,,MT5861,,,A2600PAL,,,cf3a9ada2692bb42f81192897752b912, -Air Raiders,Mattel,,,1982,MT5861,,,A2600NTSC,,,a9cb638cd2cb2e8e0643d7a67db4281c, -Air-Sea Battle (32-in-1),Atari,Larry Kaplan,,,,,,A2600PAL,,,8aad33da907bed78b76b87fceaa838c1,http://www.atariage.com/manual_thumbs.html?SoftwareID=808 -Air-Sea Battle,Atari,Larry Kaplan,,1977,,,,A2600NTSC,,,98e5e4d5c4dd9a986d30fd62bd2f75ae,http://www.atariage.com/manual_thumbs.html?SoftwareID=808 -Air-Sea Battle,Atari,Larry Kaplan,,1977,,,,A2600PAL,,,e5fcc62e1d73706be7b895e887e90f84,http://www.atariage.com/manual_thumbs.html?SoftwareID=808 -Air-Sea Battle,Atari,Larry Kaplan,,1977,CX2602,Uncommon,,A2600NTSC,,,16cb43492987d2f32b423817cdaaf7c4,http://www.atariage.com/manual_thumbs.html?SoftwareID=808 -Air-Sea Battle,Atari,Larry Kaplan,,1977,CX2602,Uncommon,,A2600NTSC,,,1d1d2603ec139867c1d1f5ddf83093f1,http://www.atariage.com/manual_thumbs.html?SoftwareID=808 -Air-Sea Battle,Atari,Larry Kaplan,,1977,CX2602,Uncommon,,A2600PAL,,,0c7926d660f903a2d6910c254660c32c,http://www.atariage.com/manual_thumbs.html?SoftwareID=808 -Airlock,Data Age,,,1982,DA 1004,Common,,A2600NTSC,,,4d77f291dca1518d7d8e47838695f54b, -Alice's Abenteuer,Starsoft,,,,,,,A2600PAL,,,d0cdafcb000b9ae04ac465f17788ad11, -Alien Brigade,Atari,Ken Grant,,1989,CX7855,Rare,A78S9,A7800NTSC,,,877dcc97a775ed55081864b2dbf5f1e2,http://www.atariage.com/manual_thumbs.html?SoftwareID=2164 -Alien Brigade,Atari,Ken Grant,,1989,CX7855,Rare,A78S9,A7800PAL,,,de3e9496cb7341f865f27e5a72c7f2f5,http://www.atariage.com/manual_thumbs.html?SoftwareID=2164 -Alien Invaders Plus,,,Hack,,,,,A2600NTSC,,,4d6cfb7da66c8d9327b3ccdce9852509, -Alien's Return,ITT Family Games,,,,554-33391,Extremely Rare,,A2600PAL,,,103f1756d9dc0dd2b16b53ad0f0f1859, -Alien,20th Century Fox,,,1982,11006,Rare,,A2600NTSC,,,f1a0a23e6464d954e3a9579c4ccd01c8, -Alien,CCE,,,,,,,A2600NTSC,,,956496f81775de0b69a116a0d1ad41cc, -Alpha Beam with Ernie,Atari,,,1983,CX26103,Rare,,A2600NTSC,Keypad,Keypad,9e01f7f95cb8596765e03b9a36e8e33c, -Alpha Beam with Ernie,Atari,,,1983,CX26103,Rare,,A2600PAL,Keypad,Keypad,f2d40c70cf3e1d03bc112796315888d9, -Amanda Invaders,,,,,,,,A2600NTSC,,,26bc2bdf447a17376aea7ef187ff6e44, -Amanda Invaders,,,,,,,,A2600NTSC,,,51f15b39d9f502c2361b6ba6a73464d4, -Amidar,Parker Bros,,,1983,PB5310,Uncommon,,A2600NTSC,,,acb7750b4d0c4bd34969802a7deb2990, -Amidar,Parker Bros,,,1983,PB5310,Uncommon,,A2600PAL,,,056f5d886a4e7e6fdd83650554997d0d, -Angling,Ariola,,,,,,,A2600PAL,,,6672de8f82c4f7b8f7f1ef8b6b4f614d, -Angriff der Luftflotten (a.k.a. Paris Attack),Starsoft,,,,,,,A2600PAL,,,adf1afac3bdd7b36d2eda5949f1a0fa3, -Apples and Dolls,CCE,,,,,,,A2600NTSC,,,e73838c43040bcbc83e4204a3e72eef4, -Aquaventure,Atari,,,,,Unbelievably Rare,A8K,A2600NTSC,,,038e1e79c3d4410defde4bfe0b99cc32, -Aquaventure,CCE,,,,,,A8K,A2600NTSC,,,f69d4fcf76942fcd9bdf3fd8fde790fb, -Arkanoid (0911),,,Homebrew,2011,,,A7832P,A7800NTSC,,,0a9e58ef5eb9ff93246e0fff684dc7f1, -Armor Ambush,Mattel,,,1982,MT5661,Common,,A2600NTSC,,,a7b584937911d60c120677fe0d47f36f, -Armor Ambush,Telegames,,,1982,,,,A2600PAL,,,d0af33865512e9b6900714c26db5fa23, -Artillery Duel,Xonox,,,1983,,,,A2600PAL,,,589c73bbcd77db798cb92a992b4c06c3, -Artillery Duel,Xonox,,,1983,99004,Extremely Rare,,A2600NTSC,,,3f039981255691d3859d04ef813a1264, -Artillery Duel,Xonox,,,1983,99004,Extremely Rare,,A2600NTSC,,,c77c35a6fc3c0f12bf9e8bae48cba54b, -Assault,Bomb,,,,CA281,Extremely Rare,,A2600NTSC,,,de78b3a064d374390ac0710f95edde92, -Aster Hawk,,Charles Morgan,Hack,,,,A8K,A2600NTSC,,,327468d6c19697e65ab702f06502c7ed, -Asterix,Atari,,,1988,CX2696,Extremely Rare,,A2600PAL,,,c5c7cc66febf2d4e743b4459de7ed868, -Asterix,Atari,,,1988,CX2696,Extremely Rare,,A2600PAL,,,faebcb2ef1f3831b2fc1dbd39d36517c, -Asterix,Atari,,Prototype,,CX2696,Extremely Rare,,A2600NTSC,,,89a68746eff7f266bbf08de2483abe55, -Asteroids (Vector),,Franklin Cruz,,,,,A8K,A2600NTSC,,,df40af244a8d68b492bfba9e97dea4d6, -Asteroids DC+,,Thomas Jentzsch,Hack,,,,A8K,A2600NTSC,Driving,Driving,2dbdca3058035d2b40c734dcf06a86d9,http://www.atariage.com/manual_html_page.html?SoftwareID=828 -Asteroids Deluxe,,Bob DeCrescenzo,Hack,2007,,,,A7800NTSC,,,f9fb84658c5586df159a0c75cc46b54c,http://www.atariage.com/software_page.html?SoftwareLabelID=2771 -Asteroids Deluxe,,Bob DeCrescenzo,Homebrew,2007,,,A7832,A7800NTSC,,,a65f79ad4a0bbdecd59d5f7eb3623fd7,http://www.atariage.com/software_page.html?SoftwareLabelID=2771 -Asteroids Deluxe,,Bob DeCrescenzo,Homebrew,2007,,,A7832,A7800PAL,,,1baf41de200f26ec643625021290bec2,http://www.atariage.com/software_page.html?SoftwareLabelID=2771 -Asteroids,,Scott Stilphen,Hack,,,,A8K,A2600NTSC,,,8df4be9ddc54ac363b13dc57ceaf161a,http://www.atariage.com/manual_html_page.html?SoftwareID=828 -Asteroids,Atari,,,1984,CX7802,Common,,A7800NTSC,,,07342c78619ba6ffcc61c10e907e3b50,http://www.atariage.com/manual_thumbs.html?SoftwareID=2117 -Asteroids,Atari,Brad Stewart,,1981,CX2649,Common,A8K,A2600NTSC,,,b227175699e372b8fe10ce243ad6dda5,http://www.atariage.com/manual_html_page.html?SoftwareID=828 -Asteroids,Atari,Brad Stewart,,1981,CX2649,Common,A8K,A2600NTSC,,,ccbd36746ed4525821a8083b0d6d2c2c,http://www.atariage.com/manual_html_page.html?SoftwareID=828 -Asteroids,Atari,Brad Stewart,,1981,CX2649,Common,A8K,A2600PAL,,,8cf0d333bbe85b9549b1e6b1e2390b8d,http://www.atariage.com/manual_html_page.html?SoftwareID=828 -Astroblast,Mattel,,,1982,MT5666,Uncommon,,A2600NTSC,,,170e7589a48739cfb9cc782cbb0fe25a, -Astroblast,Mattel,,,1982,MT5666,Uncommon,,A2600NTSC,,,75169c08b56e4e6c36681e599c4d8cc5, -Astrowar,Starsoft,,,,SM8002,Unbelievably Rare,,A2600NTSC,,,8f53a3b925f0fd961d9b8c4d46ee6755, -Atari 2600 Invaders,,,Hack,,,,,A2600NTSC,,,a4aa7630e4c0ad7ebb9837d2d81de801, -Atari Invaders,,,Hack,,,,,A2600NTSC,,,d0a379946ed77b1b126230ca68461333, -Atari Logo Demo 1,,,,,,,,A2600NTSC,,,e932f44fad2a66b6d5faec9addec208e, -Atari Logo Demo 2,,,,,,,,A2600NTSC,,,13d8326bf5648db4dafce45d25e62ddd, -Atari Logo Demo 3,,,,,,,,A2600NTSC,,,3e49da621193d2611a4ea152d5d5ca3a, -Atari Logo Demo 5,,,,,,,,A2600NTSC,,,42e0ec5ab8f5deba53e4169ff2a5efbe, -Atari Logo Demo 6,,,,,,,,A2600NTSC,,,9526e3db3bdfbc27989a9cbfd0ee34bf, -Atari Logo Demo,,,,,,,,A2600PAL,,,d61629bbbe035f45552e31cef7d591b2, -Atari Video Cube,Atari,,,1982,CX2670,Rare,,A2600NTSC,,,3f540a30fdee0b20aed7288e4a5ea528, -Atlantis II,Imagic,,,1982,,,,A2600NTSC,,,826481f6fc53ea47c9f272f7050eedf7, -Atlantis,CCE,,,,,,,A2600NTSC,,,0b33252b680b65001e91a411e56e72e9,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Atlantis,Imagic,Dennis Koble,,,,,,A2600NTSC,,,60345ae60f7c7010346de7aff9bfe6ea,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Atlantis,Imagic,Dennis Koble,,,,,,A2600NTSC,,,cb8afcbc4a779b588b0428ea7af211d5,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Atlantis,Imagic,Dennis Koble,,1982,,,,A2600PAL,,,c4bbbb0c8fe203cbd3be2e318e55bcc0,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Atlantis,Imagic,Dennis Koble,,1982,IA3203,Uncommon,,A2600NTSC,,,9ad36e699ef6f45d9eb6c4cf90475c9f,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Atlantis,Imagic,Dennis Koble,,1982,IA3203,Uncommon,,A2600NTSC,,,acb962473185d7a652f90ed6591ae13b,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Atlantis,Imagic,Dennis Koble,,1982,IA3203,Uncommon,,A2600PAL,,,3d2367b2b09c28f1659c082bb46a7334,http://www.atariage.com/manual_html_page.html?SoftwareID=2457 -Attack Of The Mutant Space Urchins,,Barry Laws Jr.,Hack,,,,,A2600NTSC,,,a7cf2b9afdbb3a161bf418dbcf0321dc, -Aufruhr im Zoo,Starsoft,,,,,,,A2600PAL,,,0fcff6fe3b0769ad5d0cf82814d2a6d9, -Autorennen (a.k.a. Grand Prix),Ariola,,,,,,,A2600PAL,,,b4f87ce75f7329c18301a2505fe59cd3, -BMX Air Master,TNT Games,,,1989,CX26190,Extremely Rare,,A2600NTSC,,,968efc79d500dce52a906870a97358ab, -BMX Air Master,TNT Games,,,1989,CX26190,Extremely Rare,,A2600PAL,,,7c757bb151269b2a626c907a22f5dae7, -Bachelor Party,Mystique,,,,1002,Extremely Rare,,A2600NTSC,Paddles,Paddles,5b124850de9eea66781a50b2e9837000, -Bachelorette Party,Playaround,,,,1004,Extremely Rare,,A2600NTSC,Paddles,Paddles,274d17ccd825ef9c728d68394b4569d2, -Backgammon,Atari,Craig Nelson,,1978,CX2617,Extremely Rare,,A2600NTSC,Paddles,Paddles,8556b42aa05f94bc29ff39c39b11bff4,http://www.atariage.com/manual_thumbs.html?SoftwareID=842 -Backgammon,Atari,Craig Nelson,,1978,CX2617,Extremely Rare,,A2600PAL,Paddles,Paddles,85b1bca93e69f13905107cc802a02470,http://www.atariage.com/manual_thumbs.html?SoftwareID=842 -Ballblazer,Atari,,,1987,CX7815,Common,A7832P,A7800NTSC,,,8fc3a695eaea3984912d98ed4a543376,http://www.atariage.com/manual_thumbs.html?SoftwareID=2118 -Ballblazer,Atari,,,1987,CX7815,Common,A7832P,A7800PAL,,,b558814d54904ce0582e2f6a801d03af,http://www.atariage.com/manual_thumbs.html?SoftwareID=2118 -Bank Heist (w Skull Island Label),20th Century Fox,,,,11012,Rare,,A2600PAL,,,e9c71f8cdba6037521c9a3c70819d171, -Bank Heist,20th Century Fox,,,1983,11012,Rare,,A2600NTSC,,,00ce0bdd43aed84a983bef38fe7f5ee3, -Barber Pole Demo,,,,,,,,A2600NTSC,,,73a710e621d44e97039d640071908aef, -Barnstorming,Activision,Steve Cartwright,,1982,AX-013,Uncommon,,A2600NTSC,,,a29fc854838e08c247553a7d883dd65b,http://www.atariage.com/manual_thumbs.html?SoftwareID=846 -Barnstorming,Activision,Steve Cartwright,,1982,AX-013,Uncommon,,A2600NTSC,,,f8240e62d8c0a64a61e19388414e3104,http://www.atariage.com/manual_thumbs.html?SoftwareID=846 -Barnstorming,Activision,Steve Cartwright,,1982,AX-013,Uncommon,,A2600PAL,,,9ad362179c2eea4ea115c7640b4b003e,http://www.atariage.com/manual_thumbs.html?SoftwareID=846 -Barnstorming,CCE,Steve Cartwright,,,,,,A2600NTSC,,,5ae73916fa1da8d38ceff674fa25a78a,http://www.atariage.com/manual_thumbs.html?SoftwareID=846 -Barnyard Blaster,Atari,,,1988,,Common,A78SG,A7800NTSC,Lightgun,Lightgun,42682415906c21c6af80e4198403ffda,http://www.atariage.com/manual_thumbs.html?SoftwareID=2119 -Barnyard Blaster,Atari,,,1988,,Common,A78SG,A7800PAL,Lightgun,Lightgun,babe2bc2976688bafb8b23c192658126, -Bars and Text Demo 2,,,,,,,,A2600NTSC,,,d7891b0faa4c7f764482762d0ed427a5, -Bars and Text Demo 3,,,,,,,,A2600NTSC,,,600d48eef5c0ec27db554b7328b3251c, -Bars and Text Demo,,,,,,,,A2600NTSC,,,dcec46a98f45b193f07239611eb878c2, -Base Attack (a.k.a. Z-Tack -Laser-Loop -Sky Scrapper),HomeVision,,,,,,,A2600PAL,,,d6dc9b4508da407e2437bfa4de53d1b2, -Basic Programming,Atari,Warren Robinett,,1978,CX262,Rare,,A2600NTSC,Keypad,Keypad,9f48eeb47836cf145a15771775f0767a,http://www.atariage.com/manual_html_page.html?SoftwareID=852 -Basic Programming,Atari,Warren Robinett,,1978,CX2624,Common,,A2600PAL,Keypad,Keypad,b061e98a4c854a672aadefa233236e51,http://www.atariage.com/manual_html_page.html?SoftwareID=852 -Basketball (32-in-1),Atari,,,,,,,A2600PAL,,,1228c01cd3c4b9c477540c5adb306d2a,http://www.atariage.com/manual_thumbs.html?SoftwareID=854 -Basketball,Atari,Alan Miller,,1978,CX2624,Common,,A2600NTSC,,,ab4ac994865fb16ebb85738316309457,http://www.atariage.com/manual_thumbs.html?SoftwareID=854 -Basketball,Atari,Alan Miller,,1978,CX2624,Common,,A2600NTSC,,,e13c7627b2e136b9c449d9e8925b4547,http://www.atariage.com/manual_thumbs.html?SoftwareID=854 -Basketball,Atari,Alan Miller,,1978,CX2624,Common,,A2600PAL,,,218c0fe53dfaaa37f3c823f66eafd3fc,http://www.atariage.com/manual_thumbs.html?SoftwareID=854 -Basketbrawl,Atari,,,1990,CX7880,Rare,A78SG,A7800NTSC,,,f5f6b69c5eb4b55fc163158d1a6b423e,http://www.atariage.com/manual_thumbs.html?SoftwareID=2165 -Basketbrawl,Atari,,,1990,CX7880,Rare,A78SG,A7800PAL,,,fba002089fcfa176454ab507e0eb76cb,http://www.atariage.com/manual_thumbs.html?SoftwareID=2165 -Battle For Naboo,Imagic,Josh,Hack,,,,,A2600NTSC,,,5c0227ad63300670a647fcebf595ea37, -Battlezone TC,,Thomas Jentzsch,Hack,,,,A16K,A2600NTSC,,,6015a9cef783e97e98a2aa2cf070ae06, -Battlezone,Atari,,,1983,CX2681,Uncommon,A8K,A2600NTSC,,,41f252a66c6301f1e8ab3612c19bc5d4, -Battlezone,Atari,,,1983,CX2681,Uncommon,A8K,A2600PAL,,,fbe554aa8f759226d251ba6b64a9cce4, -Beamrider,Activision,Dave Rolfe,,1983,AZ-037-04,Rare,,A2600NTSC,,,3604e725e81dd0abede07fd1c82eb058, -Beamrider,Activision,Dave Rolfe,,1983,AZ-037-04,Rare,,A2600NTSC,,,79ab4123a83dc11d468fb2108ea09e2e, -Beamrider,Activision,Dave Rolfe,,1983,AZ-037-04,Rare,,A2600PAL,,,fec0c2e2ab0588ed20c750b58cf3baa3, -Beanie Baby Bash,Inky,,Hack,,,,,A2600NTSC,,,f4204fc92d17ed4cb567c40361ad58f1, -Beany Bopper,20th Century Fox,,,1982,11002,Rare,,A2600NTSC,,,d0b9df57bfea66378c0418ec68cfe37f, -Beany Bopper,CCE,,,,,,,A2600NTSC,,,6a9e0c72fab92df70084eccd9061fdbd, -Beast Invaders,,Jeff 'Yak' Minter,Hack,,,,,A2600NTSC,,,235436ab0832370e73677c9c6f0c8b06, -Beat 'Em and Eat 'Em,Mystique,,,,1003,Extremely Rare,,A2600NTSC,Paddles,Paddles,59e96de9628e8373d1c685f5e57dcf10, -Beef Drop,,Ken Siders,Homebrew,2006,,,,A7800NTSC,,,6010a398070dfacb4c0173d75d73c50a,http://www.atariage.com/software_page.html?SoftwareLabelID=2782 -Beef Drop,,Ken Siders,Homebrew,2006,,,,A7800NTSC,,,c534db0a062225b17cfb8ecce0fb9090,http://www.atariage.com/software_page.html?SoftwareLabelID=2782 -Bentley Bear - Crystal Quest,,Bob DeCrescenzo,Homebrew,2012,,,A78S9,A7800NTSC,,,6da5b1b9fa0001e3517f6084ff651b07, -Berenstain Bears,Coleco,,,1982,2658,Unbelievably Rare,A8K,A2600NTSC,,,ee6665683ebdb539e89ba620981cb0f6, -Bermuda Triangle,Data Age,,,1982,112-007,Rare,,A2600NTSC,,,b8ed78afdb1e6cfe44ef6e3428789d5f, -Bermuda,,,,,SS-009,Extremely Rare,,A2600PAL,,,073d7aff37b7601431e4f742c36c0dc1, -Bermuda,Rainbow Vision,,,,SS-009,Extremely Rare,,A2600PAL,,,cf3c2725f736d4bcb84ad6f42de62a41, -Bermuda,Starsoft,,,,SS-009,Extremely Rare,,A2600PAL,,,bcef7880828a391cf6b50d5a6dcef719, -Berzerk Voice Enhanced,,Dan Hitchens & Mike Mika,Hack,,,,,A2600NTSC,,,be41463cd918daef107d249f8cde3409,http://www.atariage.com/manual_html_page.html?SystemID=2600&SoftwareID=866&ItemTypeID=HTMLMANUAL -Berzerk,Atari,,,,,,,A2600PAL,,,490e3cc59d82f85fae817cdf767ea7a0,http://www.atariage.com/manual_html_page.html?SystemID=2600&SoftwareID=866&ItemTypeID=HTMLMANUAL -Berzerk,Atari,,,,,,,A2600PAL,,,4b205ef73a5779acc5759bde3f6d33ed,http://www.atariage.com/manual_html_page.html?SystemID=2600&SoftwareID=866&ItemTypeID=HTMLMANUAL -Berzerk,Atari,,,1982,CX2650,Common,,A2600NTSC,,,136f75c4dd02c29283752b7e5799f978,http://www.atariage.com/manual_html_page.html?SystemID=2600&SoftwareID=866&ItemTypeID=HTMLMANUAL -Berzerk,Atari,,,1982,CX2650,Common,,A2600PAL,,,0805366f1b165a64b6d4df20d2c39d25,http://www.atariage.com/manual_html_page.html?SystemID=2600&SoftwareID=866&ItemTypeID=HTMLMANUAL -Berzerk,CCE,,,,,,,A2600NTSC,,,fac28963307b6e85082ccd77c88325e7,http://www.atariage.com/manual_html_page.html?SystemID=2600&SoftwareID=866&ItemTypeID=HTMLMANUAL -Better Space Invaders,,Rob Kudla,Hack,1999,,,,A2600NTSC,,,63a7445b1d3046d3cdcdbd488dca38d9, -Betterblast,Mattel,Fabrizio Zavagli,Hack,,,,,A2600NTSC,,,4d5f6db55f7f44fd0253258e810bde21, -Bi! Bi! (a.k.a. Ungeheuer der Tiefe),Starsoft,,,,SS-013,,,A2600PAL,,,1278f74ca1dfaa9122df3eca3c5bcaad, -Big - Move This Demo 2,,,,,,,,A2600NTSC,,,16cc6d1b4ddce51c767a1ba8e5ff196c, -Big - Move This Demo,,,,,,,,A2600NTSC,,,f714a223954c28eccf459295517dcae6, -Big Bird's Egg Catch,Atari,,,1983,CX26104,Rare,,A2600NTSC,Keypad,Keypad,1802cc46b879b229272501998c5de04f, -Big Bird's Egg Catch,Atari,,,1983,CX26104,Rare,,A2600PAL,Keypad,Keypad,f283cc294ece520c2badf9da20cfc025, -Billard,Starsoft,,,,,,,A2600PAL,,,93c9f9239a4e5c956663dd7affa70da2, -Bionic Breakthrough,Atari,,Prototype,,,,,A2600NTSC,Mindlink,Mindlink,f0541d2f7cda5ec7bab6d62b6128b823, -Black Hole,Starsoft,,,,,,,A2600PAL,,,282a77841cb3d33af5b56151acba770e, -Black and White Fast Scolling Demo,,,,,,,,A2600NTSC,,,cbeafd37f15e0dddb0540dbe15c545a4, -Blackjack (32-in-1),Atari,Bob Whitehead,,,,,,A2600PAL,Paddles,Paddles,ff7627207e8aa03730c35c735a82c26c,http://www.atariage.com/manual_html_page.html?SoftwareID=869 -Blackjack,Atari,Bob Whitehead,,1977,,Rare,,A2600PAL,Paddles,Paddles,19a9d3f9fa1b1358fb53009444247aaf,http://www.atariage.com/manual_html_page.html?SoftwareID=869 -Blackjack,Atari,Bob Whitehead,,1977,,Rare,,A2600PAL,Paddles,Paddles,575c0fb61e66a31d982c95c9dea6865c,http://www.atariage.com/manual_html_page.html?SoftwareID=869 -Blackjack,Atari,Bob Whitehead,,1977,,Rare,,A2600PAL,Paddles,Paddles,ff3bd0c684f7144aeaa18758d8281a78,http://www.atariage.com/manual_html_page.html?SoftwareID=869 -Blackjack,Atari,Bob Whitehead,,1977,CX2651,Rare,,A2600NTSC,Paddles,Paddles,0a981c03204ac2b278ba392674682560,http://www.atariage.com/manual_html_page.html?SoftwareID=869 -Blackjack,Atari,Bob Whitehead,,1977,CX2651,Rare,,A2600NTSC,Paddles,Paddles,b2761efb8a11fc59b00a3b9d78022ad6,http://www.atariage.com/manual_html_page.html?SoftwareID=869 -Blair Witch Project,,Tim Snider,Hack,,,,,A2600NTSC,,,93420cc4cb1af1f2175c63e52ec18332, -Blue Dot Demo,,,,,,,,A2600NTSC,,,fcf8e306f6615f74feba5cb25550038c, -Blue and White Sprite Demo,,,,,,,,A2600NTSC,,,dad2ab5f66f98674f12c92abcfbf3a20, -Blueprint,CBS Electronics,,,,4L-2486,Uncommon,,A2600NTSC,,,33d68c3cd74e5bc4cf0df3716c5848bc, -Blueprint,CBS Electronics,,,,4L-2486,Uncommon,,A2600PAL,,,2432f33fd278dea5fe6ae94073627fcc, -Bobby geht nach Hause,Starsoft,,,,,,,A2600PAL,,,48e5c4ae4f2d3b62b35a87bca18dc9f5, -Bobby is Going Home (Brazil),Rentacom,,,,,,,A2600NTSC,,,2f2f9061398a74c80420b99ddecf6448, -Bobby is Going Home,Bitcorp,,,,PG206,Rare,,A2600PAL,,,2823364702595feea24a3fbee138a243, -Bobby is Going Home,CCE,,,,PG206,Rare,,A2600NTSC,,,3cbdf71bb9fd261fbc433717f547d738, -Bobby is Going Home,CCE,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,afe776db50e3378cd6f29c7cdd79104a, -Bogey Blaster,Telegames,,,,5861 A030,Rare,,A2600PAL,,,b438a6aa9d4b9b8f0b2ddb51323b21e4, -Bogey Blaster,Telegames,,,,5861 A030,Rare,,A2600PAL,,,c59633dbebd926c150fb6d30b0576405, -Boing!,,,,,,Extremely Rare,,A2600NTSC,,,14c2548712099c220964d7f044c59fd9, -Boing!,,,,,,New Release,,A2600NTSC,,,0e08cd2c5bcf11c6a7e5a009a7715b6a, -Boing!,,,,,,New Release,,A2600NTSC,,,5d8fb14860c2f198472b233874f6b0c9, -Boing!,First Star Software,,,1983,,,,A2600PAL,,,c471b97446a85304bbac021c57c2cb49, -Boom Bang (a.k.a. Crackpots),Cooper Black,,,,,Extremely Rare,,A2600NTSC,,,a2aae759e4e76f85c8afec3b86529317, -Boom Bang (a.k.a. Kampf dem Steinfresser),Starsoft,,,,,,,A2600PAL,,,73aa02458b413091ac940c0489301710, -Booster by Junkosoft,Junkosoft,,,,,,,A2600NTSC,,,02e3f4ba156fb578bef7d7a0bf3400c1, -Bowling (32-in-1),Atari,,,,,,,A2600PAL,,,f69bb58b815a6bdca548fa4d5e0d5a75,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Bowling,Atari,Larry Kaplan,,1978,CX2628,Common,,A2600NTSC,,,4a1a0509bfc1015273a542dfe2040958,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Bowling,Atari,Larry Kaplan,,1978,CX2628,Common,,A2600NTSC,,,a28d872fc50fa6b64eb35981d0f4bb8d,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Bowling,Atari,Larry Kaplan,,1978,CX2628,Common,,A2600NTSC,,,c9b7afad3bfd922e006a6bfc1d4f3fe7,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Bowling,Atari,Larry Kaplan,,1978,CX2628,Common,,A2600NTSC,,,d4aa6d6095258ce46aaf6f144b09eea7,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Bowling,Atari,Larry Kaplan,,1978,CX2628,Common,,A2600PAL,,,969b968383d9f0e9d8ffd1056bcaef49,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Bowling,Dactar,,,,,,,A2600PAL,,,32ecb5a652eb73d287e883eea751d99c,http://www.atariage.com/manual_thumbs.html?SoftwareID=879 -Boxen,Ariola,,,,,,,A2600PAL,,,7f07cd2e89dda5a3a90d3ab064bfd1f6, -Boxing (32-in-1),Atari,Bob Whitehead,,,,,,A2600PAL,,,2c45c3eb819a797237820a1816c532eb,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Boxing,Activision,Bob Whitehead,,,,,,A2600PAL,,,fd6e507b5df68beeeddeaf696b6828fa,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Boxing,Activision,Bob Whitehead,,1981,AG-002,Uncommon,,A2600NTSC,,,277cca62014fceebb46c549bac25a2e3,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Boxing,Activision,Bob Whitehead,,1981,AG-002,Uncommon,,A2600NTSC,,,88f74ec75ef696e7294b7b6ac5ca465f,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Boxing,Activision,Bob Whitehead,,1981,AG-002,Uncommon,,A2600NTSC,,,c3ef5c4653212088eda54dc91d787870,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Boxing,Activision,Bob Whitehead,,1981,AG-002,Uncommon,,A2600PAL,,,25f2e760cd7f56b88aac88d63757d41b,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Boxing,Dactar,,,,,,,A2600PAL,,,cfb3260c603b0341d49ddfc94051ec10,http://www.atariage.com/manual_thumbs.html?SoftwareID=882 -Brain Games,Atari,Larry Kaplan,,1982,CX2664,Uncommon,,A2600NTSC,Keypad,Keypad,1cca2197d95c5a41f2add49a13738055, -Brain Games,Atari,Larry Kaplan,,1982,CX2664,Uncommon,,A2600NTSC,Keypad,Keypad,cb9626517b440f099c0b6b27ca65142c, -Brain Games,Atari,Larry Kaplan,,1982,CX2664,Uncommon,,A2600PAL,Keypad,Keypad,f280976d69d6e27a48506bd6bad11dcd, -Breakdown (a.k.a. Capture),Dynamics-Goliath,,,,,,,A2600PAL,,,372bddf113d088bc572f94e98d8249f5, -Breaking News,,Ric Pryor,Hack,,,,MN16K,A2600NTSC,,,4dbf47c7f5ac767a3b07843a530d29a5, -Breakout - Breakaway IV,Atari,Brad Stewart & Steve Jobs,,1978,CX2622,Common,,A2600NTSC,Paddles,Paddles,4df6124093ccb4f0b6c26a719f4b7706,http://www.atariage.com/manual_thumbs.html?SoftwareID=889 -Breakout - Breakaway IV,Atari,Brad Stewart & Steve Jobs,,1978,CX2622,Common,,A2600NTSC,Paddles,Paddles,9a25b3cfe2bbb847b66a97282200cca2,http://www.atariage.com/manual_thumbs.html?SoftwareID=889 -Breakout - Breakaway IV,Atari,Brad Stewart & Steve Jobs,,1978,CX2622,Common,,A2600NTSC,Paddles,Paddles,c738fc3f5aae1e8f86f7249f6c82ac81,http://www.atariage.com/manual_thumbs.html?SoftwareID=889 -Breakout - Breakaway IV,Atari,Brad Stewart & Steve Jobs,,1978,CX2622,Common,,A2600NTSC,Paddles,Paddles,f34f08e5eb96e500e851a80be3277a56,http://www.atariage.com/manual_thumbs.html?SoftwareID=889 -Breakout - Breakaway IV,Atari,Brad Stewart & Steve Jobs,,1978,CX2622,Common,,A2600PAL,Paddles,Paddles,6c76fe09aa8b39ee52035e0da6d0808b,http://www.atariage.com/manual_thumbs.html?SoftwareID=889 -Brick Kick,,,,,,,,A2600PAL,,,056ff67dd9715fafa91fb8b0ddcc4a46, -Brick Kick,R.J.P.G.,,,,,Extremely Rare,,A2600NTSC,,,e80a4026d29777c3c7993fbfaee8920f, -Bridge,Activision,Larry Kaplan,,1981,AX-006,Uncommon,,A2600NTSC,,,cfd6a8b23d12b0462baf6a05ef347cd8, -Buck Rogers - Planet of Zoom,Sega,,,1983,005-01,Uncommon,,A2600NTSC,,,1cf59fc7b11cdbcefe931e41641772f6, -Bugs Bunny,Atari,,,,,Prototype,,A2600NTSC,,,fa4404fabc094e3a31fcd7b559cdd029, -Bugs,Data Age,,,1982,DA 1005,Uncommon,,A2600NTSC,,,68597264c8e57ada93be3a5be4565096, -Bump 'N' Jump,Mattel,,,1983,MT7045,Rare,MN16K,A2600NTSC,,,205f4e080db97d3641a780c8c40261ef, -Bump 'N' Jump,Mattel,,,1983,MT7045,Rare,MN16K,A2600NTSC,,,76f53abbbf39a0063f24036d6ee0968a, -Bump 'N' Jump,Telegames,,,,,,MN16K,A2600PAL,,,9295570a141cdec18074c55dc7229d08, -Bumper Bash,Spectravideo,,,1983,,,,A2600NTSC,,,aa1c41f86ec44c0a44eb64c332ce08af, -Bumper Bash,Spectravideo,,,1983,,,,A2600PAL,,,1bf503c724001b09be79c515ecfcbd03, -Burgertime,Mattel,,,1982,MT4518,Rare,MN16K,A2600NTSC,,,0443cfa9872cdb49069186413275fa21, -Burning Desire,Mystique,,,,,Extremely Rare,,A2600NTSC,,,19d6956ff17a959c48fcd8f4706a848d, -Cakewalk,CommaVid,,,,CM-008,Extremely Rare,,A2600NTSC,,,7f6533386644c7d6358f871666c86e79, -Cakewalk,CommaVid,Fabrizio Zavagli,Hack,,,,,A2600PAL,,,0eebfb60d437796d536039701ec43845, -California Games,Epyx,,,1988,8056100286,Rare,A16K,A2600NTSC,,,9ab72d3fd2cc1a0c9adb504502579037, -California Games,Epyx,,,1988,8056100286,Rare,A16K,A2600PAL,,,8068e07b484dfd661158b3771d6621ca, -Candi,,,Hack,,,,,A2600NTSC,,,0e0808227ef41f6825c06f25082c2e56, -Candi,,,Hack,,,,,A2600NTSC,,,85478bb289dfa5c63726b9153992a920, -Canguru (Brazil),Zirok,,,,,,,A2600NTSC,,,6d8a04ee15951480cb7c466e5951eee0, -Canyon Bomber,Atari,David Crane,,1978,CX2607,Uncommon,,A2600NTSC,,,3051b6071cb26377cd428af155e1bfc4, -Canyon Bomber,Atari,David Crane,,1978,CX2607,Uncommon,,A2600NTSC,,,feedcc20bc3ca34851cd5d9e38aa2ca6, -Carnival,CBS Electronics,,,1983,,,,A2600PAL,,,de29e46dbea003c3c09c892d668b9413, -Carnival,CCE,,,,,,,A2600NTSC,,,3d6fc7a19be76d808aa233415cb583fc, -Carnival,Coleco,,,1982,2468,Uncommon,,A2600NTSC,,,028024fb8e5e5f18ea586652f9799c96, -Casino (a.k.a. Poker Plus),Sears,,,1978,CX2652,Uncommon,,A2600NTSC,Paddles,Paddles,b816296311019ab69a21cb9e9e235d12,http://www.atariage.com/manual_thumbs.html?SoftwareID=909 -Casino,Atari,Bob Whitehead,,1978,CX2652,Uncommon,,A2600PAL,Paddles,Paddles,2bc26619e31710a9884c110d8430c1da,http://www.atariage.com/manual_thumbs.html?SoftwareID=909 -Cat Trax,UA,,,,,,,A2600NTSC,,,76f66ce3b83d7a104a899b4b3354a2f2, -Cat Trax,UA,Thomas Jentzsch,Hack,,,,,A2600PAL,,,b7903268e235310dc346a164af4c7022, -Cat and Mouse,,George Veeder,Hack,,,,,A2600NTSC,,,a2de0fc85548871279ed2a3c1325c13e, -Cathouse Blues,Mystique,,,,,Extremely Rare,,A2600NTSC,,,9e192601829f5f5c2d3b51f8ae25dbe5, -Centipede 2k,Eduardo,,Hack,2000,,,A8K,A2600NTSC,,,10958cd0a1a81d599005f1797ab0e51d, -Centipede,Atari,,,1982,CX2676,Common,A8K,A2600NTSC,,,91c2098e88a6b13f977af8c003e0bca5,http://www.atariage.com/manual_thumbs.html?SoftwareID=911 -Centipede,Atari,,,1982,CX2676,Common,A8K,A2600PAL,,,17d000a2882f9fdaa8b4a391ad367f00,http://www.atariage.com/manual_thumbs.html?SoftwareID=911 -Centipede,Atari,,,1984,CX7801,Common,,A7800NTSC,,,5a09946e57dbe30408a8f253a28d07db,http://www.atariage.com/manual_thumbs.html?SoftwareID=2120 -Centipede,Atari,,,1984,CX7801,Common,,A7800PAL,,,38c056a48472d9a9e16ebda5ed91dae7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2120 -Centipede,Atari,,Prototype,1982,,,,A2600PAL,,,2f11ba54609777e2c6a5da9b302c98e8,http://www.atariage.com/manual_thumbs.html?SoftwareID=911 -Challenge of...NEXAR,Spectravideo,,,,SA-206,Rare,,A2600PAL,,,1da2da7974d2ca73a823523f82f517b3, -Challenge of...NEXAR,Spectravideo,,,1982,SA-206,Rare,,A2600NTSC,,,5d799bfa9e1e7b6224877162accada0d, -Challenge of...NEXAR,Spectravideo,,,1982,SA-206,Rare,,A2600PAL,,,3d9c2fccf8b11630762ff00811c19277, -Challenge,Funvision,,,,,Extremely Rare,,A2600PAL,,,9905f9f4706223dadee84f6867ede8e3, -Challenge,Zellers,,,,,,,A2600NTSC,,,73158ea51d77bf521e1369311d26c27b, -Championship Soccer (a.k.a. International Soccer),,,,,MT5687,Uncommon,,A2600NTSC,,,3f6dbf448f25e2bd06dea44248eb122d, -Championship Soccer (a.k.a. Pele's Soccer),,,,,CX2616,Common,,A2600NTSC,,,ace319dc4f76548659876741a6690d57, -Championship Soccer (a.k.a. Pele's Soccer),Atari,,,,CX2616,Common,,A2600PAL,,,7a09299f473105ae1ef3ad6f9f2cd807, -Chase the Chuckwagon,Spectravideo,,,1983,,Unbelievably Rare,,A2600NTSC,,,3e33ac10dcf2dff014bc1decf8a9aea4, -Checkers (32-in-1),Atari,Alan Miller,,,,,,A2600PAL,,,bce93984b920e9b56cf24064f740fe78, -Checkers,Activision,Alan Miller,,1980,AG-003,Extremely Rare,,A2600NTSC,,,3f5a43602f960ede330cd2f43a25139e, -Checkers,Activision,Alan Miller,,1980,AG-003,Extremely Rare,,A2600NTSC,,,7edc8fcb319b3fb61cac87614afd4ffa, -China Syndrome,Spectravideo,,,1982,SA-205,Rare,,A2600NTSC,,,749fec9918160921576f850b2375b516, -Chinese Character Demo,,,,,,,,A2600NTSC,,,36f9a953ebdd9a8be97ccf27a2041903, -Choplifter!,Atari,Dan Gorlin,,1987,CX7821,Common,,A7800NTSC,,,93e4387864b014c155d7c17877990d1e,http://www.atariage.com/manual_thumbs.html?SoftwareID=2121 -Choplifter!,Atari,Dan Gorlin,,1987,CX7821,Common,,A7800PAL,,,59d4edb0230b5acc918b94f6bc94779f,http://www.atariage.com/manual_thumbs.html?SoftwareID=2121 -Chopper Command,Activision,Bob Whitehead,,1982,AX-015,Uncommon,,A2600NTSC,,,25d4be3309b89583c6b39d9f93bf654f,http://www.atariage.com/manual_thumbs.html?SoftwareID=921 -Chopper Command,Activision,Bob Whitehead,,1982,AX-015,Uncommon,,A2600NTSC,,,c1cb228470a87beb5f36e90ac745da26,http://www.atariage.com/manual_thumbs.html?SoftwareID=921 -Chopper Command,Activision,Bob Whitehead,,1982,AX-015,Uncommon,,A2600PAL,,,114c599454d32f74c728a6e1f71012ba,http://www.atariage.com/manual_thumbs.html?SoftwareID=921 -Chopper Command,CCE,Bob Whitehead,,,,,,A2600NTSC,,,85a4133f6dcf4180e36e70ad0fca0921,http://www.atariage.com/manual_thumbs.html?SoftwareID=921 -Chopper Command,Supervision,Bob Whitehead,,,,,,A2600PAL,,,b9f9c0fed0db08c34346317f3957a945,http://www.atariage.com/manual_thumbs.html?SoftwareID=921 -Chuck Norris Superkicks,Xonox,,,,99003,Extremely Rare,,A2600NTSC,,,3f58f972276d1e4e0e09582521ed7a5b, -Circus Atari,Atari,Mike Lorenzen,,1978,CX2630,Common,,A2600NTSC,,,a29df35557f31dfea2e2ae4609c6ebb7,http://www.atariage.com/manual_html_page.html?SoftwareID=927 -Circus Atari,Atari,Mike Lorenzen,,1978,CX2630,Common,,A2600NTSC,Paddles,Paddles,a7b96a8150600b3e800a4689c3ec60a2,http://www.atariage.com/manual_html_page.html?SoftwareID=927 -Circus Atari,Atari,Mike Lorenzen,,1978,CX2630,Common,,A2600PAL,,,30e0ab8be713208ae9a978b34e9e8e8c,http://www.atariage.com/manual_html_page.html?SoftwareID=927 -Climber 5,,Dennis Debro,Prototype,,,,,A2600NTSC,,,d82c8a58098a6b46c5b81c16180354d1, -Coco Nuts,Telesys,,,1982,1001,Rare,,A2600NTSC,,,1e587ca91518a47753a28217cd4fd586, -Codebreaker,Atari,,,1978,CX2643,Uncommon,,A2600NTSC,Keypad,Keypad,5846b1d34c296bf7afc2fa05bbc16e98,http://www.atariage.com/manual_thumbs.html?SoftwareID=931 -Codebreaker,Atari,,,1978,CX2643,Uncommon,,A2600NTSC,Keypad,Keypad,83f50fa0fbae545e4b88bb53b788c341,http://www.atariage.com/manual_thumbs.html?SoftwareID=931 -Codebreaker,Atari,,,1978,CX2643,Uncommon,,A2600PAL,Keypad,Keypad,a47e26096de6f6487bf5dd2d1cced294,http://www.atariage.com/manual_thumbs.html?SoftwareID=931 -Coffee Cup Soccer,,Matthias Jaap,Hack,,,,,A2600NTSC,,,551a64a945d7d6ece81e9c1047acedbc, -Col 'N,HomeVision,,,,554-33391,Extremely Rare,,A2600NTSC,,,4093382187f8387e6d011883e8ea519b, -Color Bar Generator,Videosoft,,Prototype,,VS1008,,,A2600NTSC,,,76a9bf05a6de8418a3ebc7fc254b71b4, -Color Table Display Helper,,,,,,,,A2600NTSC,,,e5a6e0bb7d56e2f08b237e15076e5699, -Color Test,Atari,,,1984,,,,A7800NTSC,,,441ac404cdc7bcbd4d787f911df7bf0d, -Colors Demo,,,,,,,,A2600NTSC,,,3f9431cc8c5e2f220b2ac14bbc8231f4, -Colours Selector,,,,,,,,A2600NTSC,,,9989f974c3cf9c641db6c8a70a2a2267, -Combat (32-in-1),Atari,Joe Decuir,,,,,,A2600PAL,,,0ef64cdbecccb7049752a3de0b7ade14, -Combat - Tank Plus,,,,,CX2601,Common,,A2600NTSC,,,ac05c0e53a5e7009ddd75ed4b99949fc, -Combat - Tank Plus,,,,,CX2601,Common,,A2600NTSC,,,be35d8b37bbc03848a5f020662a99909, -Combat II,Atari,,Prototype,1982,,,,A2600NTSC,,,b0c9cf89a6d4e612524f4fd48b5bb562, -Combat Rock,,,,,,,,A2600NTSC,,,5385cf2a04de1d36ab55c73174b84db0, -Combat Rock,,Paul Slocum,Hack,,,,,A2600NTSC,,,e63efdfda9a4003dcd77a854a781a06a, -Combat,Atari,Joe Decuir,,1977,CX2601,Common,,A2600NTSC,,,4c8832ed387bbafc055320c05205bc08,http://www.atariage.com/manual_thumbs.html?SoftwareID=935 -Combat,Atari,Joe Decuir,,1977,CX2601,Common,,A2600PAL,,,e8aa36e3d49e9bfa654c25dcc19c74e6,http://www.atariage.com/manual_thumbs.html?SoftwareID=935 -Commando Raid,US Games,,,,VC 1004,Rare,,A2600NTSC,,,f457674cef449cfd85f21db2b4f631a7, -Commando Raid,US Games,,,,VC 1004,Rare,,A2600PAL,,,5f316973ffd107f7ab9117e93f50e4bd, -Commando,Activision,Mike Reidel,,1988,,,,A2600PAL,,,de1e9fb700baf8d2e5ae242bffe2dbda, -Commando,Atari,,,1988,,,,A2600NTSC,,,5d2cc33ca798783dee435eb29debf6d6, -Commando,Atari,Dwain Skinner,,1989,CX7838,Scarce,A78SGP,A7800NTSC,,,2e8e28f6ad8b9b9267d518d880c73ebb,http://www.atariage.com/manual_thumbs.html?SoftwareID=2166 -Commando,Atari,Dwain Skinner,,1989,CX7838,Scarce,A78SGP,A7800PAL,,,55da6c6c3974d013f517e725aa60f48e,http://www.atariage.com/manual_thumbs.html?SoftwareID=2166 -CompuMate,Spectravideo & Universum,,,,,,,A2600PAL,,,e7f005ddb6902c648de098511f6ae2e5, -Computer Chess,Atari,,Prototype,,,,,A2600NTSC,,,6a2c68f7a77736ba02c0f21a6ba0985b, -Condor Attack,High-Score Games,,,,,,,A2600PAL,,,e505bd8e59e31aaed20718d47b15c61b, -Condor Attack/Condor Attack/Vulture Attack,CCE/Ultravision/K-Tel Vision,,,,C-851,Extremely Rare,,A2600NTSC,,,1f21666b8f78b65051b7a609f1d48608, -Confrontation,Answer,,,,,,,A2600NTSC,,,f965cc981cbb0822f955641f8d84e774, -Congo Bongo,Sega,,,1983,006-01,Rare,,A2600NTSC,,,00b7b4cbec81570642283e7fc1ef17af, -Console Wars,Greg Thompson,,Hack,,,,,A2600NTSC,,,a81b29177f258494b499fbac69789cef, -Cookie Monster Munch,,,Prototype,,CX26102,,,A2600NTSC,Keypad,Keypad,57c5b351d4de021785cf8ed8191a195c, -Cookie Monster Munch,Atari,,,,CX26102,Rare,,A2600PAL,Keypad,Keypad,a0297c4788f9e91d43e522f4c561b4ad, -Corrida da Matematica,CCE,,,,,,,A2600NTSC,,,01e5c81258860dd82f77339d58bc5f5c, -Cosmic Ark (Star Disable Option),,,,,,,,A2600NTSC,,,7d903411807704e725cf3fafbeb97255,http://www.atariage.com/manual_thumbs.html?SoftwareID=945 -Cosmic Ark,CCE,Rob Fulop,,,,,,A2600NTSC,,,98ef1593624b409b9fb83a1c272a0aa7,http://www.atariage.com/manual_thumbs.html?SoftwareID=945 -Cosmic Ark,Imagic,Rob Fulop,,1982,IA3204,Uncommon,,A2600NTSC,,,ab5bf1ef5e463ad1cbb11b6a33797228,http://www.atariage.com/manual_thumbs.html?SoftwareID=945 -Cosmic Ark,Imagic,Rob Fulop,,1982,IA3204,Uncommon,,A2600PAL,,,0fd72a13b3b6103fc825a692c71963b4,http://www.atariage.com/manual_thumbs.html?SoftwareID=945 -Cosmic Ark,Imagic,Rob Fulop,,1982,IA3204,Uncommon,,A2600PAL,,,72d0acb5de0db662de0360a6fc59334d,http://www.atariage.com/manual_thumbs.html?SoftwareID=945 -Cosmic Avenger,,,,,,,,A2600PAL,,,00ce76ad69cdc2fa36ada01ae092d5a6, -Cosmic Commuter,,Thomas Jentzsch,Hack,,,,,A2600PAL,,,8e879aa58db41edb67cbf318b77766c4, -Cosmic Commuter,Activision,John Van Ryzin,,1984,AG-038,Rare,,A2600NTSC,,,133b56de011d562cbab665968bde352b, -Cosmic Commuter,Activision,John Van Ryzin,,1984,AG-038,Rare,,A2600NTSC,,,ba657d940a11e807ff314bba2c8b389b, -Cosmic Commuter,CCE,John Van Ryzin,,,,,,A2600NTSC,,,5f1b7d5fa73aa071ba0a3c2819511505, -Cosmic Corridor,Zimag,,,,GN-040/708-111,Rare,,A2600NTSC,,,f367e58667a30e7482175809e3cec4d4, -Cosmic Creeps,Telesys,,,1982,1002,Rare,,A2600NTSC,,,3c853d864a1d5534ed0d4b325347f131, -Cosmic Creeps,Telesys,,,1982,1002,Rare,,A2600PAL,,,5835a78a88f97acea38c964980b7dbc6, -Cosmic Swarm (32-in-1),Atari,,,,,,,A2600PAL,,,afe4eefc7d885c277fc0649507fbcd84, -Cosmic Swarm,CommaVid,,,1982,,,,A2600PAL,,,2a2f46b3f4000495239cbdad70f17c59, -Cosmic Swarm,CommaVid,,,1982,,,,A2600PAL,,,36547bc6faa5132b87504e18d088e1d7, -Cosmic Swarm,CommaVid,,,1982,CM-003,Rare,,A2600NTSC,,,9dec0be14d899e1aac4337acef5ab94a, -Cosmic Swarm,CommaVid,,,1982,CM-003,Rare,,A2600NTSC,,,e5f17b3e62a21d0df1ca9aee1aa8c7c5, -Cosmic Town,ITT Family Games,,,,,,,A2600PAL,,,6c91ac51421cb9fc72c9833c4f440d65, -Counter Demo,,,,,,,,A2600NTSC,,,be561b286b6432cac71bccbae68002f7, -Crack'ed,Atari,Rovert Neve,,1988,CX7836,Common,A78SG,A7800NTSC,,,db691469128d9a4217ec7e315930b646,http://www.atariage.com/manual_thumbs.html?SoftwareID=2122 -Crack'ed,Atari,Rovert Neve,,1988,CX7836,Common,A78SG,A7800PAL,,,7cbe78fa06f47ba6516a67a4b003c9ee,http://www.atariage.com/manual_thumbs.html?SoftwareID=2122 -Crackpots,Activision,Dan Kitchen,,,AX-029,Rare,,A2600PAL,,,2825f4d068feba6973e61c84649489fe, -Crackpots,Activision,Dan Kitchen,,,AX-029,Rare,,A2600PAL,,,f3c431930e035a457fe370ed4d230659, -Crackpots,Activision,Dan Kitchen,,1983,AX-029,Rare,,A2600NTSC,,,88ed87c011f699dd27321dbe404db6c8, -Crackpots,Activision,Dan Kitchen,,1983,AX-029,Rare,,A2600NTSC,,,a184846d8904396830951217b47d13d9, -Crackpots,CCE,Dan Kitchen,,,,,,A2600NTSC,,,3f3ad2765c874ca13c015ca6a44a40a1, -Crash Dive,20th Century Fox,,,1983,11031,Extremely Rare,,A2600NTSC,,,fb88c400d602fe759ae74ef1716ee84e, -Crash Dive,20th Century Fox,Fabrizio Zavagli,Hack,,,,,A2600PAL,,,9072c142728a3a3d994956d03bfacba2, -Crazy Brix,,Bob DeCrescenzo,Homebrew,2011,,,A7816,A7800NTSC,,,0c9b124355d5328697a3b9e0011353f2, -Crazy Brix,,Bob DeCrescenzo,Homebrew,2011,,,A7816,A7800NTSC,,,45e1d527becc96d1715e810d1c07ac27, -Crazy Brix,,Bob DeCrescenzo,Homebrew,2011,,,A7816,A7800PAL,,,fc7db1a9243ce2140f716762b8352a5c, -Crazy Climber,,,,,CX2683,Extremely Rare,,A2600NTSC,,,55ef7b65066428367844342ed59f956c,http://www.atariage.com/manual_html_page.html?SoftwareID=954 -Crazy Valet,Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,4a7eee19c2dfb6aeb4d9d0a01d37e127, -Criminal Pursuit,,,,,,Extremely Rare,,A2600NTSC,,,48f18d69799a5f5451a5f0d17876acef, -Cross Force,Spectravision,,,1982,SA-203,Rare,,A2600NTSC,,,c17bdc7d14a36e10837d039f43ee5fa3, -Cross Force,Spectravision,,,1982,SA-203,Rare,,A2600PAL,,,8372eec01a08c60dbed063c5524cdfb1, -Cross Force,Spectravision,,,1982,SA-203,Rare,,A2600PAL,,,8f88309afad108936ca70f8b2b084718, -Crossbow,Atari,,,1987,CX26139,Uncommon,,A2600NTSC,,,8cd26dcf249456fe4aeb8db42d49df74, -Crossbow,Atari,,,1987,CX26139,Uncommon,,A2600PAL,,,7e4783a59972ae2cd8384f231757ea0b, -Crossbow,Atari,,,1988,CX7844,Scarce,A78S9,A7800NTSC,Lightgun,Lightgun,a94e4560b6ad053a1c24e096f1262ebf,http://www.atariage.com/manual_thumbs.html?SoftwareID=2123 -Crossbow,Atari,,,1988,CX7844,Scarce,A78S9,A7800PAL,Lightgun,Lightgun,63db371d67a98daec547b2abd5e7aa95,http://www.atariage.com/manual_thumbs.html?SoftwareID=2123 -Cruise Missile/Radar,Froggo/Zellers,,,1982,FG 1007,Rare,,A2600NTSC,,,74f623833429d35341b7a84bc09793c0, -Crypts of Chaos,20th Century Fox,,,1982,11009,Rare,,A2600NTSC,,,384f5fbf57b5e92ed708935ebf8a8610, -Crystal Castles,Atari,,,1984,CX26110,Uncommon,A16KR,A2600NTSC,,,1c6eb740d3c485766cade566abab8208, -Crystal Castles,Atari,,,1984,CX26110,Uncommon,A16KR,A2600NTSC,,,a6127f470306eed359d85eb4a9cf3c96, -Crystal Castles,Atari,,,1984,CX26110,Uncommon,A16KR,A2600PAL,,,ca7abc774a2fa95014688bc0849eee47, -Crystal Castles,Atari,,Prototype,1984,,,A16KR,A2600NTSC,,,c68a6bafb667bad2f6d020f879be1d11, -Cubicolor,,Rob Fulop,Prototype,,,,,A2600NTSC,,,6fa0ac6943e33637d8e77df14962fbfc, -Cubis (6K),,Eckhard Stolberg,Homebrew,1997,,,,A2600NTSC,,,d2c957dd7746521b51bb09fde25c5774, -Cubis (EM),,Eckhard Stolberg,Homebrew,1997,,,,A2600NTSC,,,281ff9bd0470643853de5cbd6d9e17f5, -Cubis,,Eckhard Stolberg,Homebrew,1997,,,,A2600PAL,,,f74ad642552385c3daa203a2a6fc2291, -Cubo Magico,CCE,,,,,,,A2600NTSC,,,64ca518905311d2d9aeb56273f6caa04, -Custer's Revenge,Mystique,,,,1001,Extremely Rare,,A2600NTSC,,,58513bae774360b96866a07ca0e8fd8e, -Cute Dead Things House,,Christian Samuel,Hack,,,,,A2600NTSC,,,5355f80cacf0e63a49cbf4ade4e27034, -Cybergoth Galaxian,,Manuel Polik,Hack,,,,A8K,A2600NTSC,,,60358edf0c2cc76b1e549e031e50e130, -DUP Space Invaders,,Ron Corcoran,Hack,,,,,A2600NTSC,,,b719ada17771a8d206c7976553825139, -Dancing Baby Demo,,Andrew Davie,,,,,TV8K,A2600NTSC,,,95fd6097dc27c20666f039cfe34f7c69, -Dancing Plate,,,,,,,,A2600PAL,,,f48735115ec302ba8bb2d2f3a442e814, -Dancing Plates,,,,,PG205,Rare,,A2600PAL,,,929e8a84ed50601d9af8c49b0425c7ea, -Dare Diver,Sears,,,1977,99843/75118,Extremely Rare,,A2600NTSC,,,3d8a2d6493123a53ade45e3e2c5cafa0, -Dark Cavern,Mattel,,,1982,MT5667,Uncommon,,A2600NTSC,,,a422194290c64ef9d444da9d6a207807, -Dark Chambers,Atari,,,1988,CX26151,Uncommon,A16KR,A2600NTSC,,,106855474c69d08c8ffa308d47337269, -Dark Chambers,Atari,,,1988,CX26151,Uncommon,A16KR,A2600PAL,,,0d5af65ad3f19558e6f8e29bf2a9d0f8, -Dark Chambers,Atari,,,1988,CX7837,Common,A78SG,A7800NTSC,,,179b76ff729d4849b8f66a502398acae,http://www.atariage.com/manual_thumbs.html?SoftwareID=2124 -Dark Chambers,Atari,,,1988,CX7837,Common,A78SG,A7800PAL,,,a2b8e2f159642c4b91de82e9a2928494,http://www.atariage.com/manual_thumbs.html?SoftwareID=2124 -Dark Mage (4K),,,Homebrew,,,,,A2600NTSC,,,dba270850ae997969a18ee0001675821, -Dark Mage (8K),,,Homebrew,,,,,A2600NTSC,,,6333ef5b5cbb77acd47f558c8b7a95d3, -Dark Mage (SuperCharger),SuperCharger,,Homebrew,,,,,A2600NTSC,,,6cd506509e8fd5627f55603780e862a8, -Dark Mage (final beta),,,Homebrew,,,,,A2600NTSC,,,2b71a59a53be5883399917bf582b7772, -Dark Mage (rough beta),,,Homebrew,,,,,A2600NTSC,,,1345e972dbe08ea3e70850902e20e1a5, -Deadly Duck,20th Century Fox,,,1982,11004,Rare,,A2600NTSC,,,e4c00beb17fdc5881757855f2838c816, -Death Trap,,,,,50010,Unbelievably Rare,,A2600NTSC,,,4e15ddfd48bca4f0bf999240c47b49f5, -Decathlon,Activision,David Crane,,1983,AZ-030,Rare,DC8K,A2600NTSC,,,ac7c2260378975614192ca2bc3d20e0b,http://www.atariage.com/manual_thumbs.html?SoftwareID=967 -Decathlon,Activision,David Crane,,1983,AZ-030,Rare,DC8K,A2600PAL,,,883258dcd68cefc6cd4d40b1185116dc,http://www.atariage.com/manual_thumbs.html?SoftwareID=967 -Defender 2,Atari,,,1984,,,,A2600PAL,,,5f786b67e05fb9985b77d4beb35e06ee,http://www.atariage.com/manual_html_page.html?SoftwareID=971 -Defender 2,Atari,,,1984,CX26120,Rare,A8KR,A2600NTSC,,,3a771876e4b61d42e3a3892ad885d889,http://www.atariage.com/manual_html_page.html?SoftwareID=971 -Defender 2,Atari,,,1984,CX26120,Rare,A8KR,A2600NTSC,,,d1fc4cf675c9b49fb7deb792f2f3a7a5,http://www.atariage.com/manual_html_page.html?SoftwareID=971 -Defender,Atari,Bob Polaro,,1981,,,,A2600PAL,,,047ac3b9faea64522b7a23c4465a7aa8,http://www.atariage.com/manual_html_page.html?SoftwareID=969 -Defender,Atari,Bob Polaro,,1981,CX2609,Common,,A2600NTSC,,,0f643c34e40e3f1daafd9c524d3ffe64,http://www.atariage.com/manual_html_page.html?SoftwareID=969 -Defender,Atari,Bob Polaro,,1981,CX2609,Common,,A2600PAL,,,e4bff1d5df70163c0428a1ead309c22d,http://www.atariage.com/manual_html_page.html?SoftwareID=969 -Defender,CCE,Bob Polaro,,,,,,A2600NTSC,,,808c3b1e60ee0e7c65205fa4bd772221,http://www.atariage.com/manual_html_page.html?SoftwareID=969 -Demolition Herby,Telesys,,,1982,1006,Extremely Rare,,A2600NTSC,,,d09935802d6760ae58253685ff649268, -Demolition Herby,Telesys,,,1982,1006,Extremely Rare,,A2600PAL,,,4a6be79310f86f0bebc7dfcba4d74161, -Demon Attack,Image,Rob Fulop,,1982,,,,A2600NTSC,,,bcb2967b6a9254bcccaf906468a22241,http://www.atariage.com/manual_html_page.html?SoftwareID=974 -Demon Attack,Imagic,Rob Fulop,,1982,,,,A2600PAL,,,442602713cb45b9321ee93c6ea28a5d0,http://www.atariage.com/manual_html_page.html?SoftwareID=974 -Demon Attack,Imagic,Rob Fulop,,1982,IA3200,Common,,A2600NTSC,,,110ac8ecaf1b69f41bc94c59dfcb8b2d,http://www.atariage.com/manual_html_page.html?SoftwareID=974 -Demon Attack,Imagic,Rob Fulop,,1982,IA3200,Common,,A2600NTSC,,,f0e0addc07971561ab80d9abe1b8d333,http://www.atariage.com/manual_html_page.html?SoftwareID=974 -Demon Attack,Imagic,Rob Fulop,,1982,IA3200,Common,,A2600PAL,,,4901c05068512828367fde3fb22199fe,http://www.atariage.com/manual_html_page.html?SoftwareID=974 -Demons to Diamonds,,,,,CX2615,Uncommon,,A2600NTSC,Paddles,Paddles,f91fb8da3223b79f1c9a07b77ebfa0b2, -Demons to Diamonds,Atari,,,,CX2615,Uncommon,,A2600PAL,Paddles,Paddles,d62283aed0f4199adb2333de4c263e9c, -Demons to Diamonds,CCE,,,,,,,A2600NTSC,Paddles,Paddles,bf84f528de44225dd733c0e6a8e400a0, -Demons!,,,,,,,,A2600NTSC,,,698f569eab5a9906eec3bc7c6b3e0980, -Der Geheimkurier,Starsoft,,,,,,,A2600PAL,,,2d16a8b59a225ea551667be45f554652, -Der Vielfrass,Starsoft,,,,,,,A2600PAL,,,313243fc41e49ef6bd3aa9ebc0d372dd, -Der Vielfrass,Starsoft,,,,,,,A2600PAL,,,a1ca372388b6465a693e4626cc98b865, -Der hungrige Panda,Starsoft,,,,,,,A2600PAL,,,82bf0dff20cee6a1ed4bb834b00074e6, -Der kleine Baer,Starsoft,,,,,,,A2600PAL,,,25a21c47afe925a3ca0806876a2b4f3f, -Desert Falcon,Atari,,,1987,CX26140,Common,,A2600NTSC,,,fd4f5536fd80f35c64d365df85873418, -Desert Falcon,Atari,,,1987,CX26140,Common,,A2600PAL,,,d4806775693fcaaa24cf00fc00edcdf3, -Desert Falcon,Atari,,,1987,CX7811,Common,,A7800NTSC,,,95ac811c7d27af0032ba090f28c107bd,http://www.atariage.com/manual_thumbs.html?SoftwareID=2125 -Desert Falcon,Atari,,,1987,CX7811,Common,,A7800PAL,,,2d5d99b993a885b063f9f22ce5e6523d,http://www.atariage.com/manual_thumbs.html?SoftwareID=2125 -Diagnostic Cartridge,,,,,,,,A2600NTSC,,,02ab2c47bc21e7feafa015f90d7df776,http://www.atariage.com/manual_html_page.html?SoftwareID=2354 -Dice Puzzle,Panda,,,,,,,A2600PAL,,,e02156294393818ff872d4314fc2f38e, -Dice Puzzle,Panda,,,,106,Rare,,A2600NTSC,,,9222b25a0875022b412e8da37e7f6887, -Die Ente und der Wolf,Starsoft,,,,,,,A2600PAL,,,72876fd7c7435f41d571f1101fc456ea, -Die Ratte und die Karotten,Starsoft,,,,,,,A2600PAL,,,31df1c50c4351e144c9a378adb8c10ba, -Die Springteufel,Starsoft,,,,,,,A2600PAL,,,3b69f8929373598e1752f43f8da61aa4, -Die Unterwasser-Bestien,Starsoft,,,,,,,A2600PAL,,,6141c095d0aee4e734bebfaac939030a, -Die hungrigen Froesche,Starsoft,,,,,,,A2600PAL,,,834a2273e97aec3181ee127917b4b269, -Dig Dug (Version 1),Atari,,,1983,CX2677,Uncommon,A16KR,A2600PAL,,,977294ae6526c31c7f9a166ee00964ad,http://www.atariage.com/manual_thumbs.html?SoftwareID=982 -Dig Dug (Version 2),Atari,,,1983,CX2677,Uncommon,A16KR,A2600PAL,,,21d2c435bcccde7792d82844b3cf60f4,http://www.atariage.com/manual_thumbs.html?SoftwareID=982 -Dig Dug,Atari,,,1983,CX2677,Uncommon,A16KR,A2600NTSC,,,6dda84fb8e442ecf34241ac0d1d91d69,http://www.atariage.com/manual_thumbs.html?SoftwareID=982 -Dig Dug,Atari,,,1987,CX7803,Common,,A7800NTSC,,,731879ea82fc0ca245e39e036fe293e6,http://www.atariage.com/manual_thumbs.html?SoftwareID=2126 -Dig Dug,Atari,,,1987,CX7803,Common,,A7800PAL,,,408dca9fc40e2b5d805f403fa0509436,http://www.atariage.com/manual_thumbs.html?SoftwareID=2126 -Dishaster,Zimag,,,,,Extremely Rare,,A2600NTSC,,,939ce554f5c0e74cc6e4e62810ec2111, -Dodge 'em,Atari,Carla Meninsky,,,CX2637,Uncommon,,A2600PAL,,,a5e9ed3033fb2836e80aa7a420376788, -Dodge 'em,Atari,Carla Meninsky,,,CX2637,Uncommon,,A2600PAL,,,d28afe0517a046265c418181fa9dd9a1, -Dodge 'em,Atari,Carla Meninsky,,1978,CX2637,Uncommon,,A2600NTSC,,,83bdc819980db99bf89a7f2ed6a2de59, -Dodge 'em,Atari,Carla Meninsky,,1978,CX2637,Uncommon,,A2600NTSC,,,c3472fa98c3b452fa2fd37d1c219fb6f, -Dodge Demo 1,,,,,,,,A2600NTSC,,,bc526185ad324241782dc68ba5d0540b, -Dodge Demo 2,,,,,,,,A2600NTSC,,,5acf9865a72c0ce944979f76ff9610f0, -Dodge Demo 3,,,,,,,,A2600NTSC,,,0c0392db94a20e4d006d885abbe60d8e, -Dodge Demo 4,,,,,,,,A2600NTSC,,,e2b682f6e6d76b35c180c7d847e93b4f, -Dolphin,Activision,Matthew Hubbard,,1983,AX-024,Rare,,A2600NTSC,,,ca09fa7406b7d2aea10d969b6fc90195, -Dolphin,Activision,Matthew Hubbard,,1983,AX-024,Rare,,A2600NTSC,,,d09a7504ee8c8717ac3e24d263e7814d, -Dolphin,CCE,,,,,,,A2600NTSC,,,3889351c6c2100b9f3aef817a7e17a7a, -Domino,Ishido,,Homebrew,,,,,A2600NTSC,,,7ffc2d80fd49a124808315306d19868e, -Domino,Ishido,,Homebrew,,,,,A2600NTSC,,,84d1cf884f029e458db196548db9c2ad, -Donald Duck's Speedboat,Atari,,Prototype,,CX26108,,,A2600NTSC,,,937736d899337036de818391a87271e0, -Donkey Claus,,Philp R. Frey,Hack,,,,,A2600NTSC,,,f473f99e47d4026a7a571184922ebf04, -Donkey Kong Jr.,CCE,,,1983,2653,Rare,,A2600NTSC,,,5a6febb9554483d8c71c86a84a0aa74e, -Donkey Kong Jr.,Coleco,,,1983,,,,A2600PAL,,,2091af29b4e7b86914d79d9aaa4cbd20, -Donkey Kong Jr.,Coleco,,,1983,2653,Rare,,A2600NTSC,,,7fd52208fb6391bae0cd7e68c27bde6f, -Donkey Kong Jr.,Coleco,,,1983,2653,Rare,,A2600NTSC,,,c8fa5d69d9e555eb16068ef87b1c9c45, -Donkey Kong Junior,Atari,,,1988,CX7849,Common,,A7800NTSC,,,5e332fbfc1e0fc74223d2e73271ce650,http://www.atariage.com/manual_thumbs.html?SoftwareID=2128 -Donkey Kong Junior,Atari,,,1988,CX7849,Common,,A7800PAL,,,4dc5f88243250461bd61053b13777060,http://www.atariage.com/manual_thumbs.html?SoftwareID=2128 -Donkey Kong,,,,,2451,Common,,A2600PAL,,,0894aa7be77521f9df562be8d9555fe6,http://www.atariage.com/manual_thumbs.html?SoftwareID=989 -Donkey Kong,,,,,2451,Common,,A2600PAL,,,8b5b1e3a434ebbdc2c2a49dc68f46360,http://www.atariage.com/manual_thumbs.html?SoftwareID=989 -Donkey Kong,Atari,,,1987,CX7848,Common,,A7800NTSC,,,19f1ee292a23636bd57d408b62de79c7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2127 -Donkey Kong,Atari,,,1987,CX7848,Common,,A7800PAL,,,8e96ef14ce9b5d84bcbc996b66d6d4c7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2127 -Donkey Kong,CBS Electronics,,,,,Common,,A2600PAL,,,3a526e6a1f9fe918af0f2ce997dfea73,http://www.atariage.com/manual_thumbs.html?SoftwareID=989 -Donkey Kong,Coleco,,,,2451,Common,,A2600NTSC,,,36b20c427975760cb9cf4a47e41369e4,http://www.atariage.com/manual_thumbs.html?SoftwareID=989 -Doomzerk,Eduardo,,Hack,,,,,A2600NTSC,,,200a9d2a7cb4441ce4f002df6aa47e38, -Double Dragon,Activision,,,1989,AM-050,Rare,A78AC,A7800PAL,,,de2ebafcf0e37aaa9d0e9525a7f4dd62,http://www.atariage.com/manual_thumbs.html?SoftwareID=2167 -Double Dragon,Activision,Dan Kitchen,,1989,,,A16K,A2600PAL,,,3624e5568368929fabb55d7f9df1022e, -Double Dragon,Activision,Dan Kitchen,,1989,AK-050-04,Rare,A16K,A2600PAL,,,47464694e9cce07fdbfd096605bf39d4, -Double Dragon,Activision,Dan Kitchen,,1989,AM-050,Rare,A78AC,A7800NTSC,,,543484c00ba233736bcaba2da20eeea9,http://www.atariage.com/manual_thumbs.html?SoftwareID=2167 -Double Dragon,CCE,Dan Kitchen,,,,,A16K,A2600NTSC,,,4999b45be0ab5a85bac1b7c0e551542b, -Double Dunk,Atari,,,1989,CX26159,Rare,,A2600NTSC,,,368d88a6c071caba60b4f778615aae94, -Double Dunk,Atari,,,1989,CX26159,Rare,,A2600PAL,,,cfc226d04d7490b69e155abd7741e98c, -Dragon Defender,,,,,TP-605,Extremely Rare,,A2600NTSC,,,6a882fb1413912d2ce5cf5fa62cf3875, -Dragon Defender,,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,24d9a55d8f0633e886a1b33ee1e0e797, -Dragonfire,Imagic,Bob Smith,,1982,IA3611,Common,,A2600NTSC,,,41810dd94bd0de1110bedc5092bef5b0,http://www.atariage.com/manual_html_page.html?SoftwareID=995 -Dragonfire,Imagic,Bob Smith,,1982,IA3611,Common,,A2600PAL,,,1267e3c6ca951ff1df6f222c8f813d97,http://www.atariage.com/manual_html_page.html?SoftwareID=995 -Dragonfire,Imagic,Bob Smith,,1982,IA3611,Common,,A2600PAL,,,6fc394dbf21cf541a60e3b3631b817f1,http://www.atariage.com/manual_html_page.html?SoftwareID=995 -Dragster,Activision,David Crane,,1980,AG-001,Uncommon,,A2600NTSC,,,63a6eda1da30446569ac76211d0f861c,http://www.atariage.com/manual_thumbs.html?SoftwareID=997 -Dragster,Activision,David Crane,,1980,AG-001,Uncommon,,A2600NTSC,,,77057d9d14b99e465ea9e29783af0ae3,http://www.atariage.com/manual_thumbs.html?SoftwareID=997 -Dragster,Activision,David Crane,,1980,AG-001,Uncommon,,A2600NTSC,,,d763e3a9cdcdd56c715ec826106fab6a,http://www.atariage.com/manual_thumbs.html?SoftwareID=997 -Dragster,Activision,David Crane,,1980,AG-001,Uncommon,,A2600PAL,,,0c54811cf3b1f1573c9164d5f19eca65,http://www.atariage.com/manual_thumbs.html?SoftwareID=997 -Droid Demo 2,,,,,,,,A2600NTSC,,,2bc6c53b19e0097a242f22375a6a60ff, -Droid Demo 2-M,,,,,,,,A2600NTSC,,,37f42ab50018497114f6b0f4f01aa9a1, -Droid Demo 22,,,,,,,,A2600NTSC,,,bff8f8f53a8aeb1ee804004ccbb08313, -Dschungle Boy (a.k.a. Tom Boy),Starsoft,,,,,Extremely Rare,,A2600PAL,,,de61a0b171e909a5a4cfcf81d146dbcb, -Duck Shoot (Kampf um die Schatzinsel),Starsoft,,,,,,,A2600PAL,,,1bb91bae919ddbd655fa25c54ea6f532, -Dukes of Hazzard V2,Atari,,Prototype,,,,,A2600NTSC,Paddles,Paddles,34ca2fcbc8ba4a0b544acd94991cfb50, -Dukes of Hazzard,Atari,,Prototype,,CX2678,,,A2600NTSC,,,51de328e79d919d7234cf19c1cd77fbc, -Dumbo's Flying Circus,Atari,,Prototype,,CX2678,,,A2600PAL,,,1f773a94d919b2a3c647172bbb97f6b4, -E.T. The Extra-Terrestrial (Pits Hack),,Scott Stilphen,Hack,,,,A8K,A2600NTSC,,,efa1098c7d091b940c2543abe372f036,http://www.atariage.com/manual_html_page.html?SoftwareID=998 -E.T. The Extra-Terrestrial Fixed,,David Richardson,Hack,2013,,,A8K,A2600NTSC,,,b50ae55aac93fbed258bc5a873edd2cb,http://www.atariage.com/manual_html_page.html?SoftwareID=998 -E.T. The Extra-Terrestrial,Atari,Howard Scott Warshaw,,1982,CX2674,Common,A8K,A2600NTSC,,,615a3bf251a38eb6638cdc7ffbde5480,http://www.atariage.com/manual_html_page.html?SoftwareID=998 -E.T. The Extra-Terrestrial,Atari,Howard Scott Warshaw,,1982,CX2674,Common,A8K,A2600PAL,,,8febdd9142960d084ab6eeb1d3e88969,http://www.atariage.com/manual_html_page.html?SoftwareID=998 -E.T. The Extra-Terrestrial,CCE, ,,,,,A8K,A2600NTSC,,,c82ec00335cbb4b74494aecf31608fa1,http://www.atariage.com/manual_html_page.html?SoftwareID=998 -E.T. The Extra-Testical,,Christian Samuel,Hack,,,,A8K,A2600NTSC,,,13abc32f803165c458bb086fa57195fb,http://www.atariage.com/manual_html_page.html?SoftwareID=998 -Earth Attack,Zellers,,,,,,,A2600NTSC,,,6982854657a2cc87d712f718e402bf85, -Earth Dies Screaming,20th Century Fox,,,1983,11020,Rare,,A2600NTSC,,,033e21521e0bf4e54e8816873943406d, -Earth Dies Screaming,20th Century Fox,,,1983,11020,Rare,,A2600PAL,,,2c0dc885d5ede94aa664bf3081add34e, -Eckhard Stolberg's Scrolling Text Demo 2,,Eckhard Stolberg,Homebrew,,,,,A2600NTSC,,,f8bfd99163d2c4ec688357786e6fba28, -Eckhard Stolberg's Scrolling Text Demo 3,,Eckhard Stolberg,Homebrew,,,,,A2600NTSC,,,32e65d1e4dfcbcd9b57fee72cafe074c, -Eckhard Stolberg's Scrolling Text Demo 4,,Eckhard Stolberg,Homebrew,,,,,A2600NTSC,,,3b5751a8d20f7de41eb069f76fecd5d7, -Eckhard Stolberg's Scrolling Text Demo,,Eckhard Stolberg,Homebrew,,,,,A2600NTSC,,,9cbb07f1993a027bc2f87d5205457ec9, -Ed Invaders,,,Hack,,,,,A2600NTSC,,,3e6dab92009d6034618cb6b7844c5216, -Eddy Langfinger - der Museumsdieb,Starsoft,,,,,,,A2600PAL,,,07973be3ecfd55235bf59aa56bdef28c, -Edtris,Ed Federmeyer,,,1994,,Extremely Rare,,A2600NTSC,,,c6d48c6ae6461e0e82753540a985ac9e, -Edtris,Ed Federmeyer,,,1995,,Extremely Rare,,A2600NTSC,,,683dc64ef7316c13ba04ee4398e2b93a, -Egghead,Barry Laws Jr.,,Hack,,,,,A2600NTSC,,,a00ee0aed5c8979add4c170f5322c706, -Eggomania,US Games,,,1982,VC 2003,Rare,,A2600NTSC,Paddles,Paddles,42b2c3b4545f1499a083cfbc4a3b7640, -Eishockey-Fieber,Starsoft,,,,,,,A2600PAL,,,a3f2a0fcf74bbc5fa763b0ee979b05b1, -Elevator Action,Atari,,Prototype,,,,A8KR,A2600NTSC,,,71f8bacfbdca019113f3f0801849057e, -Eli's Ladder,Simage,,,,,Unbelievably Rare,,A2600NTSC,,,b6812eaf87127f043e78f91f2028f9f4, -Elk Attack,,,Homebrew,,,,A8K,A2600NTSC,,,7eafc9827e8d5b1336905939e097aae7, -Encounter at L5,Data Age,,,1982,DA 1001,Uncommon,,A2600NTSC,Paddles,Paddles,dbc8829ef6f12db8f463e30f60af209f, -Enduro (Brazil),Digivision,Larry Miller,,,,,,A2600PAL,,,5df559a36347d8572f9a6e8075a31322,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,Activision,Larry Miller,,1983,AX-026,Uncommon,,A2600NTSC,,,4279485e922b34f127a88904b31ce9fa,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,Activision,Larry Miller,,1983,AX-026,Uncommon,,A2600NTSC,,,94b92a882f6dbaa6993a46e2dcc58402,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,Activision,Larry Miller,,1983,AX-026,Uncommon,,A2600NTSC,,,cfe62ed7125ff9fae99b4c8a367c0399,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,Activision,Larry Miller,,1983,AX-026,Uncommon,,A2600PAL,,,61719a8bdafbd8dab3ca9ce7b171b9e2,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,Activision,Larry Miller,,1983,AX-026,Uncommon,,A2600PAL,,,6a82b8ecc663f371b19076d99f46c598,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,CCE,Larry Miller,,,,,,A2600NTSC,,,de62f8a30298e2325249fe112ecb5c10,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Enduro,Digivision,Larry Miller,,,,,,A2600PAL,,,d2f713c78a9ebba9da6d10aeefc6f20f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1004 -Entombed,US Games,,,1982,VC 2007/VC 1007,Rare,,A2600NTSC,,,6b683be69f92958abe0e2a9945157ad5, -Escape Demo,,,,,,,,A2600NTSC,,,8538c5e3ee83267774480649f83fa8d6, -Espial,,,,1983,,,,A2600NTSC,,,f344ac1279152157d63e64aa39479599, -Espial,Tigervision,,,1983,7-012,Extremely Rare,TV8K,A2600NTSC,,,7e0dc330a32398f980637f9ded8f3ac4, -Espial,Tigervision,,,1983,7-012,Extremely Rare,TV8K,A2600PAL,,,f7a138eed69665b5cd1bfa796a550b01, -Euchre (Aug 31 2002 alpha),,Erik Eid,Homebrew,,,,,A2600NTSC,,,29949f893ef6cb9e8ecb368b9e99eee4, -Euchre (Aug 31 2002 alpha),,Erik Eid,Homebrew,,,,,A2600PAL,,,407a0c6cc0ff777f67b669440d68a242, -Euchre (July 15 2002 pre-release),,Erik Eid,Homebrew,,,,,A2600NTSC,,,15bf2ef7583bfcbbba630847a1dc5539, -Euchre (Sep 28 2002 release candidate),,Erik Eid,Homebrew,,,,,A2600NTSC,,,4690fdb70c86604bb35da26696818667, -Euchre (Sep 28 2002 release candidate),,Erik Eid,Homebrew,,,,,A2600PAL,,,bffe34516aaa3cbf5d307eab382a7e95, -Euchre (Sep 8 2002 beta),,Erik Eid,Homebrew,,,,,A2600NTSC,,,ffb1cd548563158ce33f9d10268187e7, -Euchre (Sep 8 2002 beta),,Erik Eid,Homebrew,,,,,A2600PAL,,,877a5397f3f205bf6750398c98f33de1, -Euchre,,Erik Eid,Homebrew,,,,,A2600NTSC,,,6205855cc848d1f6c4551391b9bfa279, -Euchre,,Erik Eid,Homebrew,,,,,A2600PAL,,,199985cae1c0123ab1aef921daace8be, -Excalibur 39,,,,,,,,A2600NTSC,,,34303a7d4c9ad4500ca7f2ede9709595, -Excalibur Demo,,,,,,,,A2600NTSC,,,bfb7850e3ca39f417f8e4bd5ae39f24b, -Exocet (a.k.a. Space Eagle),Panda,,,,109,Rare,,A2600NTSC,,,6362396c8344eec3e86731a700b13abf, -Exocet (a.k.a. Space Eagle),Sancho-Goliath,,,,,,,A2600PAL,,,7ac4f4fb425db38288fa07fb8ff4b21d, -Exorcise,,,Hack,,,,,A2600NTSC,,,295f3679bdf91ca5e37da3f787b29997, -F-18 Hornet,Absolute,John Van Ryzin,,1988,AP-044,Scarce,A78AB,A7800NTSC,,,2251a6a0f3aec84cc0aff66fc9fa91e8,http://www.atariage.com/manual_thumbs.html?SoftwareID=2129 -F-18 Hornet,Absolute,John Van Ryzin,,1988,AP-044,Scarce,A78AB,A7800PAL,,,e7709da8e49d3767301947a0a0b9d2e6,http://www.atariage.com/manual_thumbs.html?SoftwareID=2129 -Face Invaders 2,,Barry Laws Jr.,Hack,,,,,A2600NTSC,,,7926083ad423ed685de3b3a04a914315, -Face Invaders Deluxe,,Barry Laws Jr.,Hack,,,,,A2600NTSC,,,0af51ceb4aecc7a8fc89781ac44a1973, -FailSafe,,Bob DeCrescenzo,Homebrew,2009,,,A7848,A7800NTSC,,,6287727ab36391a62f728bbdee88675c, -FailSafe,,Bob DeCrescenzo,Homebrew,2009,,,A7848,A7800NTSC,,,d2bb22f704f1610a4c396c51f5188e15, -Fantastic Voyage,20th Century Fox,,,1982,11008,Rare,,A2600NTSC,,,b80d50ecee73919a507498d0a4d922ae, -Farmyard Fun,,,,,TP-617,Extremely Rare,,A2600NTSC,,,f7e07080ed8396b68f2e5788a5c245e2, -Fast Eddie,,,,,,,,A2600PAL,,,67631ea5cfe44066a1e76ddcb6bcb512, -Fast Eddie,20th Century Fox,,,1982,11003,Uncommon,,A2600NTSC,,,9de0d45731f90a0a922ab09228510393, -Fast Eddie,20th Century Fox,,,1983,,,,A2600NTSC,,,cb8bf5a0df683cbf6ce50d614b12dd20, -Fast Eddie,CCE,,,,,,,A2600NTSC,,,a97733b0852ee3096300102cb0689175, -Fast Food (Brazil),Zirok,,,,,,,A2600NTSC,,,6b7e1c11448c4d3f28160d2de884ebc8, -Fast Food,Telesys,,,1982,1003,Rare,,A2600NTSC,,,665b8f8ead0eef220ed53886fbd61ec9, -Fat Albert,,David Marli,Hack,,,,,A2600NTSC,,,63e783994df824caf289b69a084cbf3e, -Fatal Run,Atari,,,1989,CX7854,Rare,A78SG,A7800NTSC,,,d25d5d19188e9f149977c49eb0367cd1,http://www.atariage.com/manual_thumbs.html?SoftwareID=2168 -Fatal Run,Atari,,,1989,CX7854,Rare,A78SG,A7800PAL,,,23505651ac2e47f3637152066c3aa62f,http://www.atariage.com/manual_thumbs.html?SoftwareID=2168 -Fatal Run,Atari,,,1990,CX26162,Unbelievably Rare,A32KR,A2600PAL,,,074ec425ec20579e64a7ded592155d48, -Fatal Run,Atari,Thomas Jentzsch,Hack,,,,A32KR,A2600NTSC,,,ef263d40a23483ab339cac44d9515a56, -Fathom,Imagic,Rob Fulop,,1983,O3205,Rare,,A2600NTSC,,,0b55399cf640a2a00ba72dd155a0c140, -Fathom,Imagic,Rob Fulop,,1983,O3205,Rare,,A2600NTSC,,,b442887aec0b4a725996d53f34787b14, -Fathom,Imagic,Rob Fulop,,1983,O3205,Rare,,A2600PAL,,,47cd61f83457a0890de381e478f5cf5f, -Felix Return,Goliath,,,,,,,A2600PAL,,,ce243747bf34a2de366f846b3f4ca772, -Festival,,,,,,,,A2600PAL,,,540075f657d4b244a1f74da1b9e4bf92, -Feuerwehr im Einsatz,Starsoft,,,,,,,A2600PAL,,,8e737a88a566cc94bd50174c2d019593, -Fight Night,Atari,,,1987,CX7851,Scarce,A78SG,A7800PAL,,,e80f24e953563e6b61556737d67d3836,http://www.atariage.com/manual_thumbs.html?SoftwareID=2130 -Fight Night,Atari,,,1988,CX7851,Scarce,A78SG,A7800NTSC,,,07dbbfe612a0a28e283c01545e59f25e,http://www.atariage.com/manual_thumbs.html?SoftwareID=2130 -Final Approach,Apollo,,,1982,AP 2009,Rare,,A2600NTSC,,,211fbbdbbca1102dc5b43dc8157c09b3, -Fire Bird,Video Game Program,,,,,,,A2600PAL,,,51e390424f20e468d2b480030ce95d7b, -Fire Birds (a.k.a. Scorpion),ITT Family Games,,,,554-33383,Extremely Rare,,A2600PAL,,,01e60a109a6a67c70d3c0528381d0187, -Fire Fighter,Imagic,Brad Stewart,,1982,IA3400,Rare,,A2600NTSC,,,d09f1830fb316515b90694c45728d702, -Fire Fighter,Imagic,Brad Stewart,,1982,IA3400,Rare,,A2600PAL,,,90d77e966793754ab4312c47b42900b1, -Fire Fly,Mythicon,,,1983,MA-1002,Uncommon,,A2600NTSC,,,20dca534b997bf607d658e77fbb3c0ee, -Fire Spinner,,,,,,,,A2600NTSC,,,d3171407c3a8bb401a3a62eb578f48fb, -Fire Spinner,,,,,,,,A2600PAL,,,98555b95cb38e0e0b22b482b2b60a5b6, -Fisher Price,CCE,,,,,,,A2600PAL,,,3fe43915e5655cf69485364e9f464097, -Fishing Derby (32-in-1),Atari,David Crane,,,,,,A2600PAL,,,7628d3cadeee0fd2e41e68b3b8fbe229,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,,1980,,,,A2600PAL,,,1d2a28eb8c95da0d6d6b18294211839f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,,1980,,,,A2600PAL,,,458883f1d952cd772cf0057abca57497,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,,1980,AG-004,Uncommon,,A2600NTSC,,,3c82e808fe0e6a006dc0c4e714d36209,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,,1980,AG-004,Uncommon,,A2600NTSC,,,85227160f37aaa29f5e3a6c7a3219f54,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,,1980,AG-004,Uncommon,,A2600NTSC,,,b8865f05676e64f3bec72b9defdacfa7,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,,1980,AG-004,Uncommon,,A2600PAL,,,571c6d9bc71cb97617422851f787f8fe,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,Activision,David Crane,Hack,1980,,,,A2600PAL,,,2517827950fee41a3b9de60275c8aa6a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Fishing Derby,CCE,David Crane,,,,,,A2600NTSC,,,dea0ade296f7093e71185e802b500db8,http://www.atariage.com/manual_thumbs.html?SoftwareID=1021 -Flag Capture (32-in-1),Atari,Jim Huether,,,,,,A2600PAL,,,f5445b52999e229e3789c39e7ee99947,http://www.atariage.com/manual_thumbs.html?SoftwareID=1022 -Flag Capture,Atari,Jim Huether,,1978,CX2644,Uncommon,,A2600NTSC,,,30512e0e83903fc05541d2f6a6a62654,http://www.atariage.com/manual_thumbs.html?SoftwareID=1022 -Flag Capture,Atari,Jim Huether,,1978,CX2644,Uncommon,,A2600NTSC,,,4b143d7dcf6c96796c37090cba045f4f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1022 -Flash Gordon,20th Century Fox,,,1983,11015,Rare,,A2600PAL,,,4ae8c76cd6f24a2e181ae874d4d2aa3d, -Flash Gordon/Space Adventure,20th Century Fox/Zellers,,,1983,11015,Rare,,A2600NTSC,,,8786c1e56ef221d946c64f6b65b697e9, -Flippern,Starsoft,,,,,,,A2600PAL,,,5a2f2dcd775207536d9299e768bcd2df, -Food Fight,Atari,,,1987,CX7804,Common,,A7800NTSC,,,cf76b00244105b8e03cdc37677ec1073,http://www.atariage.com/manual_thumbs.html?SoftwareID=2131 -Food Fight,Atari,,,1987,CX7804,Common,,A7800PAL,,,de0d4f5a9bf1c1bddee3ed2f7ec51209,http://www.atariage.com/manual_thumbs.html?SoftwareID=2131 -Football (32-in-1),Atari,Bob Whitehead,,,,,,A2600PAL,,,7608abdfd9b26f4a0ecec18b232bea54,http://www.atariage.com/manual_thumbs.html?SoftwareID=1024 -Football (a.k.a. Fussball),Ariola,,,,MT5687,Uncommon,,A2600PAL,,,cd568d6acb2f14477ebf7e59fb382292,http://www.atariage.com/manual_thumbs.html?SoftwareID=1024 -Football,Atari,Bob Whitehead,,1978,CX2625,Common,,A2600NTSC,,,d86deb100c6abed1588aa84b2f7b3a98,http://www.atariage.com/manual_thumbs.html?SoftwareID=1024 -Football,Atari,Bob Whitehead,,1978,CX2625,Common,,A2600NTSC,,,e549f1178e038fa88dc6d657dc441146,http://www.atariage.com/manual_thumbs.html?SoftwareID=1024 -Forest,Sancho,,,,,Extremely Rare,,A2600PAL,,,213e5e82ecb42af237cfed8612c128ac, -Fox & Goat,Starsoft,,,,,,,A2600PAL,,,76ee917d817ef9a654bc4783e0273ac4, -Fox & Goat,Starsoft,,,,,,,A2600PAL,,,9ed0f2aa226c34d4f55f661442e8f22a, -Frame Timed Sound Effects,,Eckhard Stolberg,,,,New Release,,A2600NTSC,,,8290daea8391f96d7c8e1482e184d19c, -Frame Timed Sound Effects-EM,,Eckhard Stolberg,,,,New Release,,A2600NTSC,,,442b7863683e5f084716fda050474feb, -Frankenstein's Monster,Data Age,,,1982,112-008,Rare,,A2600NTSC,,,15dd21c2608e0d7d9f54c0d3f08cca1f, -Freeway (32-in-1),Atari,David Crane,,,,,,A2600PAL,,,914a8feaf6d0a1bbed9eb61d33817679,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway (a.k.a. Rabbits),,,,,,,,A2600PAL,,,481d20ec22e7a63e818d5ef9679d548b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway,Activision,David Crane,,1981,AG-009,Uncommon,,A2600NTSC,,,69974dd5d6420b90898cde50aec5ef39,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway,Activision,David Crane,,1981,AG-009,Uncommon,,A2600NTSC,,,851cc1f3c64eaedd10361ea26345acea,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway,Activision,David Crane,,1981,AG-009,Uncommon,,A2600NTSC,,,8e0ab801b1705a740b476b7f588c6d16,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway,Activision,David Crane,,1981,AG-009,Uncommon,,A2600PAL,,,2ec6b045cfd7bc52d9cdfd1b1447d1e5,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway,CCE,David Crane,,,AG-009,Uncommon,,A2600NTSC,,,eddef10fdc0029301064115ae0cd41d4,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Freeway,Dactar,David Crane,,,,,,A2600PAL,,,7d5c3b7b908752b98e30690e2a3322c2,http://www.atariage.com/manual_thumbs.html?SoftwareID=1031 -Frog Pond,Atari,,Prototype,,CX2665,,,A2600NTSC,,,5f73e7175474c1c22fb8030c3158e9b3, -Frogger Demo,,Matthias Luedtke & Manuel Polik,Homebrew Hack,2005,,,,A7800NTSC,,,45136d1d9eddf0bebad32995647b3298, -Frogger II - Threedeep!,Parker Bros,,,1983,PB5590,Extremely Rare,PB8K,A2600NTSC,,,27c6a2ca16ad7d814626ceea62fa8fb4, -Frogger,Parker Bros,,,1983,PB5300,Common,,A2600NTSC,,,081e2c114c9c20b61acf25fc95c71bf4,http://www.atariage.com/manual_html_page.html?SoftwareID=1033 -Frogger,Parker Bros,,,1983,PB5300,Common,,A2600PAL,,,02ced7ea2b7cb509748db6bfa227ebec,http://www.atariage.com/manual_html_page.html?SoftwareID=1033 -Frogs and Flies,Mattel,,,1982,MT5664,Uncommon,,A2600NTSC,,,dcc2956c7a39fdbf1e861fc5c595da0d, -Frogs and Flies,Mattel,,,1982,MT5664,Uncommon,,A2600PAL,,,1b8c3c0bfb815b2a1010bba95998b66e, -Frontline,Coleco,,,,2665,Rare,,A2600NTSC,,,e556e07cc06c803f2955986f53ef63ed, -Frostbite (Brazil),Digitel,,,,,,,A2600PAL,,,f4469178cd8998cb437fa110a228eaca, -Frostbite,,,,,AX-031,Rare,,A2600PAL,,,70ce036e59be92821c4c7fd735ec6f68, -Frostbite,Activision,Steve Miller,,,AX-031,Rare,,A2600PAL,,,6a9b30ca46b0dba9e719f4cbd340e01c, -Frostbite,Activision,Steve Miller,,,AX-031,Rare,,A2600PAL,,,6b71f20c857574b732e7a8e840bd3cb2, -Frostbite,Activision,Steve Miller,,1983,AX-031,Rare,,A2600NTSC,,,4ca73eb959299471788f0b685c3ba0b5, -Frostbite,Activision,Steve Miller,,1983,AX-031,Rare,,A2600PAL,,,5a93265095146458df2baf2162014889, -Frostbite,CCE,Steve Miller,,,,,,A2600NTSC,,,c6ae21caceaad734987cb24243793bd5, -Frostbite,Digivision,,,,,,,A2600PAL,,,adb79f9ac1a633cdd44954e2eac14774, -Fuchs & Schweinchen Schlau,Starsoft,,,,,,,A2600PAL,,,0de53160a8b54c3aa5aed8d68c970b62, -Fun With Numbers,Atari,,,,CX2661,Uncommon,,A2600NTSC,,,819aeeb9a2e11deb54e6de334f843894, -Fun with Numbers (32-in-1),Atari,,,,,,,A2600PAL,,,d816fea559b47f9a672604df06f9d2e3, -Fun with Numbers,Atari,,,,CX2661,Uncommon,,A2600PAL,,,5f46d1ff6d7cdeb4b09c39d04dfd50a1, -G.I. Joe - Cobra Strike,Parker Bros,,,1983,PB5920,Uncommon,,A2600NTSC,Paddles,Paddles,c1fdd44efda916414be3527a47752c75, -GREGXM Demo,,,,,,,,A2600NTSC,,,a3b9d2be822eab07e7f4b10593fb5eaa, -Galactic (G),Funvision,,,,,,,A2600PAL,,,13a991bc9c2ff03753aeb322d3e3e2e5, -Galactic (G),Funvision,,,,,,,A2600PAL,,,b49331b237c8f11d5f36fe2054a7b92b, -Galaga (River Raid clone),,,,,,,,A2600PAL,,,01b09872dcd9556427761f0ed64aa42a, -Galaga,Atari,,,1987,CX7805,Common,,A7800NTSC,,,fb8d803b328b2e442548f7799cfa9a4a,http://www.atariage.com/manual_thumbs.html?SoftwareID=2132 -Galaga,Atari,,,1987,CX7805,Common,,A7800PAL,,,f5dc7dc8e38072d3d65bd90a660148ce,http://www.atariage.com/manual_thumbs.html?SoftwareID=2132 -Galaxian (Enhanced Graphics),,Jess Ragan,Hack,,,,A8K,A2600NTSC,,,579baa6a4aa44f035d245908ea7a044d, -Galaxian,Atari,,,,CX2684,Uncommon,A8K,A2600NTSC,,,211774f4c5739042618be8ff67351177, -Galaxian,Atari,,,,CX2684,Uncommon,A8K,A2600PAL,,,13a37cf8170a3a34ce311b89bde82032, -Galaxian,CCE,,,,,,A8K,A2600NTSC,,,d65028524761ef52fbbdebab46f79d0f, -Game of Concentration,,,,,CX2642,Uncommon,,A2600NTSC,Keypad,Keypad,102672bbd7e25cd79f4384dd7214c32b, -Game of Concentration,,,,,CX2642,Uncommon,,A2600NTSC,Keypad,Keypad,31f4692ee2ca07a7ce1f7a6a1dab4ac9, -Gangster Alley,Spectravideo,,,1983,SA-201,Rare,,A2600PAL,,,47aad247cce2534fd70c412cb483c7e0, -Gangster Alley,Spectravideo,,,1983,SA-201,Rare,,A2600PAL,,,bae66907c3200bc63592efe5a9a69dbb, -Gangster Alley,Spectravision,,,1982,SA-201,Rare,,A2600NTSC,,,20edcc3aa6c189259fa7e2f044a99c49, -Gangster,Ariola,,,,,,,A2600PAL,,,a7523db9a33e9417637be0e71fa4377c, -Garfield,,,Prototype,,CX26132,,A16K,A2600NTSC,,,dc13df8420ec69841a7c51e41b9fbba5, -Gas Hog (a.k.a. Marspatrouille),Spectravideo,,,1983,SA-217,Extremely Rare,,A2600PAL,,,b1486e12de717013376447ac6f7f3a80, -Gas Hog,Spectravideo,,,1983,SA-217,Extremely Rare,,A2600NTSC,,,728152f5ae6fdd0d3a9b88709bee6c7a, -Gato,Atari,,Prototype,,,,,A7800NTSC,,,06204dadc975be5e5e37e7cc66f984cf, -Gauntlet,,,,,ASC1002,Unbelievably Rare,,A2600NTSC,,,e64a8008812327853877a37befeb6465, -Gefaehrliche Maeusejagt,Starsoft,,,,,,,A2600PAL,,,f802fa61011dd9eb6f80b271bac479d0, -Gefecht im All,Starsoft,,,,,,,A2600PAL,,,e784a9d26707cfcd170a4c1c60422a72, -General Retreat,Playaround,,,,,,,A2600PAL,,,7e464186ba384069582d9f0c141f7491, -Ghost Manor,Xonox,,,1983,99002,Extremely Rare,,A2600NTSC,,,0eecb5f58f55de9db4eedb3a0f6b74a8, -Ghost Manor,Xonox,,,1983,99002,Extremely Rare,,A2600NTSC,,,2bee7f226d506c217163bad4ab1768c0, -Ghost Manor,Xonox,,,1983,99002,Extremely Rare,,A2600PAL,,,40d8ed6a5106245aa79f05642a961485, -Ghostbusters II (Version 2),,,,,,,,A2600NTSC,,,643e6451eb6b8ab793eb60ba9c02e000, -Ghostbusters II,Salu,,,1992,,Extremely Rare,,A2600PAL,,,c2b5c50ccb59816867036d7cf730bf75, -Ghostbusters II,Salu,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,718ee85ea7ec27d5bea60d11f6d40030, -Ghostbusters,Activision,David Crane & Dan Kitchen,,,AZ-108-04,Rare,,A2600NTSC,,,e314b42761cd13c03def744b4afc7b1b,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=209 -Ghostbusters,Activision,David Crane & Dan Kitchen,,,AZ-108-04,Rare,,A2600PAL,,,f7d6592dcb773c81c278140ed4d01669,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=209 -Gigolo,Mystique,,,,1009,Extremely Rare,,A2600NTSC,,,1c8c42d1aee5010b30e7f1992d69216e, -Glacier Patrol,,,,,5667 A106,Rare,,A2600NTSC,,,5e0c37f534ab5ccc4661768e2ddf0162, -Glib (Selchow Righter),Selchow,,,,87,Unbelievably Rare,,A2600NTSC,,,2d9e5d8d083b6367eda880e80dfdfaeb, -Glorb,,,Hack,,,,,A2600NTSC,,,72db1194b1cc7d45b242f25eb1c148d3, -Golf (32-in-1),Atari,,,,,,,A2600PAL,,,95351b46fa9c45471d852d28b9b4e00b, -Golf,Atari,,,1978,CX2634,Common,,A2600NTSC,,,2e663eaa0d6b723b645e643750b942fd, -Golf,Atari,,,1978,CX2634,Common,,A2600NTSC,,,f542b5d0193a3959b54f3c4c803ba242, -Golf,Atari,,,1978,CX2634,Common,,A2600PAL,,,9d522a3759aa855668e75962c84546f7, -Gopher,Carrere Video,,,1982,,,,A2600PAL,,,a56b642a3d3ab9bbeee63cd44eb73216, -Gopher,US Games,,,1982,,,,A2600PAL,,,06db908011065e5ebb37f4e253c2a0b0, -Gopher,US Games,,,1982,VC 2001,Rare,,A2600NTSC,,,c16c79aad6272baffb8aae9a7fff0864, -Gorf,CBS Electronics,,,,M8793,Uncommon,,A2600NTSC,,,81b3bf17cf01039d311b4cd738ae608e, -Gorf,CBS Electronics,,,,M8793,Uncommon,,A2600PAL,,,3e03086da53ecc29d855d8edf10962cb, -Gorilla Kong,,,Hack,,,,,A2600NTSC,,,98ba601a60172cb46c5bf9a962fd5b1f, -Grand Prix,Activision,David Crane,,1982,AX-014,Uncommon,,A2600NTSC,,,2903896d88a341511586d69fcfc20f7d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1062 -Grand Prix,Activision,David Crane,,1982,AX-014,Uncommon,,A2600PAL,,,757f529026696e13838364dea382a4ed,http://www.atariage.com/manual_thumbs.html?SoftwareID=1062 -Grand Prix,Activision,David Crane,,1982,AX-014,Uncommon,A4K,A2600NTSC,,,de4436eaa41e5d7b7609512632b90078,http://www.atariage.com/manual_thumbs.html?SoftwareID=1062 -Grand Prix,CCE,David Crane,,,,,,A2600NTSC,,,41c4e3d45a06df9d21b7aae6ae7e9912,http://www.atariage.com/manual_thumbs.html?SoftwareID=1062 -Gravitar,,,,,CX2685,Uncommon,A8K,A2600NTSC,,,8ac18076d01a6b63acf6e2cab4968940, -Gravitar,Atari,,,,CX2685,Uncommon,A8K,A2600NTSC,,,7146dd477e019f81eac654a79be96cb5, -Gravitar,CCE,,,,,,A8K,A2600NTSC,,,a81697b0c8bbc338ae4d0046ede0646b, -Great Escape,Bomb,,,,CA282,Extremely Rare,,A2600NTSC,,,18f299edb5ba709a64c80c8c9cec24f2, -Green Bar Text Demo,,,,,,,,A2600NTSC,,,ed014beeeb77dbb2bbcf9b5f6850b2f4, -Green and Yellow Number 1 Demo 2,,,,,,,,A2600NTSC,,,b41fdd4a522e1d5a2721840028684ac2, -Green and Yellow Number 1 Demo,,,,,,,,A2600NTSC,,,abc64037ca5d5b04ae8a7eedbca3ed74, -Gremlins,Atari,,,1984,CX26127,Extremely Rare,,A2600NTSC,,,01cb3e8dfab7203a9c62ba3b94b4e59f, -Grid Demo,,,,,,,,A2600NTSC,,,9962034ea7b3d4a905d0991804670087, -Grid and Purple Dot Demo,,,,,,,,A2600NTSC,,,d65900fefa7dc18ac3ad99c213e2fa4e, -Ground Zero,Rainbow Vision,,,,,,,A2600PAL,,,eb46e99ec15858f8cd8c91cef384ce09, -Grover's Music Maker,Atari,,Prototype,,CX26106,,,A2600NTSC,Keypad,Keypad,4ac9f40ddfcf194bd8732a75b3f2f214, -Guardian,Apollo,,,1982,AP 2008,Rare,,A2600NTSC,Paddles,Paddles,7ab2f190d4e59e8742e76a6e870b567e, -Gunfight (0.01),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,14a56b493a8d9d10e94a3e100362e3a2, -Gunfight (0.02),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,111029770226b319524134193886a10e, -Gunfight (0.03),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,d17a671029b1532b197defca5f3649a7, -Gunfight (0.04),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,801ba40f3290fc413e8c816c467c765c, -Gunfight (0.05),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,c21450c21efb7715746e9fa87ad6f145, -Gunfight (0.06),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,24759be31e8fe55d2829fd86bdf3181f, -Gunfight (0.07),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,68c80e7e1d30df98a0cf67ecbf39cc67, -Gunfight (0.07a),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,a025a8f83a42a4d6d46c4887e799bfac, -Gunfight (0.08),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,a15b5831a1fab52e4c416068c85ec011, -Gunfight (0.09),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,9853089672116117258097dbbdb939b7, -Gunfight,,Manuel Polik,Homebrew,,,,,A2600NTSC,,,f750b5d613796963acecab1690f554ae, -Gunfight,,Manuel Polik,Homebrew,,,,,A2600PAL,,,18b28b386abdadb3a700ac8fb68e639a, -Gyruss,Parker Bros,,,1984,PB5080,Rare,PB8K,A2600NTSC,,,2f273c423471d125d32d1d54d58f063a, -Gyruss,Parker Bros,,,1984,PB5080,Rare,PB8K,A2600NTSC,,,b311ab95e85bc0162308390728a7361d, -H.E.R.O.,Activision,John Van Ryzin,,1984,AZ-036-04,Rare,A8K,A2600NTSC,,,c8df076c7e4349ca8dcbdb773bf3c985,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=228 -H.E.R.O.,Activision,John Van Ryzin,,1984,AZ-036-04,Rare,A8K,A2600NTSC,,,fca4a5be1251927027f2c24774a02160,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=228 -H.E.R.O.,Activision,John Van Ryzin,,1984,AZ-036-04,Rare,A8K,A2600PAL,,,48bcf2c5a8c80f18b24c55db96845472,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=228 -H.E.R.O.,Activision,John Van Ryzin,,1984,AZ-036-04,Rare,A8K,A2600PAL,,,66b92ede655b73b402ecd1f4d8cd9c50,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=228 -H.E.R.O.,Activision,John Van Ryzin,,1984,AZ-036-04,Rare,A8K,A2600PAL,,,d9b49f0678776e04916fa5478685a819,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=228 -H.E.R.O.,CCE,John Van Ryzin,,,,,A8K,A2600NTSC,,,1d284d6a3f850bafb25635a12b316f3d,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=228 -Halloween (a.k.a. Sexta Fiera 13),Wizard Video,,,,7,Extremely Rare,,A2600NTSC,,,30516cfbaa1bc3b5335ee53ad811f17a, -Halloween (a.k.a. Sexta Fiera 13),Wizard Video,,,,7,Extremely Rare,,A2600NTSC,,,c450a285daa7a3b65188c2c3cf04fb3e, -Hangman,Atari,Alan Miller,,1978,CX2662,Uncommon,,A2600NTSC,,,f16c709df0a6c52f47ff52b9d95b7d8d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1073 -Harbor Escape,Panda,,,1983,110,Rare,,A2600NTSC,,,b9232c1de494875efe1858fc8390616d, -Hat Trick,Atari,,,1987,CX7829,Common,,A7800PAL,,,0baec96787ce17f390e204de1a136e59,http://www.atariage.com/manual_thumbs.html?SoftwareID=2133 -Hat Trick,Atari,,Prototype,1987,CX7829,,,A7800NTSC,,,fd9e78e201b6baafddfd3e1fbfe6ba31,http://www.atariage.com/manual_thumbs.html?SoftwareID=2133 -Haunted House,Atari,,,,CX2654,Common,,A2600NTSC,,,f0a6e99f5875891246c3dbecbf2d2cea,http://www.atariage.com/manual_html_page.html?SoftwareID=1076 -Haunted House,Atari,,,,CX2654,Common,,A2600PAL,,,09e1ecf9bd2a3030d5670dba7a65e78d,http://www.atariage.com/manual_html_page.html?SoftwareID=1076 -Hell Driver,ITT Family Games,,,,,,,A2600PAL,,,aab840db22075aa0f6a6b83a597f8890, -Hell Driver,ITT Family Games,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,260c787e8925bf3649c8aeae5b97dcc0, -Hili Ball,Starsoft,,,,,,,A2600PAL,,,8fe00172e7fff4c1878dabcf11bb8dce, -Hili Ball,Starsoft,,,,,,,A2600PAL,,,97933c9f20873446e4c1f8a4da21575f, -Hole Hunter,,,,,TP-606,Extremely Rare,,A2600NTSC,,,3d48b8b586a09bdbf49f1a016bf4d29a, -Holey Moley,Atari,,Prototype,,,,,A2600NTSC,Keypad,Keypad,c52d9bbdc5530e1ef8e8ba7be692b01e, -Home Run Baseball (32-in-1),Atari,Bob Whitehead,,,,,,A2600PAL,,,ca7aaebd861a9ef47967d31c5a6c4555, -Home Run Baseball,Atari,Bob Whitehead,,1978,CX2623,Common,,A2600NTSC,,,0bfabf1e98bdb180643f35f2165995d0, -Home Run Baseball,Atari,Bob Whitehead,,1978,CX2623,Common,,A2600NTSC,,,9f901509f0474bf9760e6ebd80e629cd, -Home Run Baseball,Atari,Bob Whitehead,,1978,CX2623,Common,,A2600PAL,,,24b5f4bbdb853eca38ea0cae2dfe73a1, -Home Run Baseball,Atari,Bob Whitehead,,1978,CX2623,Common,,A2600PAL,,,328949872e454181223a80389d03c122, -Horizonal Color Bars Demo 2,,,,,,,,A2600NTSC,,,68449e4aaba677abcd7cde4264e02168, -Horizonal Color Bars Demo,,,,,,,,A2600NTSC,,,6b7a56b6ac2ca4bf9254474bf6ed7d80, -Horizontally Scrolling Playfield Thing,,Rob Kudla,,,,,,A2600NTSC,,,70a8480cfaf08776e5420365732159d2, -Hozer Video Demo,,,Homebrew,,,,,A2600NTSC,,,7dc03a1f56d0e6a8aae3e3e50d654a08, -Human Cannonball (a.k.a. Cannon Man) (32-in-1),Atari,,,,,,,A2600PAL,,,ad42e3ca3144e2159e26be123471bffc, -Human Cannonball (a.k.a. Cannon Man),128-in-1 Junior Console,,,,,,,A2600NTSC,,,c6c63da3bc2e47291f63280e057061d0, -Human Cannonball (a.k.a. Cannon Man),128-in-1 Junior Console,,,,,,,A2600PAL,,,11330eaa5dd2629052fac37cfe1a0b7d, -Human Cannonball (a.k.a. Cannon Man),Atari,,,1978,CX2627,Uncommon,,A2600NTSC,,,7972e5101fa548b952d852db24ad6060, -Human Cannonball (a.k.a. Cannon Man),Atari,,,1978,CX2627,Uncommon,,A2600NTSC,,,ffe51989ba6da2c6ae5a12d277862e16, -Human Cannonball (a.k.a. Cannon Man),Atari,,,1979,,,,A2600PAL,,,10a3cd14e5dcfdde6ff216a14ce7b7dd, -Hunt & Score,Atari,Alan Miller,,,,,,A2600PAL,,,5be03a1fe7b2c114725150be04b38704, -I Want My Mommy (a.k.a. Ursinho Esperto),Zimag,,,,GN-010/710-111,Extremely Rare,,A2600NTSC,,,f6a282374441012b01714e19699fc62a, -I.Q. 180,,,,,,Extremely Rare,,A2600NTSC,,,4b9581c3100a1ef05eac1535d25385aa, -Ice Hockey,,Alan Miller,,,AX-012,Uncommon,,A2600PAL,,,c7d5819b26b480a49eb26aeb63cc831e, -Ice Hockey,Activision,Alan Miller,,1981,AX-012,Uncommon,,A2600NTSC,,,5bcc83677d68f7ef74c1b4a0697ba2a8, -Ice Hockey,Activision,Alan Miller,,1981,AX-012,Uncommon,,A2600NTSC,,,a4c08c4994eb9d24fb78be1793e82e26, -Ice Hockey,Activision,Alan Miller,,1981,AX-012,Uncommon,,A2600PAL,,,ac9adbd6de786a242e19d4bec527982b, -Ice Hockey,CCE,Alan Miller,,,,Uncommon,,A2600NTSC,,,47711c44723da5d67047990157dcb5dd, -Ikari Warriors,Atari,,,1984,CX7862,Rare,A78SG,A7800NTSC,,,c3672482ca93f70eafd9134b936c3feb,http://www.atariage.com/manual_thumbs.html?SoftwareID=2169 -Ikari Warriors,Atari,,,1984,CX7862,Rare,A78SG,A7800PAL,,,8c2c2a1ea6e9a928a44c3151ba5c1ce3,http://www.atariage.com/manual_thumbs.html?SoftwareID=2169 -Ikari Warriors,Atari,,,1990,CX26177,Rare,,A2600PAL,,,9813b9e4b8a6fd919c86a40c6bda8c93, -Ikari Warriors,Atari,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,3f251c50aa7237e61a38ab42315ebed4, -Im Reich der Spinne,Starsoft,,,,,,,A2600PAL,,,709910c2e83361bc4bf8cd0c20c34fbf, -Im Schutz der Drachen,Starsoft,,,,,,,A2600PAL,,,95e542a7467c94b1e4ab24a3ebe907f1, -Imagic Selector,,,,,,,,A2600NTSC,,,c4bc8c2e130d76346ebf8eb544991b46, -Immies & Aggies (Emag),Emag,,,,,,,A2600PAL,,,faffd84f3a8eceee2fa5ea5b0a3e6678, -Immies and Aggies,,,,,C-838,Extremely Rare,,A2600NTSC,,,9b21d8fc78cc4308990d99a4d906ec52, -Impossible Mission Fixed,Atari,,,1987,CX7832,Scarce,A78SGR,A7800NTSC,,,1745feadabb24e7cefc375904c73fa4c,http://www.atariage.com/manual_thumbs.html?SoftwareID=2170 -Impossible Mission,Atari,,,1987,CX7832,Scarce,A78SGR,A7800NTSC,,,baebc9246c087e893dfa489632157180,http://www.atariage.com/manual_thumbs.html?SoftwareID=2170 -Impossible Mission,Atari,,,1987,CX7832,Scarce,A78SGR,A7800PAL,,,80dead01ea2db5045f6f4443faa6fce8,http://www.atariage.com/manual_thumbs.html?SoftwareID=2170 -Incoming!,,Ben Larson,Homebrew,,,,,A2600NTSC,,,20bf2b233c227cbb9fdfebf81dcd5dc3, -Indy 500 (Hack),Atari,,,1978,,Uncommon,,A2600NTSC,Driving,Driving,dac762e4d01d445bdef20b7771f6570e,http://www.atariage.com/manual_thumbs.html?SoftwareID=1087 -Indy 500,Atari,Carla Meninsky,,1978,CX2611,Uncommon,,A2600NTSC,Driving,Driving,08188785e2b8300983529946dbeff4d2,http://www.atariage.com/manual_thumbs.html?SoftwareID=1087 -Indy 500,Atari,Carla Meninsky,,1978,CX2611,Uncommon,,A2600NTSC,Driving,Driving,c5301f549d0722049bb0add6b10d1e09,http://www.atariage.com/manual_thumbs.html?SoftwareID=1087 -Indy 500,Atari,Carla Meninsky,,1978,CX2611,Uncommon,,A2600PAL,Driving,Driving,4f781f0476493c50dc578336f1132a67,http://www.atariage.com/manual_thumbs.html?SoftwareID=1087 -Indy 500,Atari,Carla Meninsky,,1978,CX2611,Uncommon,,A2600PAL,Driving,Driving,81591a221419024060b890665beb0fb8,http://www.atariage.com/manual_thumbs.html?SoftwareID=1087 -Infiltrate,Apollo,,,1982,AP 2006,Uncommon,,A2600NTSC,,,afe88aae81d99e0947c0cfb687b16251, -International Soccer,Mattel,,,,MT5687,Uncommon,,A2600PAL,,,a0185c06297b2818f786d11a3f9e42c3, -International Soccer,Mattel,,,1982,MT5687,Uncommon,,A2600NTSC,,,29630a20d356fb58685b150bfa8f00c3, -International Soccer,Mattel,,,1982,MT5687,Uncommon,,A2600NTSC,,,b4030c38a720dd84b84178b6ce1fc749, -International Soccer,Telegames,,,,,,,A2600PAL,,,ce904c0ae58d36d085cd506989116b0b, -Inv (4-24-97),,,Homebrew,,,,,A2600NTSC,,,cd139ae6d09f3665ad09eb79da3f9e49, -Inv (Alpha 1),,,Homebrew,,,,,A2600NTSC,,,8874b68751fd2ba6d3306a263ae57a7d, -Inv (Alpha 2),,,Homebrew,,,,,A2600NTSC,,,6d475019ea30d0b29f695e9dcfd8f730, -Inv (Beta),,,Homebrew,,,,,A2600NTSC,,,62992392ea651a16aa724a92e4596ed6, -Inv (V2.1) (1-3-98),,,Homebrew,,,,,A2600NTSC,,,4868a81e1b6031ed66ecd60547e6ec85, -Inv 2,,Eric Mooney,Homebrew,,,,,A2600NTSC,,,2016726db38ad6a68b4c48ba6fe51557, -Invader Sprites in a Line Demo,,,,,,,,A2600NTSC,,,e0cf2dcc4c1348c468f5bb1e421c9164, -Invaders From Space,,David Marli,Hack,,,,,A2600NTSC,,,80cec82239913cb8c4016eb13749de44, -Invisible Pac-Man,,,Hack,,,,,A2600NTSC,,,9c729017dd2f9ccbadcb511187f80e6b, -JKH Text Scrolling Demo,,,,,,,,A2600NTSC,,,a5262fe6d01d6a1253692682a47f79dd, -Jam Demo 1,,,,,,,,A2600NTSC,,,98ea10c47c13f1b3306c7b13db304865, -Jam Demo 2,,,,,,,,A2600NTSC,,,60d304582d33e2957b73eb300a7495bb, -James Bond 007,Parker Bros,,,1983,PB5110,Rare,,A2600NTSC,,,b9c3bc1d77f8e9d814735188bf324e40, -James Bond 007,Parker Bros,,,1983,PB5110,Rare,PB8K,A2600NTSC,,,e51030251e440cffaab1ac63438b44ae, -Jammed (0.1),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,911d385ee0805ff5b8f96c5a63da7de5, -Jammed (0.2),Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,15b498199ed0ed28057bf0dbdce9b8d8, -Jammed (1.0),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,04dfb4acac1d0909e4c360fd2ac04480, -Jammed (Demo Version),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,ef5c02c95a1e7ed24f24193935755cd3, -Jawbreaker,CCE,,,,7-002,Rare,,A2600NTSC,,,58a82e1da64a692fd727c25faef2ecc9, -Jawbreaker,Tigervision,,,,,,,A2600PAL,,,8f33bce5ba1053dcf4cea9c1c69981e4, -Jawbreaker,Tigervision,,,,,,,A2600PAL,,,97327d6962f8c64e6f926f79cd01c6b9, -Jawbreaker,Tigervision,,,,,,,A2600PAL,,,a406d2f6d84e61d842f4cb13b2b1cfa7, -Jinks,Atari,,,1989,CX7857,Common,A78SGR,A7800NTSC,,,045fd12050b7f2b842d5970f2414e912,http://www.atariage.com/manual_thumbs.html?SoftwareID=2134 -Jinks,Atari,,,1989,CX7857,Common,A78SGR,A7800PAL,,,dfb86f4d06f05ad00cf418f0a59a24f7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2134 -John K Harvey's Equalizer,,,Homebrew,,,,,A2600NTSC,,,4fc1b85b8074b4b9436d097900e34f29, -John K Harvey's Equalizer,,,Homebrew,,,,,A2600NTSC,,,eb4252faff7a4f2ba5284a98b8f78d1a, -Journey Escape,,,,,112-006,Common,,A2600NTSC,,,718ae62c70af4e5fd8e932fee216948a, -Joust,Atari,,,1983,CX2691,Common,A8K,A2600NTSC,,,3276c777cbe97cdd2b4a63ffc16b7151, -Joust,Atari,,,1983,CX2691,Common,A8K,A2600PAL,,,640a08e9ca019172d612df22a9190afb, -Joust,Atari,,,1987,CX7806,Common,,A7800NTSC,,,f18b3b897a25ab3885b43b4bd141b396,http://www.atariage.com/manual_thumbs.html?SoftwareID=2135 -Joust,Atari,,,1987,CX7806,Common,,A7800PAL,,,f2dae0264a4b4a73762b9d7177e989f6,http://www.atariage.com/manual_thumbs.html?SoftwareID=2135 -Jr. Ms. Pac-Man,,Bob DeCrescenzo,Homebrew,2009,,,A7832P,A7800NTSC,,,548ba2e54e4fc45ab84ed634d702c136, -Jr. Pac-Man (Tunnels),,Bob DeCrescenzo,Homebrew,2009,,,A7832P,A7800NTSC,,,6bc2daeb48e28d103a4298a276e7e551, -Jr. Pac-Man,,Bob DeCrescenzo,Homebrew,2009,,,A78SGR,A7800NTSC,,,0b3baf47886915dd2eec5da7671bfa63, -Jr. Pac-Man,,Bob DeCrescenzo,Homebrew,2009,,,A78SGR,A7800NTSC,,,8281ab17fa3bfc0a6c497d6a4f350061, -Jr. Pac-Man,Atari,,,1984,CX26123,Uncommon,A16KR,A2600NTSC,,,36c29ceee2c151b23a1ad7aa04bd529d, -Jr. Pac-Man,Atari,,,1984,CX26123,Uncommon,A16KR,A2600PAL,,,297c405afd01f3ac48cdb67b00d273fe, -Jumping Jack,Dynamics,,,,,,,A2600PAL,,,80e1410ec98089e0733cc09e584dba4b, -Jungle Fever,Mystique,,,,1011,Extremely Rare,,A2600NTSC,,,2cccc079c15e9af94246f867ffc7e9bf, -Jungle Hunt,Atari,,,1983,CX2688,Uncommon,A8K,A2600NTSC,,,2bb9f4686f7e08c5fcc69ec1a1c66fe7, -Jungle Hunt,Atari,,,1983,CX2688,Uncommon,A8K,A2600PAL,,,9fc2d1627dcdd8925f4c042e38eb0bc9, -Jungle Hunt,CCE,,,1983,CX2688,Uncommon,A8K,A2600NTSC,,,88a6c9c88cb329ee5fa7d168bd6c7c63, -Jungle King,Atari,Jess Ragan,Hack,,,,A8K,A2600NTSC,,,e1d5c8213e82820128fa9c4775f1e166, -Junkosoft One Year Demo,Junkosoft,,,1999,,,,A2600NTSC,,,65917ae29a8c9785bb1f2acb0d6aafd0, -KC Pacman,,,Hack,,,,,A2600NTSC,,,66b54641b5786ea3ff0215aa39d61e01, -KLAX,Atari,,Prototype,1988,,,A78SG,A7800NTSC,,,17b3b764d33eae9b5260f01df7bb9d2f,http://www.atariage.com/manual_html_page.html?SoftwareID=2227 -Kabobber,Activision,Rex Bradford,Prototype,1983,,,,A2600NTSC,,,b9d1e3be30b131324482345959aed5e5, -Kaboom!,Activision,Larry Kaplan,,1981,AG-010,Uncommon,,A2600NTSC,Paddles,Paddles,5428cdfada281c569c74c7308c7f2c26,http://www.atariage.com/manual_thumbs.html?SoftwareID=1101 -Kaboom!,Activision,Larry Kaplan,,1981,AG-010,Uncommon,,A2600NTSC,Paddles,Paddles,af6ab88d3d7c7417db2b3b3c70b0da0a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1101 -Kaboom!,Activision,Larry Kaplan,,1981,AG-010,Uncommon,,A2600NTSC,Paddles,Paddles,e14dc36b24fe22c04fa076e298f2e15f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1101 -Kaboom!,Activision,Larry Kaplan,,1981,AG-010,Uncommon,,A2600PAL,Paddles,Paddles,f9e99596345a84358bc5d1fbe877134b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1101 -Kaboom!,CCE,Larry Kaplan,,,,,,A2600NTSC,Paddles,Paddles,dbdaf82f4f0c415a94d1030271a9ef44, -Kabul!,,Jess Ragan,Hack,,,,,A2600NTSC,Paddles,Paddles,a93e8ea1f565c3c1e86b708cf0dc2fa9, -Kamikaze Saucers,,,Prototype,,,,,A2600NTSC,,,7b43c32e3d4ff5932f39afcb4c551627, -Kangaroo,Atari,,,,CX2689,Uncommon,,A2600NTSC,,,4326edb70ff20d0ee5ba58fa5cb09d60, -Kangaroo,Atari,,,,CX2689,Uncommon,,A2600PAL,,,6fe67f525c39200a798985e419431805, -Karate,,,,,,,,A2600PAL,,,dd17711a30ad60109c8beace0d4a76e8, -Karate,Froggo,,,1982,,Rare,,A2600NTSC,,,cedbd67d1ff321c996051eec843f8716, -Karateka,Atari,,,1987,CS7822,Common,A78S4,A7800PAL,,,5e0a1e832bbcea6facb832fde23a440a,http://www.atariage.com/manual_html_page.html?SoftwareID=2227 -Karateka,Atari,,,1987,CX7822,Common,,A7800NTSC,,,c3a5a8692a423d43d9d28dd5b7d109d9,http://www.atariage.com/manual_thumbs.html?SoftwareID=2136 -Keystone Kapers (Brazil),Digivision,Garry Kitchen,,,,,,A2600NTSC,,,1351c67b42770c1bd758c3e42f553fea, -Keystone Kapers,Activision,Garry Kitchen,,1983,AX-025,Uncommon,,A2600NTSC,,,be929419902e21bd7830a7a7d746195d, -Keystone Kapers,Activision,Garry Kitchen,,1983,AX-025,Uncommon,,A2600PAL,,,05aedf04803c43eb5e09dfd098d3fd01, -Keystone Kapers,Activision,Garry Kitchen,,1983,AX-025,Uncommon,,A2600PAL,,,6c1f3f2e359dbf55df462ccbcdd2f6bf, -Keystone Kapers,Activision,Garry Kitchen,,1983,AX-025,Uncommon,,A2600PAL,,,bedfbde71fb606601f936b5b057f26f7, -Keystone Kapers,CCE,Garry Kitchen,,,,,,A2600NTSC,,,e28113d10c0c14cc3b5f430b0d142fcb, -Keystone Kaypers (Brazil),Zirok,Garry Kitchen,,,,,,A2600NTSC,,,7187118674ff3c0bb932e049d9dbb379, -King Arthur,Starsoft,,,,,,,A2600PAL,,,05ccf96247af12eef59698f1a060a54f, -King Kong,Tigervision,,,1982,7-001,Rare,,A2600NTSC,,,0b1056f1091cfdc5eb0e2301f47ac6c3, -King Kong,Tigervision,,,1982,7-001,Rare,,A2600PAL,,,0dd4c69b5f9a7ae96a7a08329496779a, -Klax,Atari,David Dentt,,1990,CX26192,Extremely Rare,,A2600NTSC,,,2c29182edf0965a7f56fe0897d2f84ba, -Klax,Atari,David Dentt,,1990,CX26192,Extremely Rare,,A2600PAL,,,eed9eaf1a0b6a2b9bc4c8032cb43e3fb, -Knight on the Town,Playaround,,,,,Extremely Rare,,A2600NTSC,,,7fcd1766de75c614a3ccc31b25dd5b7a, -Kool Aid Man,,Fabrizio Zavagli,Hack,1982,,,,A2600NTSC,,,2c8c11295d8613f875b7bcf5253ab9bb, -Kool Aid Man,Mattel,,,1982,MT4648,Uncommon,,A2600NTSC,,,534e23210dd1993c828d944c6ac4d9fb, -Krieg Der Sterne,Atlantis-Ariola,,,,,,,A2600PAL,,,071f84d10b343c7c05ce3e32af631687, -Krull,Atari,,,1983,CX2682,Rare,,A2600NTSC,,,4baada22435320d185c95b7dd2bcdb24, -Krull,CCE,,,,,,,A2600NTSC,,,00dc28b881989c39a6cf87a892bd3c6b, -Kung Fu Master,Activision,Dan Kitchen,,1984,AX-039,Rare,A8K,A2600NTSC,,,5b92a93b23523ff16e2789b820e2a4c5, -Kung Fu Master,Activision,Dan Kitchen,,1984,AX-039,Rare,A8K,A2600PAL,,,4474b3ad3bf6aabe719a2d7f1d1fb4cc, -Kung Fu Master,CCE,Dan Kitchen,,,AX-039,Rare,A8K,A2600NTSC,,,0b4e793c9425175498f5a65a3e960086, -Kung Fu Sprite Demo 2,,,,,,,,A2600NTSC,,,ce89529d6e98a13ddf3d84827bbdfe68, -Kung Fu Sprite Demo,,,,,,,,A2600NTSC,,,a8101cb667e50a46165c6fb48c608b6b, -Kung Fu,,,,,99003,Extremely Rare,,A2600PAL,,,6805734a0b7bcc8925d9305b071bf147, -Kung-Fu Master,Absolute,,,1989,AM-039,Scarce,,A7800NTSC,,,f57d0af323d4e173fb49ed447f0563d7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2137 -Kung-Fu Master,Absolute,,,1989,AM-039,Scarce,,A7800PAL,,,2931b75811ad03f3ac9330838f3d231b,http://www.atariage.com/manual_thumbs.html?SoftwareID=2137 -Labyrinth,Starsoft,,,,,,,A2600PAL,,,0fbf618be43d4396856d4244126fe7dc, -Lady in Wading,Playaround,,,,,Extremely Rare,,A2600NTSC,,,858abdc9deba2f248e073d01c356e1ab, -Lady in Wading,Playaround,,,,,Extremely Rare,,A2600NTSC,,,95a89d1bf767d7cc9d0d5093d579ba61, -Landung in der Normandie,Starsoft,,,,,,,A2600PAL,,,ec407a206b718a0a9f69b03e920a0185, -Landungskommando,Starsoft,,,,,,,A2600PAL,,,b7345220a0c587f3b0c47af33ebe533c, -Laser Base (a.k.a. World End),ITT Family Games,,,,,,,A2600PAL,,,130c5742cd6cbe4877704d733d5b08ca, -Laser Base (a.k.a. World End),ITT Family Games,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,8c103a79b007a2fd5af602334937b4e1, -Laser Blast (32-in-1),Atari,David Crane,,,,,,A2600PAL,,,0d1b3abf681a2fc9a6aa31a9b0e8b445,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Blast,Activision,David Crane,,1981,AG-008,Common,,A2600NTSC,,,931b91a8ea2d39fe4dca1a23832b591a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Blast,Activision,David Crane,,1981,AG-008,Common,,A2600NTSC,,,9ec1b259a1bcffa63042a3c2b3b90f0a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Blast,Activision,David Crane,,1981,AG-008,Common,,A2600NTSC,,,d5e27051512c1e7445a9bf91501bda09,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Blast,Activision,David Crane,,1982,,,,A2600PAL,,,8a8e401369e2b63a13e18a4d685387c6,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Blast,Activision,David Crane,,1982,,,,A2600PAL,,,d339b95f273f8c3550dc4daa67a4aa94,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Blast,CCE,David Crane,,,,,,A2600NTSC,,,303242c239474f2d7763b843de58c1c3,http://www.atariage.com/manual_thumbs.html?SoftwareID=1115 -Laser Gates,CCE,,,,,Rare,,A2600NTSC,,,1fa58679d4a39052bd9db059e8cda4ad, -Laser Gates,Imagic,Dan Oliver,,1983,,Rare,,A2600PAL,,,8e4cd60d93fcde8065c1a2b972a26377, -Laser Volley,Zellers,,,,,Rare,,A2600NTSC,,,48287a9323a0ae6ab15e671ac2a87598, -Laseral 2600 (7 July 2002) (PAL-49),Andrew Wallace,,Homebrew,,,,,A2600NTSC,,,02dcba28c614fec7ca25955327128abb, -Laseral 2600 (7 July 2002),Andrew Wallace,,Homebrew,,,,,A2600NTSC,,,19098c46da0640f2b5763167dea6c716, -Laseral 2600 (7 July 2002),Andrew Wallace,,Homebrew,,,,,A2600NTSC,,,9c6fd6ed3599978ab7b6f900484b9be6, -Laseral 2600 (7 July 2002),Andrew Wallace,,Homebrew,,,,,A2600PAL,,,f9655ed51462ecfc690c7b97cec649f9, -Lightbulb Lightens - The (Non Functional),,,,,,,,A2600NTSC,,,bb579404924c40ca378b4aff6ccf302d, -Lilly Adventure,Starsoft,,,,,,,A2600PAL,,,ab10f2974dee73dab4579f0cab35fca6, -Lilly Adventure,Starsoft,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,64d43859258dc8ca54949e9ff4174202, -Lines Demo,,,,,,,,A2600PAL,,,fe0b7f27e3ad50bbf9ff468ee56d553d, -Lochjaw,Apollo,,,,,,,A2600NTSC,,,86128001e69ab049937f265911ce7e8a, -Lock 'N' Chase,Mattel,,,1982,MT5663,Common,,A2600NTSC,,,71464c54da46adae9447926fdbfc1abe, -Lock 'N' Chase,Mattel,,,1982,MT5663,Common,,A2600PAL,,,e88340f5bd2f03e2e9ce5ecfa9c644f5, -Lock 'N' Chase,Telegames,,,,,,,A2600PAL,,,493e90602a4434b117c91c95e73828d1, -London Blitz,,,,,50010,Extremely Rare,,A2600NTSC,,,b4e2fd27d3180f0f4eb1065afc0d7fc9, -Lord of the Rings,Parker Bros,,Prototype,,PB5590,,PB8K,A2600NTSC,,,e24d7d879281ffec0641e9c3f52e505a, -Lord of the Rings-Fellowship of the Ring (Improved Engine),,Adam Thornton,Hack,,,,,A2600NTSC,,,e4b12deaafd1dbf5ac31afe4b8e9c233, -Lord of the Rings-Fellowship of the Ring,,Adam Thornton,Hack,,,,,A2600NTSC,,,daef7d8e5a09981c4aa81573d4dbb380, -Lost Luggage,,,,,AP 2004,Uncommon,,A2600NTSC,,,7c00e7a205d3fda98eb20da7c9c50a55, -Lost Luggage,Apollo,,,1981,,,,A2600NTSC,,,2d76c5d1aad506442b9e9fb67765e051, -Lumberman,Cracker Jack Productions,,Hack,,,,,A2600NTSC,,,df5cc5cccdc140eb7107f5b8adfacda1, -M.A.D.,Carrere Video,,,,VC 1012,Rare,,A2600PAL,,,090f0a7ef8a3f885048d213faa59b2f8, -M.A.D.,US Games,,,1982,VC 1012,Rare,,A2600NTSC,,,393e41ca8bdd35b52bf6256a968a9b89, -M.A.S.H. (no logo),CCE,,,,,,,A2600PAL,,,1423f560062c4f3c669d55891a2bcbe7, -M.A.S.H.,20th Century Fox,,,1982,11011,Uncommon,,A2600NTSC,,,835759ff95c2cdc2324d7c1e7c5fa237, -M.A.S.H.,CCE,,,,,,,A2600NTSC,,,cf63ffac9da89ef09c6c973083061a47, -Magicard,CommaVid,,,,,,,A2600NTSC,,,cddabfd68363a76cd30bee4e8094c646, -Malagai,,,,,ASC1001,Unbelievably Rare,,A2600NTSC,,,ccb5fa954fb76f09caae9a8c66462190, -Mangia',Spectravideo,,,1983,SA-212,Rare,,A2600NTSC,Paddles,Paddles,54a1c1255ed45eb8f71414dadb1cf669, -Mangia',Spectravideo,,,1983,SA-212,Rare,,A2600PAL,Paddles,Paddles,d8295eff5dcc43360afa87221ea6021f, -Many Blue Bars Demo,,,,,,,,A2600NTSC,,,e4c2077a18e3c27f4819aa7757903aa0, -Many Blue Bars and Text Demo 2,,,,,,,,A2600NTSC,,,163e7e757e2dc44469123ff0e5daec5e, -Many Blue Bars and Text Demo 3,,,,,,,,A2600NTSC,,,f032b2f2d8323404a6b4541f92dd1825, -Many Blue Bars and Text Demo 4,,,,,,,,A2600NTSC,,,ef60b06fddb675b0d783afbfa5fc5232, -Many Blue Bars and Text Demo,,,,,,,,A2600NTSC,,,cef01595000627ee50863d4290372c27, -Marauder,Tigervision,,,1982,7-005,Extremely Rare,,A2600NTSC,,,13895ef15610af0d0f89d588f376b3fe, -Marauder,Tigervision,,,1982,7-005,Extremely Rare,,A2600NTSC,,,2a156728c0123034bd73e25bf8c70a88, -Marauder,Tigervision,,,1982,7-005,Extremely Rare,,A2600PAL,,,512e874a240731d7378586a05f28aec6, -Marble Craze (Title Only),,Paul Slocum,Homebrew,,,,,A2600NTSC,,,cd9fea12051e414a6dfe17052067da8e, -Marine Wars,Konami,,,1983,11,Extremely Rare,,A2600NTSC,,,b00e8217633e870bf39d948662a52aac, -Marineflieger,Starsoft,,,,,,,A2600PAL,,,1b8d35d93697450ea26ebf7ff17bd4d1, -Mario Bros.,Atari,,,1983,CX2697,Uncommon,,A2600NTSC,,,e908611d99890733be31733a979c62d8, -Mario Bros.,Atari,,,1983,CX2697,Uncommon,,A2600PAL,,,c49fe437800ad7fd9302f3a90a38fb7d, -Mario Bros.,Atari,,,1988,CX7850,Scarce,,A7800NTSC,,,431ca060201ee1f9eb49d44962874049,http://www.atariage.com/manual_thumbs.html?SoftwareID=2138 -Mario Bros.,Atari,,,1988,CX7850,Scarce,,A7800PAL,,,d2e861306be78e44248bb71d7475d8a3,http://www.atariage.com/manual_thumbs.html?SoftwareID=2138 -Mario Bros.,CCE,,,1983,,,,A2600NTSC,,,b1d1e083dc9e7d9a5dc1627869d2ade7, -Mark's Sound Demo,,,,,,,,A2600NTSC,,,c446288fe62c0c2737639fd788ae4a21, -Master Builder,Spectravideo,,,,SA-210,Rare,,A2600NTSC,,,ae4be3a36b285c1a1dff202157e2155d, -Master Builder,Spectravideo,,,,SA-210,Rare,,A2600PAL,,,36e47ed74968c365121eab60f48c6517, -Masters of the Universe - The Power of He-Man,Mattel,,,1983,MT4318,Rare,MN16K,A2600NTSC,,,3b76242691730b2dd22ec0ceab351bc6, -Mat Mania Challenge,Atari,,,1989,CS7863,Scarce,A78SG,A7800NTSC,,,37b5692e33a98115e574185fa8398c22,http://www.atariage.com/manual_thumbs.html?SoftwareID=2139 -Mat Mania Challenge,Atari,,,1989,CX7863,Scarce,A78SG,A7800PAL,,,6819c37b96063b024898a19dbae2df54,http://www.atariage.com/manual_thumbs.html?SoftwareID=2139 -Math Gran Prix,Atari,,,,CX2658,Common,,A2600NTSC,,,470878b9917ea0348d64b5750af149aa, -Math Gran Prix,Atari,,,,CX2658,Common,,A2600PAL,,,45beef9da1a7e45f37f3f445f769a0b3, -Matt Demo,,,,,,,,A2600NTSC,,,244c6de27faff527886fc7699a41c3be, -Maze Craze,Atari,Rick Maurer,,,CX2635,Uncommon,,A2600PAL,,,ed2218b3075d15eaa34e3356025ccca3, -Maze Craze,Atari,Rick Maurer,,1978,CX2635,Uncommon,,A2600NTSC,,,f825c538481f9a7a46d1e9bc06200aaf, -Maze Demo 1,,,,,,,,A2600NTSC,,,69ebf910ab9b63e5b8345f016095003b, -Maze Demo 2,,,,,,,,A2600NTSC,,,f9de91d868d6ebfb0076af9063d7195e, -McDonald's,Parker Bros,,Prototype,,,,,A2600NTSC,,,35b43b54e83403bb3d71f519739a9549, -Mean 18 Ultimate Golf,Atari,,,1988,CX7847,Rare,A78SG,A7800NTSC,,,f2f5e5841e4dda89a2faf8933dc33ea6,http://www.atariage.com/manual_thumbs.html?SoftwareID=2178 -Mean 18 Ultimate Golf,Atari,,,1988,CX7847,Rare,A78SG,A7800PAL,,,2e9dbad6c0fa381a6cd1bb9abf98a104,http://www.atariage.com/manual_thumbs.html?SoftwareID=2178 -Mega Force,20th Century Fox,,,1982,11005,Rare,,A2600NTSC,,,daeb54957875c50198a7e616f9cc8144, -Mega Force,20th Century Fox,,,1982,11005,Rare,,A2600PAL,,,bdbaeff1f7132358ea64c7be9e46c1ac, -Mega Force,20th Century Fox,,,1982,11005,Rare,,A2600PAL,,,ecf51385384b468834611d44a8429c03, -Mega Funpak - Pac-Man - Planet Patrol - Skeet Shoot - Battles of Gorf,HES,,,,,,,A2600PAL,,,e37c8055d70979af354251ebe9f1b7dd, -Mega Mania Raid,Activision,Thiago Paiva,Hack,,,,,A2600NTSC,,,28a2bea8f84936cb2e063f857414cda0, -Megaboy (Brazil),,,,,,,,A2600PAL,,,b65d4a38d6047735824ee99684f3515e, -Megamania,Activision,Steve Cartwright,,,AX-017,Uncommon,,A2600PAL,,,049626cbfb1a5f7a5dc885a0c4bb758e, -Megamania,Activision,Steve Cartwright,,1982,AX-017,Uncommon,,A2600NTSC,,,318a9d6dda791268df92d72679914ac3, -Megamania,Activision,Steve Cartwright,,1982,AX-017,Uncommon,,A2600NTSC,,,a35d47898b2b16ec641d1dfa8a45c2b7, -Megamania,Activision,Steve Cartwright,,1982,AX-017,Uncommon,,A2600PAL,,,3d934bb980e2e63e1ead3e7756928ccd, -Megamania,CCE,Steve Cartwright,,,,,,A2600NTSC,,,d5618464dbdc2981f6aa8b955828eeb4, -Mein Weg,Starsoft,,,,,,,A2600PAL,,,1e0ef01e330e5b91387f75f700ccaf8f, -Meltdown,Atari,,,1990,,Common,A78SG,A7800NTSC,Lightgun,Lightgun,bedc30ec43587e0c98fc38c39c1ef9d0,http://www.atariage.com/manual_thumbs.html?SoftwareID=2140 -Meltdown,Atari,,,1990,,Common,A78SG,A7800PAL,Lightgun,Lightgun,c80155d7eec9e3dcb79aa6b83c9ccd1e,http://www.atariage.com/manual_thumbs.html?SoftwareID=2140 -Merlin's Walls (Standard Edition),Ebivision,,,1999,,,,A2600NTSC,,,50568c80ac61cab789d9923c9b05b68e, -Meteor Defense,ITT Family Games,,,,554-33391,Extremely Rare,,A2600PAL,,,6522717cfd75d1dba252cbde76992090, -Meteor Shower,,Bob DeCrescenzo,Homebrew,2011,,,A7816,A7800NTSC,,,b02f93661f4b7e712810d2bf8e02ad79, -Meteor Shower,,Bob DeCrescenzo,Homebrew,2011,,,A7816,A7800PAL,,,2f1f199ecc2b414d28e01f0de53ca8f7, -Midnight Magic,Atari,,,1984,CX26129,Rare,A16K,A2600NTSC,,,f1554569321dc933c87981cf5c239c43, -Midnight Magic,Atari,,,1984,CX26129,Rare,A16K,A2600PAL,,,da732c57697ad7d7af414998fa527e75, -Midnight Mutants,Atari,,,1990,CX7889,Scarce,A78SG,A7800NTSC,,,bc1e905db1008493a9632aa83ab4682b,http://www.atariage.com/manual_thumbs.html?SoftwareID=2141 -Midnight Mutants,Atari,,,1990,CX7889,Scarce,A78SG,A7800PAL,,,6794ea31570eba0b88a0bf1ead3f3f1b,http://www.atariage.com/manual_thumbs.html?SoftwareID=2141 -Millipede,Atari,,,1984,CX26118,Rare,A16KR,A2600NTSC,,,3c57748c8286cf9e821ecd064f21aaa9,http://www.atariage.com/manual_thumbs.html?SoftwareID=1149 -Millipede,Atari,,,1984,CX26118,Rare,A16KR,A2600PAL,,,a7673809068062106db8e9d10b56a5b3,http://www.atariage.com/manual_thumbs.html?SoftwareID=1149 -Millipede,Atari,,Prototype,,,,A16KR,A2600PAL,,,efd387430a35a659ff569a9a0ec22209,http://www.atariage.com/manual_thumbs.html?SoftwareID=1149 -Miner 2049er Vol. 2,Tigervision,,,,7-011,Extremely Rare,TV8K,A2600NTSC,,,2723e442d55d741a8e2d9293108cd5ed, -Miner 2049er Vol. 2,Tigervision,,,,7-011,Extremely Rare,TV8K,A2600NTSC,,,e2cff4a96b91fcf5de694b7480a612ae, -Miner 2049er Vol. 2,Tigervision,,,,7-011,Extremely Rare,TV8K,A2600PAL,,,468f2dec984f3d4114ea84f05edf82b6, -Miner 2049er,Tigervision,,,,7-008,Extremely Rare,TV8K,A2600NTSC,,,005ea4b9f089336ab7ae46440513a9d3, -Miner 2049er,Tigervision,,,,7-008,Extremely Rare,TV8K,A2600NTSC,,,b21ee4639476eaec8204f00c712b7497, -Miner 2049er,Tigervision,,,,7-008,Extremely Rare,TV8K,A2600NTSC,,,fa0570561aa80896f0ead05c46351389, -Mines of Minos,CommaVid,,,,CM-005,Extremely Rare,,A2600NTSC,,,4543b7691914dfd69c3755a5287a95e1, -Mines of Minos,CommaVid,,,,CM-005,Extremely Rare,,A2600PAL,,,73cb1f1666f3fd30b52b4f3d760c928f, -Mines of Minos,CommaVid,,,,CM-005,Extremely Rare,,A2600PAL,,,b5cb9cf6e668ea3f4cc2be00ea70ec3c, -Minesweeper (V.09),,,,,,,,A2600NTSC,,,635cc7a0db33773959d739d04eff96c2, -Minesweeper (V.099),,,,,,,,A2600NTSC,,,ac5f78bae0638cf3f2a0c8d07eb4df69, -Miniature Golf (32-in-1),Atari,,,,,,,A2600PAL,,,73521c6b9fed6a243d9b7b161a0fb793, -Miniature Golf - Arcade Golf,,,,1979,CX2626,Uncommon,,A2600NTSC,,,384db97670817103dd8c0bbdef132445, -Miniature Golf - Arcade Golf,,,,1979,CX2626,Uncommon,,A2600NTSC,,,df62a658496ac98a3aa4a6ee5719c251, -Miniature Golf,Atari,,,,,,,A2600PAL,,,4f82d8d78099dd71e8e169646e799d05, -Miniature Golf,Atari,,,,CX2626,Uncommon,,A2600PAL,,,ed5ccfc93ad4561075436ee42a15438a, -Miss Pack Man,,,,,,,,A2600PAL,,,391764720140c432aec454a468f77a40, -Miss Piggy's Wedding,,,Prototype,,,,,A2600NTSC,,,25e73efb9a6edf119114718bd2f646ba, -Miss Piggy's Wedding,,,Prototype,,,,,A2600NTSC,,,4181087389a79c7f59611fb51c263137, -Miss Piggy's Wedding,,,Prototype,,,,,A2600NTSC,,,855a42078b14714bcfd490d2cf57e68d, -Missile Command (Different Graphics),,,Hack,,,,,A2600PAL,,,c4d888bcf532e7c9c5fdeafbb145266a,http://www.atariage.com/manual_html_page.html?SoftwareID=1154 -Missile Command,Atari,Rob Fulop,,1980,CX2638,,,A2600PAL,,,f6a9ea814d15b85bffe980c927df606b,http://www.atariage.com/manual_html_page.html?SoftwareID=1154 -Missile Command,Atari,Rob Fulop,,1980,CX2638,Common,,A2600NTSC,,,3a2e2d0c6892aa14544083dfb7762782,http://www.atariage.com/manual_html_page.html?SoftwareID=1154 -Missile Command,Atari,Rob Fulop,,1980,CX2638,Common,,A2600PAL,,,9364ad51c321e0f15c96a8c0aff47ceb,http://www.atariage.com/manual_html_page.html?SoftwareID=1154 -Missile Control (a.k.a. Raketen-Angriff),Ariola,,,,,,,A2600PAL,,,0b577e63b0c64f9779f315dca8967587, -Missile Control (a.k.a. Raketen-Angriff),Ariola,,,,VG-01,Extremely Rare,,A2600PAL,,,cb24210dc86d92df97b38cf2a51782da, -Missile Control (a.k.a. Raketen-Angriff),Ariola,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,e6e5bb0e4f4350da573023256268313d, -Missile War,Goliath,,,,,,,A2600PAL,,,317a4cdbab090dcc996833d07cb40165, -Missing in Action,TNT Games,Chuck Peavey,Prototype,1989,CX7890,,A78S9,A7800NTSC,,,017066f522908081ec3ee624f5e4a8aa,http://www.atariage.com/software_page.html?SoftwareLabelID=2760 -Missing in Action,TNT Games,Chuck Peavey,Prototype,1989,CX7890,,A78S9,A7800NTSC,,,d0f46bf92ed6e7b1cce63278420cae8a,http://www.atariage.com/software_page.html?SoftwareLabelID=2760 -Mission 3000 A.D.,Bitcorp,,,,PG207,Rare,,A2600PAL,,,6efe876168e2d45d4719b6a61355e5fe, -Mission Survive,,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,b676a9b7094e0345a76ef027091d916b, -Mission Survive,Video Gems,,,,,,,A2600PAL,,,cf9069f92a43f719974ee712c50cd932, -Misterious Thief - A,CCE,,,,C-839,Extremely Rare,,A2600NTSC,,,e13818a5c0cb2f84dd84368070e9f099, -Moby Blues,Ataritalia,,Hack,,,,,A2600NTSC,,,63e9e612bbee31045f8d184a4e53f8ec, -Mogul Maniac,Amiga,,,,3120,Extremely Rare,,A2600NTSC,,,7af40c1485ce9f29b1a7b069a2eb04a7, -Mondo Pong V1,,Piero Cavina,Homebrew,,,,,A2600NTSC,Paddles,Paddles,6bde3f6ac31aceef447ce57d4d2c2ec0, -Mondo Pong,,,Homebrew,,,,,A2600NTSC,Paddles,Paddles,1f60e48ad98b659a05ce0c1a8e999ad9, -Monster aus dem All,Rainbow Vision,,,1983,,,,A2600PAL,,,c31a17942d162b80962cb1f7571cd1d5, -Monstercise,,,Prototype,,CX26131,,,A2600NTSC,Keypad,Keypad,6913c90002636c1487538d4004f7cac2, -Montezuma's Revenge - Starring Panama Joe,Parker Bros,,,1983,PB5760,Extremely Rare,PB8K,A2600NTSC,,,3347a6dd59049b15a38394aa2dafa585, -Montezuma's Revenge - Starring Panama Joe,Parker Bros,Thomas Jentzsch,Hack,1983,,,PB8K,A2600PAL,,,9f59eddf9ba91a7d93bce7ee4b7693bc, -Moon Cresta,,Bob DeCrescenzo,Homebrew,2011,,,A7832,A7800NTSC,,,9ff38ea62004201d870caa8bd9463525, -Moon Patrol,Atari,,,1983,CX2692,Uncommon,A8K,A2600NTSC,,,515046e3061b7b18aa3a551c3ae12673, -Moon Patrol,Atari,,,1983,CX2692,Uncommon,A8K,A2600PAL,,,65490d61922f3e3883ee1d583ce10855, -Moon Patrol,CCE,,,,,,,A2600NTSC,,,6de924c2297c8733524952448d54a33c, -Moonsweeper,Imagic,Bob Smith,,1983,O3207,Uncommon,,A2600NTSC,,,203abb713c00b0884206dcc656caa48f, -Moonsweeper,Imagic,Bob Smith,,1983,O3207,Uncommon,,A2600NTSC,,,7db7c5fd8d3f53127a4bb0092c91d983, -Moonsweeper,Imagic,Bob Smith,,1983,O3207,Uncommon,,A2600PAL,,,4af4103759d603c82b1c9c5acd2d8faf, -Moto Laser,CCE,,,,,,,A2600NTSC,,,eb503cc64c3560cd78b7051188b7ba56, -Motocross Racer - Joystick,Xonox,,,,,Rare,,A2600NTSC,,,5641c0ff707630d2dd829b26a9f2e98f, -Motocross Racer,Xonox,,,,,Rare,,A2600NTSC,,,de0173ed6be9de6fd049803811e5f1a8, -Motocross,Starsoft,,,,,Rare,,A2600PAL,,,5635cd67fb680424254ec156c42deee0, -Motocross,Starsoft,,,,,Rare,,A2600PAL,,,a20b7abbcdf90fbc29ac0fafa195bd12, -Motocross,Starsoft,,,,,Rare,,A2600PAL,,,f5a2f6efa33a3e5541bc680e9dc31d5b, -Motor Psycho,Atari,,,1990,CX7852,Rare,A78SG,A7800NTSC,,,3bc8f554cf86f8132a623cc2201a564b,http://www.atariage.com/manual_thumbs.html?SoftwareID=2171 -Motor Psycho,Atari,,,1990,CX7852,Rare,A78SG,A7800PAL,,,5330bfe428a6b601b7e76c2cfc4cd049,http://www.atariage.com/manual_thumbs.html?SoftwareID=2171 -Motorodeo,Atari,,,1990,CX26171,Unbelievably Rare,,A2600PAL,,,b1e2d5dc1353af6d56cd2fe7cfe75254, -Mountain King,CBS Electronics,,,,4L-2738,Rare,CBS12K,A2600NTSC,,,7e51a58de2c0db7d33715f518893b0db, -Mountain Man (a.k.a. Winterjagt),ITT Family Games,,,,,,,A2600PAL,,,6c1553ca90b413bf762dfc65f2b881c7, -Mouse Trap,CBS Electronics,,,,2459,Uncommon,,A2600PAL,,,23d445ea19a18fb78d5035878d9fb649, -Mouse Trap,Coleco,,,,2459,Uncommon,,A2600NTSC,,,5678ebaa09ca3b699516dba4671643ed, -Movable Grid Demo,,,,,,,,A2600NTSC,,,24fbf8250a71611e40ef18552e61b009, -Move a Blue Blob Demo 2,,,,,,,,A2600NTSC,,,f69a39b215852a0c2764d2a923c1e463, -Move a Blue Blob Demo,,,,,,,,A2600NTSC,,,6342afe9c9ad1b6120b8f6fb040d0926, -Moving Blue Ladder Demo,,,,,,,,A2600NTSC,,,140909d204abd6841c64cdad4d7765b4, -Moving Maze Demo,,,,,,,,A2600NTSC,,,703d32062436e4c20c48313dff30e257, -Mr. Do!'s Castle,Parker Bros,,,1983,2695/PB5820,Extremely Rare,PB8K,A2600NTSC,,,b7a7e34e304e4b7bc565ec01ba33ea27, -Mr. Do!,CBS Electronics,,,1983,2656,Rare,,A2600NTSC,,,0164f26f6b38a34208cd4a2d0212afc3, -Mr. Do!,CBS Electronics,,,1983,2656,Rare,,A2600PAL,,,aa7bb54d2c189a31bb1fa20099e42859, -Mr. Postman,,,,,PG209,Rare,,A2600NTSC,,,f0daaa966199ef2b49403e9a29d12c50, -Mr. Postman,Bitcorp,,,1983,,,,A2600PAL,,,603c7a0d12c935df5810f400f3971b67, -Mr. Postman,CCE,,,,C-801,Extremely Rare,,A2600NTSC,,,9a4274409216ff09ecde799f2a56ac73, -Mr. Roboto,Paul Slocum,,Homebrew,,,,,A2600NTSC,,,cff9950d4e650094f65f40d179a9882d, -Mr. T (a.k.a. Fast Eddie),Starsoft,,,,11003,Uncommon,,A2600PAL,,,a1f9159121142d42e63e6fb807d337aa, -Ms. Pac-Man,Atari,,,1982,CX2675,Common,A8K,A2600NTSC,,,87e79cd41ce136fd4f72cc6e2c161bee, -Ms. Pac-Man,Atari,,,1982,CX2675,Common,A8K,A2600PAL,,,1ee9c1ba95cef2cf987d63f176c54ac3, -Ms. Pac-Man,Atari,,,1987,CX7807,Common,,A7800NTSC,,,fc0ea52a9fac557251b65ee680d951e5,http://www.atariage.com/manual_thumbs.html?SoftwareID=2142 -Ms. Pac-Man,Atari,,,1987,CX7807,Common,,A7800PAL,,,56469e8c5ff8983c6cb8dadc64eb0363,http://www.atariage.com/manual_thumbs.html?SoftwareID=2142 -Ms. Pac-Man,CCE,,,1982,,,A8K,A2600NTSC,,,9469d18238345d87768e8965f9f4a6b2, -Multi Sprite Demo 1,,,,,,,,A2600NTSC,,,25f9cf703575c5d63048c222f5463758, -Multi-Color Demo 0,,,,,,,,A2600NTSC,,,079fe9103515d15bc108577e234a484d, -Multi-Color Demo 1,,,,,,,,A2600PAL,,,4afe528a082f0d008e7319ebd481248d, -Multi-Color Demo 2,,,,,,,,A2600NTSC,,,191449e40b0c56411c70772706f79224, -Multi-Color Demo 3,,,,,,,,A2600NTSC,,,ae18c11e4d7ed2437f0bf5d167c0e96c, -Multi-Color Demo 4,,,,,,,,A2600NTSC,,,c28b29764c2338b0cf95537cc9aad8c9, -Multi-Color Demo 5,,,,,,,,A2600NTSC,,,d34b933660e29c0a0a04004f15d7e160, -Multi-Color Demo 6,,,,,,,,A2600NTSC,,,14163eb2a3ddd35576bd8527eae3b45e, -Multi-Color Demo 7,,,,,,,,A2600NTSC,,,b1fd0b71de9f6eeb5143a97963674cb6, -Multi-Sprite Demo V1.1,,Piero Cavina,Homebrew,,,,,A2600NTSC,,,17515a4d0b7ea5029ffff7dfa8456671, -Multi-Sprite Demo V2.0,,Piero Cavina,Homebrew,,,,,A2600NTSC,,,ef71e9fb0d8d477226d8d42261fbf0a7, -Multi-Sprite Demo,,,,,,,,A2600NTSC,,,42ae81ae8ac51e5c238639f9f77d91ae, -Multi-Sprite Game V1.0,,Piero Cavina,Homebrew,,,,,A2600NTSC,,,b958d5fd9574c5cf9ece4b9421c28ecd, -Multi-Sprite Game V2.1,,Piero Cavina,Homebrew,,,,,A2600NTSC,,,7197b6cbde6ecd10376155e6b848e80d, -Muncher,,David Marli,Hack,,,,,A2600NTSC,,,a100eff2d7ae61ca2b8e65baf7e2aae8, -Music Machine,Sparrow,,,1983,GCG 1001T,Unbelievably Rare,,A2600NTSC,Paddles,Paddles,65b106eba3e45f3dab72ea907f39f8b4, -My Golf,,,,,,,,A2600PAL,,,dfad86dd85a11c80259f3ddb6151f48f, -My Golf,CCE,,,,,,,A2600NTSC,,,ee6cbedf6c0aac90faa0a8dbc093ffbe, -My Golf,HES,,,1990,,,,A2600PAL,,,04fccc7735155a6c1373d453b110c640, -My Golf,HES,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,0546f4e6b946f38956799dd00caab3b1, -Mystery Science Theater 2600,,Tim Snider,Hack,,,,,A2600NTSC,,,fa7e11a3dbea4365975cd2f094e61d25, -NOIZ Invaders (SPIKE the Percussionist),SPIKE the Percussionist,,Homebrew,,,,,A2600NTSC,,,c58708c09ccb61625cda9d15ddcd8be6, -Name That Game (a.k.a. Octopus),US Games,,,,,,,A2600PAL,,,b392964e8b1c9c2bed12246f228011b2, -Name This Game (a.k.a. Octopus),US Games,,,1982,VC 1007,Extremely Rare,,A2600PAL,,,45cb0f41774b78def53331e4c3bf3362, -Night Driver,Atari,Rob Fulop,,1978,CX2633,Common,,A2600NTSC,Paddles,Paddles,392f00fd1a074a3c15bc96b0a57d52a1, -Night Driver,Atari,Rob Fulop,,1978,CX2633,Common,,A2600NTSC,Paddles,Paddles,f48022230bb774a7f22184b48a3385af, -Night Driver,Atari,Rob Fulop,,1978,CX2633,Common,,A2600PAL,Paddles,Paddles,feec54aac911887940b47fe8c9f80b11, -Night Stalker,Telegames,,,,,Rare,,A2600PAL,,,2783006ee6519f15cbc96adae031c9a9, -Night Stalker,Telegames,,,,,Rare,,A2600PAL,,,bd39598f067a1193ae81bd6182e756d1, -Nightmare,,,,,TEC004/105,Rare,,A2600NTSC,,,ed0ab909cf7b30aff6fc28c3a4660b8e, -Nightmare,CCE,,,,,,,A2600NTSC,,,27f9e2e1b92af9dc17c6155605c38e49, -Nightmare,Sancho,,,,TEC004,Extremely Rare,,A2600PAL,,,ead60451c28635b55ca8fea198444e16, -Ninja Golf,Atari,David Dentt & David Sullivan,,1990,CX7870,Scarce,A78SG,A7800NTSC,,,220121f771fc4b98cef97dc040e8d378,http://www.atariage.com/manual_thumbs.html?SoftwareID=2143 -Ninja Golf,Atari,David Dentt,,1990,CX7870,Scarce,A78SG,A7800PAL,,,ea0c859aa54fe5eaf4c1f327fab06221,http://www.atariage.com/manual_thumbs.html?SoftwareID=2143 -No Escape!,Imagic,Michael Greene,,1983,IA3312,Rare,,A2600NTSC,,,9912d06eea42200a198dd3e2be18c601, -No Escape!,Imagic,Michael Greene,,1983,IA3312,Rare,,A2600NTSC,,,b6d52a0cf53ad4216feb04147301f87d, -No Escape!,Imagic,Michael Greene,,1983,IA3312,Rare,,A2600PAL,,,d8df256c0d89e494a9fb3e9abb8e44ac, -Noize Maker Demo,,,,,,,,A2600NTSC,,,637efac676ff063f2fbb0abff77c4fa5, -Nuts,Technovision,,,,,Extremely Rare,,A2600NTSC,,,de7a64108074098ba333cc0c70eef18a, -Obelix,Atari,,,,CX26117,Extremely Rare,,A2600PAL,,,19e739c2764a5ab9ed08f9095aa2af0b, -Obelix,Atari,,,,CX26117,Extremely Rare,,A2600PAL,,,669840b0411bfbab5c05b786947d55d4, -Obelix,Atari,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,a189f280521f4e5224d345efb4e75506, -Ocean City Defender,Zellers,,,,,Extremely Rare,,A2600NTSC,,,4cabc895ea546022c2ecaa5129036634, -Octopus (a.k.a. Name That Game),Carrere Video,,,,VC 1007,Extremely Rare,,A2600PAL,,,36306070f0c90a72461551a7a4f3a209, -Off Your Rocker,Amiga,,,,3130,Extremely Rare,,A2600NTSC,,,b6166f15720fdf192932f1f76df5b65d, -Off the Wall,Atari,,,1989,,,,A2600PAL,,,36edef446ab4c2395666efc672b92ed0, -Off the Wall,Atari,,,1989,CX26168,Extremely Rare,,A2600PAL,,,131864e1d18d3406048700d3c0760417, -Off the Wall,Atari,,,1989,CX26168,Extremely Rare,,A2600PAL,,,98f63949e656ff309cefa672146dc1b8, -Oink!,Activision,Mike Lorenzen,,1983,,,,A2600PAL,,,853c11c4d07050c22ef3e0721533e0c5, -Oink!,Activision,Mike Lorenzen,,1983,AX-023,Rare,,A2600NTSC,,,3da7cc7049d73d34920bb73817bd05a9, -Oink!,Activision,Mike Lorenzen,,1983,AX-023,Rare,,A2600NTSC,,,c9c25fc536de9a7cdc5b9a916c459110, -Oink!,Activision,Mike Lorenzen,,1983,AX-023,Rare,,A2600PAL,,,06b6c5031b8353f3a424a5b86b8fe409, -Oink!,CCE,Mike Lorenzen,,,,,,A2600NTSC,,,f8648d0c6ad1266434f6c485ff69ec40, -Okie Dokie (4K),,,Homebrew,,,,,A2600PAL,,,8101efafcf0af32fedda4579c941e6f4, -Okie Dokie (Older),,,Homebrew,,,,,A2600NTSC,,,ce4bbe11d682c15a490ae15a4a8716cf, -Okie Dokie,,,Homebrew,,,,,A2600NTSC,,,cca33ae30a58f39e3fc5d80f94dc0362, -Omega Race JS,CBS Electronics, Thomas Jentzsch ,Hack,,,,CBS12K,A2600NTSC,,,3b6dba1a24bb2893bd3bd0593f92016b, -Omega Race,CBS Electronics,,,,4L-2737,Uncommon,CBS12K,A2600NTSC,BoosterGrip,BoosterGrip,885b2002fa9d27502d84968d4656c4ca, -Omega Race,CBS Electronics,,,,4L-2737,Uncommon,CBS12K,A2600NTSC,BoosterGrip,BoosterGrip,9947f1ebabb56fd075a96c6d37351efa, -One Blue Bar Demo,,,,,,,,A2600NTSC,,,61426cee013306e7f7367534ab124747, -One on One Basketball,Atari,,,1987,CX7824,Common,,A7800NTSC,,,74569571a208f8b0b1ccfb22d7c914e1,http://www.atariage.com/manual_thumbs.html?SoftwareID=2144 -One on One Basketball,Atari,,,1987,CX7824,Common,,A7800PAL,,,8dba0425f0262e5704581d8757a1a6e3,http://www.atariage.com/manual_thumbs.html?SoftwareID=2144 -One on One,,Angelino,Hack,,,,,A2600NTSC,,,b83df1f32b4539c324bdf94851b4db55, -Oscar's Trash Race,,,Prototype,,CX26101,,,A2600NTSC,Keypad,Keypad,fa1b060fd8e0bca0c2a097dcffce93d3, -Oscar's Trash Race,Atari,,,,CX26101,Rare,,A2600PAL,Keypad,Keypad,47911752bf113a2496dbb66c70c9e70c, -Othello (32-in-1),Atari,Ed Logg,,1978,,,,A2600PAL,,,6468d744be9984f2a39ca9285443a2b2, -Othello,Atari,Ed Logg,,1978,,,,A2600PAL,,,7d9c96b215d1941e87b6fb412eb9204f, -Othello,Atari,Ed Logg,,1978,CX2639,Rare,,A2600NTSC,,,113cd09c9771ac278544b7e90efe7df2, -Othello,Atari,Ed Logg,,1978,CX2639,Rare,,A2600NTSC,,,2c3b9c171e214e9e46bbaa12bdf8977e, -Othello,Atari,Ed Logg,,1978,CX2639,Rare,,A2600NTSC,,,55949cb7884f9db0f8dfcf8707c7e5cb, -Othello,Atari,Ed Logg,,1978,CX2639,Rare,,A2600PAL,,,00e19ebf9d0817ccfb057e262be1e5af, -Out of Control,Avalon Hill,,,,,Rare,,A2600NTSC,,,f97dee1aa2629911f30f225ca31789d4, -Outlaw (32-in-1),Atari,David Crane,,,,,,A2600PAL,,,2e3728f3086dc3e71047ffd6b2d9f015, -Outlaw - GunSlinger,Atari,David Crane,,1978,CX2605,Uncommon,,A2600NTSC,,,890c13590e0d8d5d6149737d930e4d95, -Outlaw - GunSlinger,Atari,David Crane,,1978,CX2605,Uncommon,,A2600NTSC,,,f060826626aac9e0d8cda0282f4b7fc3, -Outlaw - GunSlinger,Atari,David Crane,,1978,CX2605,Uncommon,,A2600PAL,,,22675cacd9b71dea21800cbf8597f000, -Overhead Adventure Demo 1,,,,,,,,A2600NTSC,,,1ec5bef77b91e59313cba205f15b06d7, -Overhead Adventure Demo 2,,,,,,,,A2600NTSC,,,4066d7d88ec4a2c656127a67fa52dcf1, -Overhead Adventure Demo 3,,,,,,,,A2600NTSC,,,3c7a96978f52b2b15426cdd50f2c4048, -Overhead Adventure Demo 4,,,,,,,,A2600NTSC,,,0cfdd2f3b243cac21f38a0f09f54bead, -Overhead Adventure Demo 5,,,,,,,,A2600NTSC,,,d5aa7472e7f2cc17e893a1a36f8dadf0, -Overhead Adventure Demo 6,,,,,,,,A2600NTSC,,,f45644ff82b533a781a1ee50f2e95f3c, -Oystron (V2.7),,,Homebrew,,,,,A2600NTSC,,,26f4f8b098609164effef7809e0121e1,http://www.io.com/~nickb/atari/oystron.html -Oystron (V2.8),,,Homebrew,,,,,A2600NTSC,,,e6508b878145187b87b9cded097293e7,http://www.io.com/~nickb/atari/oystron.html -Oystron (V2.82),,,Homebrew,,,,,A2600NTSC,,,70d14c66c319683b4c19abbe0e3db57c,http://www.io.com/~nickb/atari/oystron.html -Oystron (V2.85),,,Homebrew,,,,,A2600NTSC,,,5360693f1eb90856176bd1c0a7b17432,http://www.io.com/~nickb/atari/oystron.html -Oystron (V2.9),,,Homebrew,1997,,,,A2600NTSC,,,91f0a708eeb93c133e9672ad2c8e0429,http://www.io.com/~nickb/atari/oystron.html -Oystron X,,,Homebrew,,,,,A2600NTSC,,,aa2c4b32656bde9a75042a4d158583e1,http://www.io.com/~nickb/atari/oystron.html -PC Invaders,,Matthias Jaap,Hack,,,,,A2600NTSC,,,6ac3fd31a51730358708c7fdc62487f8, -PCMSG 2.0,,,,,,,,A2600NTSC,,,59135f13985b84c4f13cc9e55eec869a,http://www.io.com/~nickb/atari/oystron.html -PCMSG 2.2,,,,,,,,A2600NTSC,,,585600522b1f22f617652c962e358a5d,http://www.io.com/~nickb/atari/oystron.html -PCMSG 2.3,,,,,,,,A2600NTSC,,,e609e8a007127b8fcff79ffc380da6b1,http://www.io.com/~nickb/atari/oystron.html -PCMSG 2.4,,,,,,,,A2600NTSC,,,50ef88f9a5e0e1e6b86e175362a27fdb,http://www.io.com/~nickb/atari/oystron.html -PCMSG 2.5,,,,,,,,A2600NTSC,,,157356f80c709ab675961d8b8b207e20,http://www.io.com/~nickb/atari/oystron.html -PCMSG 2.6 (Oystron Pre-release demo),,,Homebrew,,,,,A2600NTSC,,,4689081b7363721858756fe781cc7713,http://www.io.com/~nickb/atari/oystron.html -PIEROXM Demo,,,,,,,,A2600NTSC,,,9c7fa3cfcaaafb4e6daf1e2517d43d88, -Pac Ghost Sprite Demo 2,,,,,,,,A2600NTSC,,,bd430c2193045c68d1a20a018a976248, -Pac Ghost Sprite Demo,,,,,,,,A2600NTSC,,,d0498baca989e792db4b8270a02b9624, -Pac Invaders,ZUT,,,,,,,A2600NTSC,,,f9da42f91a1c5cfa344d2ff440c6f8d4, -Pac Kong,,,,,,Extremely Rare,,A2600PAL,,,936ef1d6f8a57b9ff575dc195ee36b80, -Pac Kong,Funvision,,,,,Extremely Rare,,A2600PAL,,,88d300a38bdd7cab9edad271c18cd02b, -Pac Kong,Goliath,,,,,,,A2600PAL,,,f14d5e96ec3380aef57a4b70132c6677, -Pac Kong,Starsoft,,,,,,,A2600PAL,,,d223bc6f13358642f02ddacfaf4a90c9, -Pac-2600,,,Hack,,,,,A2600NTSC,,,ebf9038e927e6a0db3e0d170c59911e6, -Pac-Law,,Jim Goebel,Hack,,,,,A2600NTSC,,,a4b99aa5ed85cfdb7d101923147de035, -Pac-Man Collection,,Bob DeCrescenzo,Homebrew,2006,,,,A7800NTSC,,,5d7bc7092de69095137456733e7b685d,http://www.atariage.com/software_page.html?SoftwareID=4086 -Pac-Man,,Rob Kudla,Hack,,,,,A2600NTSC,,,aeb104f1e7b166bc0cbaca0a968fde51,http://www.atariage.com/manual_thumbs.html?SoftwareID=1193 -Pac-Man,Atari,Tod Frye,,,CX2646,Common,,A2600PAL,,,c2410d03820e0ff0a449fa6170f51211,http://www.atariage.com/manual_thumbs.html?SoftwareID=1193 -Pac-Man,Atari,Tod Frye,,,CX2646,Common,,A2600PAL,,,fc2233fc116faef0d3c31541717ca2db,http://www.atariage.com/manual_thumbs.html?SoftwareID=1193 -Pac-Man,Atari,Tod Frye,,1981,CX2646,Common,,A2600NTSC,,,6e372f076fb9586aff416144f5cfe1cb,http://www.atariage.com/manual_thumbs.html?SoftwareID=1193 -Pac-Man,CCE,Tod Frye,,,,,,A2600NTSC,,,ca53fc8fd8b3c4a7df89ac86b222eba0,http://www.atariage.com/manual_thumbs.html?SoftwareID=1193 -Pac-Man,CCE,Tod Frye,,,,,,A2600PAL,,,651d2b6743a3a18b426bce2c881af212,http://www.atariage.com/manual_thumbs.html?SoftwareID=1193 -Pac-Space,,,,,,,,A2600NTSC,,,c569e57dca93d3bee115a49923057fd7, -PacArcade,,,Homebrew,2011,,,A7816,A7800NTSC,,,90223a8a363bdf643a19d0f97e63b1b2, -Panda Chase,HomeVision,,,,,Extremely Rare,,A2600NTSC,,,f8582bc6ca7046adb8e18164e8cecdbc, -Parachute,HomeVision,,,,,Extremely Rare,,A2600PAL,,,714e13c08508ee9a7785ceac908ae831, -Parachute,HomeVision,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,245f07c8603077a0caf5f83ee6cf8b43, -Peek-A-Boo,,,Prototype,,CX26137,,,A2600NTSC,,,e40a818dac4dd851f3b4aafbe2f1e0c1, -Pengo (1 player only),,,,,CX2690,Extremely Rare,A8K,A2600NTSC,,,04014d563b094e79ac8974366f616308, -Pengo,,,,,CX2690,Extremely Rare,A8K,A2600NTSC,,,4bcc7f6ba501a26ee785b7efbfb0fdc8, -Pepsi Invaders,Coca Cola,,Prototype,,,,,A2600NTSC,,,212d0b200ed8b45d8795ad899734d7d7, -Pete Rose Baseball,Absolute,,,1989,AV-045,Scarce,,A7800PAL,,,386bded4a944bae455fedf56206dd1dd,http://www.atariage.com/manual_thumbs.html?SoftwareID=2172 -Pete Rose Baseball,Absolute,Alex DeMeo,,,AK-045,Rare,A16K,A2600NTSC,,,09388bf390cd9a86dc0849697b96c7dc, -Pete Rose Baseball,Absolute,Alex DeMeo,,1989,AV-045,Scarce,,A7800NTSC,,,1a5207870dec6fae9111cb747e20d8e3,http://www.atariage.com/manual_thumbs.html?SoftwareID=2172 -Peter Penguin,ITT,Jagt auf Diamanten-Frisco,,,,,,A2600PAL,,,cb4a7b507372c24f8b9390d22d54a918, -Phantom Panzer II,Starsoft,,,,,,,A2600PAL,,,08bd4c1dcc843f6a0b563d9fd80b3b11, -Phantom Tank,Bitcorp,,,,PG203,Rare,,A2600PAL,,,6b1fc959e28bd71aed7b89014574bdc2, -Phantom Tank,Bitcorp,,,,PG203,Rare,,A2600PAL,,,7454786af7126ccc7a0c31fcf5af40f1, -Phantom Tank,CCE,,,,,,,A2600PAL,,,5a9d188245aff829efde816fcade0b16, -Phantom UFO,,,,,,,,A2600PAL,,,4d38e1105c3a5f0b3119a805f261fcb5, -Pharaoh's Curse,TechnoVision,,,,,,,A2600PAL,,,a69f5b1761a8a11c98e706ec7204937f, -Pharaoh's Curse,TechnoVision,,,,,Extremely Rare,,A2600PAL,,,3577e19714921912685bb0e32ddf943c, -Pharaoh's Curse,TechnoVision,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,2ae700c9dba843a68dfdca40d7d86bd6, -Pharoah's Curse,TechnoVision,,Hack,,,Extremely Rare,,A2600PAL,,,62f74a2736841191135514422b20382d, -Philly Flasher,Playaround,,,,,Extremely Rare,,A2600NTSC,,,ca54de69f7cdf4d7996e86f347129892, -Phoenix,Atari,,,,CX2673,Common,A8K,A2600PAL,,,79fcdee6d71f23f6cf3d01258236c3b9, -Phoenix,Atari,,,1982,CX2673,Common,A8K,A2600NTSC,,,7e52a95074a66640fcfde124fffd491a, -Phoenix,CCE,,,,,,A8K,A2600NTSC,,,a00ec89d22fcc0c1a85bb542ddcb1178, -Pick 'n Pile,Salu,,,1990,,Extremely Rare,,A2600PAL,,,da79aad11572c80a96e261e4ac6392d0, -Picnic,US Games,,,1982,VC 2004,Extremely Rare,,A2600NTSC,,,17c0a63f9a680e7a61beba81692d9297, -Piece o' Cake,US Games,,,1982,VC 2005,Extremely Rare,,A2600NTSC,Paddles,Paddles,d3423d7600879174c038f53e5ebbf9d3, -Pigs in Space starring Miss Piggy,Atari,,,,CX26114,Extremely Rare,,A2600NTSC,,,8e4fa8c6ad8d8dce0db8c991c166cdaa, -Pigs in Space starring Miss Piggy,Atari,,,,CX26114,Extremely Rare,,A2600PAL,,,95e1d834c57cdd525dd0bd6048a57f7b, -Pink Floyd,,Kyle Pittman,Hack,,,,,A2600NTSC,,,dbc7485ad5814d466de780a3e7ed3b46, -Pitfall 2 Plus,,,Hack,,,,DPC,A2600NTSC,,,39a6a5a2e1f6297cceaa48bb03af02e9,http://www.atariage.com/manual_thumbs.html?SoftwareID=1206 -Pitfall 2,Activision,David Crane,,1984,AB-035-04,Rare,DPC,A2600PAL,,,e34c236630c945089fcdef088c4b6e06,http://www.atariage.com/manual_thumbs.html?SoftwareID=1206 -Pitfall II - Lost Caverns,Activision,David Crane,,1984,AB-035-04,Rare,DPC,A2600NTSC,,,48eb1fcde4caf6a2dce059c98bd2e375,http://www.atariage.com/manual_thumbs.html?SoftwareID=1206 -Pitfall II - Lost Caverns,Activision,David Crane,,1984,AB-035-04,Rare,DPC,A2600NTSC,,,6d842c96d5a01967be9680080dd5be54,http://www.atariage.com/manual_thumbs.html?SoftwareID=1206 -Pitfall II - Lost Caverns,Activision,David Crane,,1984,AB-035-04,Rare,DPC,A2600NTSC,,,f939780714db69dc69a80fbefe350e0d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1206 -Pitfall! (Beta),Activision,David Crane,Prototype,1982,AX-018,,,A2600NTSC,,,aad91be0bf78d33d29758876d999848a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1206 -Pitfall! (No Walls),,,Hack,,,,,A2600NTSC,,,e42b937c30c617241ca9e01e4510c3f6,http://www.atariage.com/manual_thumbs.html?SoftwareID=1207 -Pitfall!,,,Hack,1985,,,,A2600NTSC,,,5bbab3f3e4b47e3e23f9820765dbb45c,http://www.atariage.com/manual_thumbs.html?SoftwareID=1207 -Pitfall!,Activision,David Crane,,1982,AB-035-04,Rare,,A2600PAL,,,791bc8aceb6b0f4d9990d6062b30adfa,http://www.atariage.com/manual_thumbs.html?SoftwareID=1207 -Pitfall!,Activision,David Crane,,1982,AX-018,Common,,A2600NTSC,,,3e90cf23106f2e08b2781e41299de556,http://www.atariage.com/manual_thumbs.html?SoftwareID=1207 -Pitfall!,Activision,David Crane,,1982,AX-018,Common,,A2600NTSC,,,6fd7c7057eeab273b29c7aafc7429a96,http://www.atariage.com/manual_thumbs.html?SoftwareID=1207 -Pitfall!,CCE,David Crane,,,AX-018,Common,,A2600NTSC,,,f73d2d0eff548e8fc66996f27acf2b4b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1207 -Pitfighter,Atari,,Prototype,1984,,,A78S4,A7800NTSC,,,05f43244465943ce819780a71a5b572a, -Pizza Chef,CCE,,,,,,,A2600NTSC,,,82efe7984783e23a7c55266a5125c68e, -Planet Invaders,Atari,Charles Morgan,Hack,,,,,A2600NTSC,,,ae10527840a1ac24de43730645ed508d, -Planet Patrol,,,,1982,,,,A2600PAL,,,aafc79ffc32c4c9b2d73c8ada7602cfe, -Planet Patrol,CCE,,,,,,,A2600NTSC,,,79004f84bdeee78d142e445057883169, -Planet Patrol,Play Video,,,1982,,,,A2600PAL,,,bb745c893999b0efc96ea9029e3c62ca, -Planet Patrol,Spectravideo,,,,SA-202,Rare,,A2600PAL,,,d6acff6aed0f04690fe4024d58ff4ce3, -Planet Patrol,Spectravision,,,1982,SA-202,Rare,,A2600NTSC,,,043f165f384fbea3ea89393597951512, -Planet Patrol,Spectravision,,,1982,SA-202,Rare,,A2600PAL,,,69fac82cd2312dd9ce5d90e22e2f070a, -Planet Smashers,Atari,James V. Zalewski,,1990,CX7868,Rare,A78SG,A7800NTSC,,,33aea1e2b6634a1dec8c7006d9afda22,http://www.atariage.com/manual_thumbs.html?SoftwareID=2173 -Planet Smashers,Atari,James V. Zalewski,,1990,CX7868,Rare,A78SG,A7800PAL,,,2837a8fd49b7fc7ccd70fd45b69c5099,http://www.atariage.com/manual_thumbs.html?SoftwareID=2173 -Planet of the Apes,20th Century Fox,,Prototype,,,,,A2600NTSC,,,9efb4e1a15a6cdd286e4bcd7cd94b7b8, -Plaque Attack,Activision,Steve Cartwright,,,AX-027,Rare,,A2600PAL,,,3eccf9f363f5c5de0c8b174a535dc83b, -Plaque Attack,Activision,Steve Cartwright,,1983,AX-027,Rare,,A2600NTSC,,,32244e55ce6ec6bfbd763f33384bdc2e, -Plaque Attack,Activision,Steve Cartwright,,1983,AX-027,Rare,,A2600NTSC,,,da4e3396aa2db3bd667f83a1cb9e4a36, -Plaque Attack,Activision,Steve Cartwright,,1983,AX-027,Rare,,A2600PAL,,,7ced6709f091e79a2ab9575d3516a4ac, -Plaque Attack,CCE,Steve Cartwright,,,,,,A2600NTSC,,,de24f700fd28d5b8381de13abd091db9, -Plutos,Tynesoft,David Peacock & Kevin Franklin & Michael Owens,Prototype Hack,,,,A78SGR,A7800NTSC,,,86546808dc60961cdb1b20e761c50ab1,http://www.atariage.com/software_page.html?SoftwareLabelID=2764 -Polaris,Tigervision,,,,7-007,Extremely Rare,TV8K,A2600NTSC,,,ee8e2aa00e3a9cf1238157cbcff7de74, -Polaris,Tigervision,,,,7-007,Extremely Rare,TV8K,A2600PAL,,,203049f4d8290bb4521cc4402415e737, -Polaris,Tigervision,,Prototype,,,,TV8K,A2600NTSC,,,44f71e70b89dcc7cf39dfd622cfb9a27, -Polaris,Tigervision,Thomaz Jentzsch,Hack,,,,TV8K,A2600NTSC,,,87bea777a34278d29b3b6029833c5422, -Pole Position II,Atari,,,1987,CX7808,Common,,A7800NTSC,,,584582bb09ee8122e7fc09dc7d1ed813,http://www.atariage.com/manual_thumbs.html?SoftwareID=2145 -Pole Position II,Atari,,,1987,CX7808,Common,,A7800PAL,,,865457e0e0f48253b08f77b9e18f93b2,http://www.atariage.com/manual_thumbs.html?SoftwareID=2145 -Pole Position,Atari,,,,CX2694,Common,,A2600NTSC,,,56606b4d9109e2db36dea47cf7c8cca6, -Pole Position,Atari,,,,CX2694,Common,,A2600NTSC,,,5f39353f7c6925779b0169a87ff86f1e, -Pole Position,Atari,,,,CX2694,Common,,A2600PAL,,,b56264f738b2eb2c8f7cf5a2a75e5fdc, -Pole Position,CCE,,,,,,,A2600NTSC,,,3225676f5c0c577aeccfaa7e6bedd765, -Polo,Atari,,Prototype,,,,,A2600NTSC,,,14b1e30982962c72f426e2e763eb4274, -Polo,Atari,,Prototype,,,,,A2600NTSC,,,ee28424af389a7f3672182009472500c, -Pompeii,Apollo,,Prototype,,,,,A2600NTSC,,,a83b070b485cf1fb4d5a48da153fdf1a, -Pooyan,Konami-Gakken,,,1982,,,,A2600PAL,,,668dc528b7ea9345140f4fcfbecf7066, -Pooyan,Konami-Gakken,,,1982,,,,A2600PAL,,,89afff4a10807093c105740c73e9b544, -Pooyan,Konami-Gakken,,,1982,,Extremely Rare,,A2600NTSC,,,4799a40b6e889370b7ee55c17ba65141, -Popeye,Parker Bros,,,1983,PB5370,Common,PB8K,A2600NTSC,,,c7f13ef38f61ee2367ada94fdcc6d206, -Popeye,Parker Bros,,,1983,PB5370,Common,PB8K,A2600PAL,,,e9cb18770a41a16de63b124c1e8bd493, -Porky's,20th Century Fox,,,1983,11013,Rare,,A2600NTSC,,,f93d7fee92717e161e6763a88a293ffa, -Pressure Cooker,Activision,Garry Kitchen,,1983,AZ-032,Rare,,A2600NTSC,,,97d079315c09796ff6d95a06e4b70171, -Pressure Cooker,Activision,Garry Kitchen,,1983,AZ-032,Rare,,A2600PAL,,,525ea747d746f3e80e3027720e1fa7ac, -Pressure Cooker,CCE,Garry Kitchen,,,,,,A2600NTSC,,,027a59a575b78860aed780b2ae7d001d, -Pressure Gauge 2 Beta,,,Homebrew,,,,,A2600NTSC,,,6a03c28d505bab710bf20b954e14d521, -Pressure Gauge,,,Homebrew,,,,,A2600NTSC,,,30997031b668e37168d4d0e299ccc46f, -Pressure Gauge,,,Homebrew,,,,,A2600NTSC,,,de1a636d098349be11bbc2d090f4e9cf, -Private Eye,Activision,Bob Whitehead,,1983,AG-034-04,Rare,,A2600NTSC,,,bc24440b59092559a1ec26055fd1270e, -Private Eye,Activision,Bob Whitehead,,1983,AG-034-04,Rare,,A2600NTSC,,,ef3a4f64b6494ba770862768caf04b86, -Private Eye,Activision,Bob Whitehead,,1983,AG-034-04,Rare,,A2600PAL,,,1266b3fd632c981f3ef9bdbf9f86ce9a, -Private Eye,CCE,Bob Whitehead,,,,,,A2600NTSC,,,f9cef637ea8e905a10e324e582dd39c2, -Pro Wrestling,Absolute-Activision,,,,,,,A2600PAL,,,ec5d04b7e6cc6641d74d3ba7bb41ebc9, -Purple Bar Demo 2,,,Homebrew,,,,,A2600NTSC,,,9ca2deb61318eba4fb784d4bf7441d8b, -Purple Bar Demo,,,Homebrew,,,,,A2600NTSC,,,22f6b40fc82110d68e50a1208ae0bb97, -Purple Cross Demo,,,Homebrew,,,,,A2600NTSC,,,6e19428387686a77d8c8d2f731cb09e0, -Puzzle,,Colin Hughes,Homebrew,,,,,A2600NTSC,,,679d30c7886b283cbe1db4e7dbe5f2a6, -Puzzled World,,Cooper Black,,,,,,A2600PAL,,,8108ad2679bd055afec0a35a1dca46a4, -Pygmy,Starsoft,,,,,,,A2600PAL,,,3ff5165378213dab531ffa4f1a41ae45, -Pyramid War (a.k.a. Wuestenschlacht),Rainbow Vision,,,,,,,A2600PAL,,,5c0520c00163915a4336e481ca4e7ef4, -Pyramid War,Suntek,,,,4,Extremely Rare,,A2600PAL,,,37fd7fa52d358f66984948999f1213c5, -Q-bert's Qubes,Parker Bros,,,1983,PB5550,Extremely Rare,PB8K,A2600NTSC,,,517592e6e0c71731019c0cebc2ce044f, -Q-bert's Qubes,Parker Bros,,,1983,PB5550,Extremely Rare,PB8K,A2600NTSC,,,72b8dc752befbfb3ffda120eb98b2dd0, -Q-bert,,,Homebrew,2005,,,A7832,A7800NTSC,,,66e7230f7ef9d14db82d76b06b241bc0, -Q-bert,Atari,,,,CX26150,Rare,,A2600NTSC,,,484b0076816a104875e00467d431c2d2, -Q-bert,Atari,,,,CX26150,Rare,,A2600PAL,,,eb6d6e22a16f30687ade526d7a6f05c5, -Q-bert,Parker Bros,,,1983,PB5360,Common,,A2600PAL,,,1ede4f365ce1386d58f121b15a775e24, -Q-bert,Parker Bros,,,1983,PB5360,Common,,A2600PAL,,,8b40a9ca1cfcd14822e2547eaa9df5c1, -Qb (0.01),Retroactive,,,,,,,A2600NTSC,,,cff1e9170bdbc29859b815203edf18fa, -Qb (0.03),Retroactive,,,,,,,A2600NTSC,,,c482f8eebd45e0b8d479d9b71dd72bb8, -Qb (0.04),Retroactive,,,,,,,A2600NTSC,,,d787ec6785b0ccfbd844c7866db9667d, -Qb (0.05) (Mac),Retroactive,,,,,,,A2600NTSC,,,35fa32256982774a4f134c3347882dff, -Qb (0.05),Retroactive,,,,,,,A2600NTSC,,,cf0c593c563c84fdaf0f741adb367445, -Qb (0.06),Retroactive,,,,,,,A2600NTSC,,,b15026b43c6758609667468434766dd8, -Qb (0.10) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,d010e3dfe7366e47561c088079a59439, -Qb (0.10),Retroactive,,,,,,,A2600NTSC,,,8712cceec5644aacc2c21203d9ebe2ec, -Qb (0.10),Retroactive,,,,,,,A2600PAL,,,4233eb824c2b4811abef9b6d00355ae9, -Qb (0.11) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,376944889dcfa96c73d3079f308e3d32, -Qb (0.11),Retroactive,,,,,,,A2600NTSC,,,6803fa7c2c094b428b859a58dc1dd06a, -Qb (0.11),Retroactive,,,,,,,A2600PAL,,,5a5390f91437af9951a5f8455b61cd43, -Qb (0.12) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,cdc1a5c61d7488eadc9aba36166b253d, -Qb (0.12),Retroactive,,,,,,,A2600NTSC,,,0906c6e0e4bda9c10cfa4c5fc64d2f4b, -Qb (0.12),Retroactive,,,,,,,A2600PAL,,,ae682886058cd6981c4b8e93e7b019cf, -Qb (1.00) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,7bc4fd254ec8c0a25a13f02fd3f762ff, -Qb (1.00),Retroactive,,,,,,,A2600NTSC,,,8b504b417c8626167a7e02f44229f0e7, -Qb (1.00),Retroactive,,,,,,,A2600PAL,,,8fffc8f15bb2e6d24e211884a5479aa5, -Qb (1.01),Retroactive,,,,,,,A2600NTSC,,,8ccaa442d26b09139685f5b22bf189c4, -Qb (2.00) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,f33f1d0f7819c74148dacb48cbf1c597, -Qb (2.00),Retroactive,,,,,,,A2600NTSC,,,d0e9beb2347595c6c7d158e9d83d2da8, -Qb (2.00),Retroactive,,,,,,,A2600PAL,,,c866c995c0d2ca7d017fef0fc0c2e268, -Qb (2.03),Retroactive,,,,,,,A2600NTSC,,,98ccd15345b1aee6caf51e05955f0261, -Qb (2.03),Retroactive,,,,,,,A2600PAL,,,4c030667d07d1438f0e5c458a90978d8, -Qb (2.04) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,4dd6c7ab9ef77f2b4950d8fc7cd42ee1, -Qb (2.04),Retroactive,,,,,,,A2600NTSC,,,ce64812eb83c95723b04fb56d816910b, -Qb (2.04),Retroactive,,,,,,,A2600PAL,,,eb9712e423b57f0b07ccd315bb9abf61, -Qb (2.05),Retroactive,,,,,,,A2600NTSC,,,659a20019de4a23c748ec2292ea5f221, -Qb (2.05),Retroactive,,,,,,,A2600PAL,,,c92cfa54b5d022637fdcbdc1ef640d82, -Qb (2.06) (Stella),Retroactive,,,,,,,A2600NTSC,,,e800e4aec7c6c54c9cf3db0d1d030058, -Qb (2.06),Retroactive,,,,,,,A2600NTSC,,,2e0aed5bb619edcefa3fafb4fbe7c551, -Qb (2.06),Retroactive,,,,,,,A2600PAL,,,05eb4347f0ec8f4783983ca35ffd8d1b, -Qb (2.07) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,cea9f72036dc6f7af5eff52459066290, -Qb (2.07),Retroactive,,,,,,,A2600NTSC,,,3a51a6860848e36e6d06ffe01b71fb13, -Qb (2.07),Retroactive,,,,,,,A2600PAL,,,fae0b86934a7c5a362281dffebdb43a0, -Qb (2.08) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,318046ae3711c05fd16e479b298e5fcc, -Qb (2.08) (Test Jump),Retroactive,,,,,,,A2600NTSC,,,dcba0e33aa4aed67630a4b292386f405, -Qb (2.08),Retroactive,,,,,,,A2600NTSC,,,57a66b6db7efc5df17b0b0f2f2c2f078, -Qb (2.08),Retroactive,,,,,,,A2600PAL,,,876a953daae0e946620cf05ed41989f4, -Qb (2.09) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,67ce6cdf788d324935fd317d064ed842, -Qb (2.09),Retroactive,,,,,,,A2600NTSC,,,e2389c0be5b5b84e0d3ca36ec7e67514, -Qb (2.09),Retroactive,,,,,,,A2600PAL,,,008543ae43497af015e9428a5e3e874e, -Qb (2.11) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,2808dc745ff4321dc5c8122abef6711f, -Qb (2.11),Retroactive,,,,,,,A2600NTSC,,,67bd3d4dc5ac6a42a99950b4245bdc81, -Qb (2.11),Retroactive,,,,,,,A2600PAL,,,283dee88f295834c4c077d788f151125, -Qb (2.12) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,94e4c9b924286038527f49cdc20fda69, -Qb (2.12),Retroactive,,,,,,,A2600NTSC,,,35163b56f4a692a232ae96ad3e23310f, -Qb (2.12),Retroactive,,,,,,,A2600PAL,,,b3017e397f74efd53caf8fae0a38e3fe, -Qb (2.14) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,52e1954dc01454c03a336b30c390fb8d, -Qb (2.14),Retroactive,,,,,,,A2600NTSC,,,6e5d5ba193d2540aec2e847aafb2a5fb, -Qb (2.14),Retroactive,,,,,,,A2600PAL,,,4f634893d54e9cabe106e0ec0b7bdcdf, -Qb (2.15) (Stella-compatable),Retroactive,,,,,,,A2600NTSC,,,34e37eaffc0d34e05e40ed883f848b40, -Qb (2.15),Retroactive,,,,,,,A2600NTSC,,,ac53b83e1b57a601eeae9d3ce1b4a458, -Qb (2.15),Retroactive,,,,,,,A2600PAL,,,9281eccd7f6ef4b3ebdcfd2204c9763a, -Qb (Early Development 1),Retroactive,,,,,,,A2600NTSC,,,78963290052fd17c6c7998305ab3a6a0, -Qb (Early Development 2),Retroactive,,,,,,,A2600NTSC,,,9d2f05d0fe8b2dfcf770b02eda066fc1, -Qb (Early Development 3),Retroactive,,,,,,,A2600NTSC,,,96f806fc62005205d851e758d050dfca, -Qb (Release Candidate #1) (Stella-Compatable),Retroactive,,,,,,,A2600NTSC,,,c504a71c411a601d1fc3173369cfdca4, -Qb (Release Candidate #1),Retroactive,,,,,,,A2600NTSC,,,17512d0c38f448712f49f36f9d185c4e, -Qb (Release Candidate #1),Retroactive,,,,,,,A2600PAL,,,ae0d4f3396cb49de0fabdff03cb2756f, -Quadrun,Atari,,,,CX2686,Extremely Rare,,A2600NTSC,,,392d34c0498075dd58df0ce7cd491ea2, -Quest (Early Version),,Chris Larkin,Homebrew,,,,,A2600NTSC,,,152c253478b009c275e18cd731b48561, -Quest for Quintana Roo,Sunrise,,,,6057 A227,Extremely Rare,,A2600NTSC,,,a0675883f9b09a3595ddd66a6f5d3498, -Quest for Quintana Roo,Telegames,,,,,,,A2600PAL,,,f736864442164b29235e8872013180cd, -Quick Step!,Imagic,Dave Johnson,,1983,O3211,Rare,,A2600NTSC,,,7eba20c2291a982214cc7cbe8d0b47cd, -Quick Step!,Imagic,Dave Johnson,,1983,O3211,Rare,,A2600PAL,,,84290e333ff7567c2380f179430083b8, -Quick Step!,Imagic,Dave Johnson,,1983,O3211,Rare,,A2600PAL,,,e72ee2d6e501f07ec5e8a0efbe520bee, -RUN Platform Demo,,,,,,,,A2600NTSC,,,0f341d1f4e144e3163d9a5fc5a662b79, -Race Demo,,,,,,,,A2600NTSC,,,1a23540d91f87584a04f184304a00648, -Racquetball,Apollo,,,1981,AP 2003,Uncommon,,A2600NTSC,,,a20d931a8fddcd6f6116ed21ff5c4832, -Racquetball,Apollo,,,1981,AP 2003,Uncommon,,A2600NTSC,,,cbced209dd0575a27212d3eee6aee3bc, -Rad Action Pak - Kung-Fu -Frostb -Freeway,HES,,,1990,,,,A2600PAL,,,56300ed31fef018bd96768ccc982f7b4, -Radar Lock,Atari,,,1989,CX26176,Rare,A16KR,A2600NTSC,,,baf4ce885aa281fd31711da9b9795485, -Radar Lock,Atari,,,1989,CX26176,Rare,A16KR,A2600PAL,,,04856e3006a4f5f7b4638da71dad3d88, -Radar,CCE,,,,,,,A2600PAL,,,247fa1a29ad90e64069ee13d96fea6d6, -Radial Pong (Version 10),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,0f14c03050b35d6b1d8850b07578722d, -Radial Pong (Version 11),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,43f33c6dfdeaf5138ce6e6968ad7c5ce, -Radial Pong (Version 2),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,6337927ad909aa739d6d0044699a916d, -Radial Pong (Version 3),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,f1e375d921858467166e53bcec05803f, -Radial Pong (Version 4),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,481f9a742052801cc5f3defb41cb638e, -Radial Pong (Version 5),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,fd9b321cee5fbb32c39ba3ca5d9ec7cf, -Radial Pong (Version 6),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,64b8e19c767191ccdc97acc6904c397b, -Radial Pong (Version 7),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,2450dfa1df70d12b60683185775efed8, -Radial Pong (Version 8),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,9f9ee0f60c119c831e80694b6678ca1a, -Radial Pong (Version 9),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,05824fcbe615dbca836d061a140a50e0, -Radial Pong (initial version),,Jeffry Johnston,Homebrew,,,,,A2600NTSC,,,200309c8fba0f248c13751ed4fc69bab, -Raft Rider,US Games,,,1982,VC 2006,Extremely Rare,,A2600NTSC,,,92a1a605b7ad56d863a56373a866761b, -Raiders of the Lost Ark,Atari,Howard Scott Warshaw,,1982,CX2659,Common,A8K,A2600NTSC,,,f724d3dd2471ed4cf5f191dbb724b69f,http://www.atariage.com/manual_html_page.html?SoftwareID=1240 -Raiders of the Lost Ark,Atari,Howard Scott Warshaw,,1982,CX2659,Common,A8K,A2600PAL,,,1cafa9f3f9a2fce4af6e4b85a2bbd254,http://www.atariage.com/manual_html_page.html?SoftwareID=1240 -Rainbow Invaders (half complete),,Silvio Mogno,Homebrew,,,,,A2600NTSC,,,8f98519a91dbbf4864f135a10050d9ed, -Ram It,Telegames,,,1982,,,,A2600PAL,,,f2f2cb35fdef063c966c1f5481050ea2, -Ram It,Telegames,,,1982,1004,Extremely Rare,,A2600PAL,,,7096a198531d3f16a99d518ac0d7519a, -Rambo in Afghanistan,,Kyle Pittman,Hack,,,,,A2600NTSC,,,2eda6a49a49fcb2b674ea9e160b6a617, -Rampage!,Activision,Bob Polaro,,1989,AK-049,Rare,A16K,A2600NTSC,,,0cb3211ec39a66e225e8faa9fbdb0757,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=397 -Rampage!,Activision,Bob Polaro,,1989,AK-049,Rare,A16K,A2600NTSC,,,5e1b4629426f4992cf3b2905a696e1a7,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=397 -Rampage!,Activision,Bob Polaro,,1989,AK-049,Rare,A16K,A2600PAL,,,a11099b6ec24e4b00b8795744fb12005,http://www.atariage.com/manual_thumbs.html?SoftwareLabelID=397 -Rampage,Activision,,,1989,AM-049,Rare,A78AC,A7800NTSC,,,ac03806cef2558fc795a7d5d8dba7bc0,http://www.atariage.com/manual_thumbs.html?SoftwareID=2174 -Raumpatrouille,Starsoft,,,,,,,A2600PAL,,,ca50cc4b21b0155255e066fcd6396331, -Reactor,Parker Bros,,,1982,PB5330,Uncommon,,A2600NTSC,,,9f8fad4badcd7be61bbd2bcaeef3c58f, -Reactor,Parker Bros,,,1982,PB5330,Uncommon,,A2600PAL,,,4904a2550759b9b4570e886374f9d092, -RealSports Baseball,Atari,,,1982,CX2640,Uncommon,,A2600NTSC,,,eb634650c3912132092b7aee540bbce3, -RealSports Basketball,Atari,,Prototype,,,,,A2600PAL,,,8a183b6357987db5170c5cf9f4a113e5, -RealSports Basketball,Atari,Thomas Jentzsch,Prototype Hack,,,,,A2600NTSC,,,5524718a19107a04ec3265c93136a7b5, -RealSports Boxing,Atari,,,1987,CX26135,Uncommon,A16K,A2600NTSC,,,3177cc5c04c1a4080a927dfa4099482b, -RealSports Boxing,Atari,,,1987,CX26135,Uncommon,A16K,A2600PAL,,,4abb4c87a4c5f5d0c14ead2bb36251be, -RealSports Football,Atari,,,1982,CX2668,Common,,A2600NTSC,,,7ad257833190bc60277c1ca475057051, -RealSports Soccer,Atari,,,1983,CX2667,Uncommon,,A2600NTSC,,,08f853e8e01e711919e734d85349220d, -RealSports Soccer,Atari,,,1983,CX2667,Uncommon,,A2600PAL,,,b9336ed6d94a5cc81a16483b0a946a73, -RealSports Tennis,Atari,,,1983,CX2680,Uncommon,,A2600NTSC,,,dac5c0fe74531f077c105b396874a9f1, -RealSports Tennis,Atari,,,1983,CX2680,Uncommon,,A2600PAL,,,4e66c8e7c670532569c70d205f615dad, -RealSports Tennis,Atari,,,1983,CX2680,Uncommon,,A2600PAL,,,c7eab66576696e11e3c11ffff92e13cc, -RealSports Tennis,CCE,,,,,,,A2600NTSC,,,53b66f11f67c3b53b2995e0e02017bd7, -RealSports Volleyball,Atari,,,1982,CX2666,Uncommon,,A2600NTSC,,,aed0b7bd64cc384f85fdea33e28daf3b, -RealSports Volleyball,Atari,,,1982,CX2666,Uncommon,,A2600PAL,,,4ca0959f846d2beada18ecf29efe137e, -Realsports Baseball,Atari,,,1988,CX7834,Common,A78S4,A7800NTSC,,,383ed9bd1efb9b6cb3388a777678c928,http://www.atariage.com/manual_thumbs.html?SoftwareID=2146 -Red And White Checkerboard Demo,,,,,,,,A2600NTSC,,,a8d4a9500b18b0a067a1f272f869e094, -Red Pong Number 2 Demo 2,,,,,,,,A2600NTSC,,,79b649fb812c50b4347d12e7ddbb8400, -Red Pong Number 2 Demo,,,,,,,,A2600NTSC,,,874c76726f68c166fcfac48ce78eef95, -Register Twiddler Demo 2,,,,,,,,A2600NTSC,,,7450ae4e10ba8380c55b259d7c2b13e8, -Register Twiddler Demo,,,,,,,,A2600NTSC,,,eb9f8b84c193d9d93a58fca112aa39ed, -Rescue 1 Demo (This Planet Sucks proto),,,Homebrew,,,,,A2600NTSC,,,225522777dc7155627808bde0c1d0ef0, -Rescue 2 Demo (This Planet Sucks proto),,,Homebrew,,,,,A2600NTSC,,,8530caaaf40acbdcd118c282b5f8a37a, -Rescue 3 Demo (This Planet Sucks proto),,,Homebrew,,,,,A2600NTSC,,,7f790939f7eaa8c47a246c4283981f84, -Rescue 4 Demo (This Planet Sucks proto),,,Homebrew,,,,,A2600NTSC,,,e56da674188ba2f02c7a0a343a01236f, -Rescue Bira Bira,,Chris Cracknell,Hack,,,,,A2600NTSC,,,8a9d874a38608964f33ec0c35cab618d, -Rescue Terra I,Venture Vision,,,1982,VV2001,Extremely Rare,,A2600NTSC,,,60a61da9b2f43dd7e13a5093ec41a53d, -Rescue on Fractalus,Atari,,Prototype,,CX7816,,A7832,A7800NTSC,,,8f7eb10ad0bd75474abf0c6c36c08486,http://www.atariage.com/software_page.html?SoftwareLabelID=2693 -Resgate Espacial,CCE,,,,,,,A2600NTSC,,,42249ec8043a9a0203dde0b5bb46d8c4, -Return of Mario Bros.,,Philip R. Frey,Hack,,,,,A2600NTSC,,,5e1cd11a6d41fc15cf4792257400a31e, -Revenge of the Beefsteak Tomatoes,20th Century Fox,,,1983,11016,Rare,,A2600NTSC,,,4f64d6d0694d9b7a1ed7b0cb0b83e759, -Riddle of the Sphinx,Imagic,Bob Smith,,1982,IA3600,Uncommon,,A2600NTSC,,,a995b6cbdb1f0433abc74050808590e6, -Riddle of the Sphinx,Imagic,Bob Smith,,1982,IA3600,Uncommon,,A2600PAL,,,083e7cae41a874b2f9b61736c37d2ffe, -Rip Off,,Bob DeCrescenzo,Homebrew,2012,,,A7816,A7800NTSC,,,43525a0405184875c2ecfd0196886a34, -Rip Off,,Bob DeCrescenzo,Homebrew,2012,,,A7816,A7800PAL,,,106b409c6f4c219b1a3b3d099ead3b2b, -River Patrol,Tigervision,,,,7-004,Extremely Rare,TV8K,A2600NTSC,,,31512cdfadfd82bfb6f196e3b0fd83cd, -River Raid (Brazil),,Carol Shaw,,,,,,A2600NTSC,,,a94528ae05dd051894e945d4d2349b3b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid (Tanks),Activision,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,c74bfd02c7f1877bbe712c1da5c4c194,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid II (a.k.a. Katastrophen-Einsatz),Starsoft,,,,,,,A2600PAL,,,65ba1a4c643d1ab44481bdddeb403827, -River Raid II,Activision,David Lubar,,1988,AK-048-04,Extremely Rare,,A2600NTSC,,,ab56f1b2542a05bebc4fbccfc4803a38, -River Raid II,Activision,David Lubar,,1988,AK-048-04,Extremely Rare,,A2600NTSC,,,deb39482e77f984d4ce73be9fd8adabd, -River Raid II,Activision,David Lubar,,1988,AK-048-04,Extremely Rare,,A2600PAL,,,b049fc8ac50be7c2f28418817979c637, -River Raid Plus,Activision,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,304512528a5530a9361e8a231ed9a6de,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Activision,Carol Shaw,,1982,,,,A2600NTSC,,,33ed6dfac4b9ea2f81f778ceddbb4a75,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Activision,Carol Shaw,,1982,,,,A2600PAL,,,1e89f722494608d6ea15a00d99f81337,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Activision,Carol Shaw,,1982,AX-020,Uncommon,,A2600NTSC,,,291cc37604bc899e8e065c30153fc4b9,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Activision,Carol Shaw,,1982,AX-020,Uncommon,,A2600NTSC,,,393948436d1f4cc3192410bb918f9724,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Activision,Carol Shaw,,1982,AX-020,Uncommon,,A2600NTSC,,,95c4576d6a14e2debfa0fd6f6ec254ab,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Activision,Carol Shaw,,1982,AX-020,Uncommon,,A2600PAL,,,927d422d6335018da469a9a07cd80390,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,CCE,Carol Shaw,,,,,,A2600NTSC,,,59f596285d174233c84597dee6f34f1f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,Polyvox,,,,,,,A2600NTSC,,,6ce2110ac5dd89ab398d9452891752ab,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,SpkSoft 98,,Hack,,,,,A2600NTSC,,,edf69b123e06eaf8663cc78d8aeba06e,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -River Raid,SpkSoft,,Hack,,,,,A2600NTSC,,,dd92d6ad50976f881d86b52d38616118,http://www.atariage.com/manual_thumbs.html?SoftwareID=1255 -Road Runner,Atari,,,1989,CX2663,Extremely Rare,,A2600PAL,,,2bd00beefdb424fa39931a75e890695d, -Road Runner,Atari,,,1989,CX2663,Extremely Rare,,A2600PAL,,,c3a9550f6345f4c25b372c42dc865703, -Road Runner,CCE,,,,,,,A2600NTSC,,,7d3cdde63b16fa637c4484e716839c94, -Robin Hood,Xonox,,,,99005,Extremely Rare,,A2600NTSC,,,72a46e0c21f825518b7261c267ab886e, -Robin Hood,Xonox,,,1983,99005,Extremely Rare,,A2600PAL,,,db76f7a0819659d9e585f2cdde9175c7, -Robin Hood,Xonox,,,1983,99005,Extremely Rare,,A2600PAL,,,dd7598b8bcb81590428900f71b720efb, -Robot City (Version 0.12),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,3e1682ddaec486d8b6b90b527aaa0fc4, -Robot City (Version 0.18),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,f954381f9e0f2009d1ac40dedd777b1a, -Robot City (Version 0.21),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,97cd63c483fe3c68b7ce939ab8f7a318, -Robot Fight (a.k.a. Space Robot),HomeVision,,,,1,Extremely Rare,,A2600PAL,,,1bef389e3dd2d4ca4f2f60d42c932509, -Robot Finds Kitten,,Thomas Mathys,Homebrew,2004,,,A7832,A7800NTSC,,,505f05e7f161f62ccd749dab3c4a204b, -Robot Tank TC,Activision,Thomas Jentzsch,Hack,,,,DC8K,A2600NTSC,,,fbb0151ea2108e33b2dbaae14a1831dd, -Robot Tank,Activision,Alan Miller,,1983,AZ-028,Rare,DC8K,A2600NTSC,,,4f618c2429138e0280969193ed6c107e, -Robot Tank,Activision,Alan Miller,,1983,AZ-028,Rare,DC8K,A2600PAL,,,f687ec4b69611a7f78bd69b8a567937a, -Robotron 2084,Atari,David Brown,,1987,CX7809,Common,,A7800NTSC,,,66ecaafe1b82ae68ffc96267aaf7a4d7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2147 -Roc n' Rope,CBS Electronics,,,,2667,Rare,,A2600PAL,,,0173675d40a8d975763ee493377ca87d, -Roc n' Rope,Coleco,,,1984,2667,Rare,,A2600NTSC,,,65bd29e8ab1b847309775b0de6b2e4fe, -Rodeo Champ,,,,,,,,A2600PAL,,,3f96eb711928a6fac667c04ecd41f59f, -Room of Doom,CommaVid,,,,CM-004,Extremely Rare,,A2600NTSC,,,67931b0d37dc99af250dd06f1c095e8d, -Room of Doom,CommaVid,,,,CM-004,Extremely Rare,,A2600PAL,,,685e9668dc270b6deeb9cfbfd4d633c3, -Rotating Colors Demo 1 by Junkosoft,Junkosoft,,,,,,,A2600NTSC,,,cbb0ee17c1308148823cc6da85bff25c, -Rotating Colors Demo 2 by Junkosoft,Junkosoft,,,,,,,A2600NTSC,,,c1b038ce5cb6d85e956c5509b0e0d0d8, -SALT Diagnostics,,,,,,,,A2600NTSC,,,a8916734ff8c64ec3342f4c73fd5b57d, -SCSIcide (1.00 First Playable Version),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,eae0c06ee61c63b81cd016096fc901b0, -SCSIcide (1.10),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,7991e1797e5e9f311fd957e62d889dff, -SCSIcide (1.20),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,6538e454b0498ad2befe1ef0f87815c0, -SCSIcide (1.30) (CGE 2001 Release),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,523f5cbb992f121e2d100f0f9965e33f, -SCSIcide (1.31),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,843435eb360ed72085f7ab9374f9749a, -SCSIcide (1.32),Hozer Video Games,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,9efa877a98dd5a075e058214da428abb, -SCSIcide (pre-release 1),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,b1a6c96e9093352106bc335e96caa154, -SCSIcide (pre-release 2),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,07a3af1e18b63765b6807876366f5e8a, -SCSIcide (pre-release 3),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,d483f65468d9a265661917bae1a54f3e, -SCSIcide (pre-release 4),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,34340c8eecd1e557314789cc6477e650, -SCSIcide (pre-release 5),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,f34dd3b8156aaf113cb621b2e51d90b8, -SCSIcide (pre-release 6),,Joe Grand,Homebrew,,,,,A2600NTSC,Paddles,Paddles,a0028f057d496f22b549fd8deecc6f78, -Sabotage,Ultravision,,,,,,,A2600NTSC,,,88d8a1accab58cf1abb043613cf185e9, -Saboteur,,,Prototype,,CX26119,,,A2600NTSC,,,1ec57bbd27bdbd08b60c391c4895c1cf, -Santa Simon,,,Homebrew,,,,A7848,A7800NTSC,,,ae85689b21bdf85cb9dc57c3b1fec9db, -Save Mary,,Tod Frye,,,,,,A2600NTSC,,,4d502d6fb5b992ee0591569144128f99, -Save Our Ship (unknown variation),,,,,,,,A2600PAL,,,0f8043715d66a4bbed394ef801d99862, -Save Our Ship,,,,,,,,A2600PAL,,,49571b26f46620a85f93448359324c28, -Save Our Ship,,,,,,Extremely Rare,,A2600NTSC,,,ed1a784875538c7871d035b7a98c2433, -Save Our Ship,TechnoVision,,,,,Extremely Rare,,A2600PAL,,,01297d9b450455dd716db9658efb2fae, -Schiessbude,Starsoft,,,,,,,A2600PAL,,,2516f4f4b811ede4ecf6fbeb5d54a299, -Schnapp die Apfeldiebe (a.k.a. Catch Time),Starsoft,,,,,,,A2600PAL,,,f6f1b27efc247a0e8d473ddb4269ff9e, -Schnecke und Eichhoernchen,Bitcorp,,,1983,PG208,Rare,,A2600PAL,,,898b5467551d32af48a604802407b6e8, -Schussel - der Polizistenschreck,Starsoft,,,,,Extremely Rare,,A2600PAL,,,7ff53f6922708119e7bf478d7d618c86, -Scramble,,Bob DeCrescenzo,Hack,2012,,,,A7800NTSC,,,57651b6c8e62811fab0361cea537b79c, -Scramble,,Bob DeCrescenzo,Hack,2012,,,,A7800NTSC,,,c265cfd65534a4514f226cb4c7f7d6bf, -Scramble,,Bob DeCrescenzo,Hack,2012,,,,A7800PAL,,,1ee26fc6b06b4c9ba74931914b7e719d, -Scramble,,Bob DeCrescenzo,Hack,2012,,,,A7800PAL,,,65fe82f419f6583a0f9a736242cb303d, -Scrapyard Dog,Atari,,,1990,CX7879,Scarce,A78SG,A7800NTSC,,,980c35ae9625773a450aa7ef51751c04,http://www.atariage.com/manual_thumbs.html?SoftwareID=2148 -Scrapyard Dog,Atari,,,1990,CX7879,Scarce,A78SG,A7800PAL,,,53db322c201323fe2ca8f074c0a2bf86,http://www.atariage.com/manual_thumbs.html?SoftwareID=2148 -Scroller Demo,,Bob Colbert,,,,,,A2600NTSC,,,0f2e09c71cc216f79d22a804152ba24b, -Scrolling Playfield 1 by Junkosoft,Junkosoft,,,,,,,A2600NTSC,,,0d07d2c1be1a5eaaea235a533bcda781, -Scrolling Playfield 2 by Junkosoft,Junkosoft,,,,,,,A2600NTSC,,,f6c13e816e58c8c62f82b2c8b91a2d67, -Scrolling Playfield 3 by Junkosoft,Junkosoft,,,,,,,A2600NTSC,,,a6737c81542a99ee71cb5f5ff14703d9, -Scuba Diver,Panda,,,,104,Rare,,A2600NTSC,,,19e761e53e5ec8e9f2fceea62715ca06, -Sea Hawk (a.k.a. Overkill-RVision),Sancho,,,1982,,,,A2600PAL,,,74d072e8a34560c36cacbc57b2462360, -Sea Hawk,CCE,,,,,,,A2600NTSC,,,3fd53bfeee39064c945a769f17815a7f, -Sea Hawk,Froggo,,,1987,FG 1008,Rare,,A2600NTSC,,,07f42847a79e4f5ae55cc03304b18c25, -Sea Hawk,Panda,,,,108,Rare,,A2600NTSC,,,624e0a77f9ec67d628211aaf24d8aea6, -Sea Hunt,CCE,,,,,,,A2600NTSC,,,d8acaa980cda94b65066568dd04d9eb0, -Sea Hunt,Froggo,,,1987,FG 1009,Rare,,A2600NTSC,,,5dccf215fdb9bbf5d4a6d0139e5e8bcb, -Sea Monster,Bitcorp,,,,,,,A2600PAL,,,2124cf92978c46684b6c39ccc2e33713, -Sea Monster,Bitcorp,,,,PG201,Rare,,A2600PAL,,,68489e60268a5e6e052bad9c62681635, -Sea Monster,Bitcorp,,,,PG201,Rare,,A2600PAL,,,b79087a8f2f54337d6a8fa56616dee1c, -Seaquest,Activision,Steve Cartwright,,1983,AX-022,Rare,,A2600NTSC,,,240bfbac5163af4df5ae713985386f92, -Seaquest,Activision,Steve Cartwright,,1983,AX-022,Rare,,A2600NTSC,,,ebcbc8a181a738e13df6216e5c329230, -Seaquest,Activision,Steve Cartwright,,1983,AX-022,Rare,,A2600PAL,,,5b6f5bcbbde42fc77d0bdb3146693565, -Seaquest,Activision,Steve Cartwright,,1983,AX-022,Rare,,A2600PAL,,,fd0e5148162e8ec6719445d559f018a9, -Seaquest,CCE,Steve Cartwright,,,AX-022,Rare,,A2600NTSC,,,79c27f90591e3fdc7d2ed020ecbedeb3, -Secret Agent,Data Age,,Prototype,,,,,A2600NTSC,,,605fd59bfef88901c8c4794193a4cbad, -Secret Quest,Atari,,,1989,CX26170,Rare,A16KR,A2600NTSC,,,fc24a94d4371c69bc58f5245ada43c44, -Secret Quest,Atari,,,1989,CX26170,Rare,A16KR,A2600PAL,,,2d2c5f0761e609e3c5228766f446f7f8, -See Saw,Starsoft,,,,,,,A2600PAL,,,f3dfae774f3bd005a026e29894db40d3, -See Saw,Starsoft,Cooper Black,,,,,,A2600PAL,,,efffafc17b7cb01b9ca35324aa767364, -Sentinel,Atari,,,1990,CX26183,Rare,A16K,A2600NTSC,Lightgun,Lightgun,8da51e0c4b6b46f7619425119c7d018e, -Sentinel,Atari,,Prototype,1988,,,A78SG,A7800NTSC,Lightgun,Lightgun,b697d9c2d1b9f6cb21041286d1bbfa7f,http://www.atariage.com/manual_thumbs.html?SoftwareID=2228 -Sentinel,Atari,,Prototype,1988,,,A78SG,A7800PAL,Lightgun,Lightgun,5469b4de0608f23a5c4f98f331c9e75f,http://www.atariage.com/manual_thumbs.html?SoftwareID=2228 -Sesam - Oeffne Dich (a.k.a. Open Sesame),Bitcorp,,,,,,,A2600PAL,,,90578a63441de4520be5324e8f015352, -Sesam - Oeffne Dich (a.k.a. Open Sesame),Bitcorp,,,,PG204,Rare,,A2600PAL,,,28d5df3ed036ed63d33a31d0d8b85c47, -Sesam - Oeffne Dich (a.k.a. Open Sesame),Bitcorp,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,c880c659cdc0f84c4a66bc818f89618e, -Shark Attack,Apollo,,,1982,AP 2005,Uncommon,,A2600NTSC,,,54f7efa6428f14b9f610ad0ca757e26c, -Ship Demo (V 10),,,,,,,,A2600NTSC,,,1db3bc4601f22cf43be7ce015d74f59a, -Ship Demo (V 15),,,,,,,,A2600NTSC,,,85e48d68c8d802e3ba9d494a47d6e016, -Ship Demo (V 1501),,,,,,,,A2600NTSC,,,a0563dd6d8215c38c488fbbd61435626, -Ship Demo (V 1502),,,,,,,,A2600NTSC,,,1b1daaa9aa5cded3d633bfcbeb06479c, -Ship Demo,,,,,,,,A2600NTSC,,,90b1799dddb8bf748ee286d22e609480, -Shootin' Gallery,Imagic,Dennis Koble,,1982,IA3410,Extremely Rare,,A2600NTSC,,,b5a1a189601a785bdb2f02a424080412, -Shooting Arcade,Atari,Tod Frye,,,CX26169,,,A2600NTSC,,,15c11ab6e4502b2010b18366133fc322, -Shuttle Orbiter,Avalon Hill,,,,50040,Unbelievably Rare,,A2600NTSC,,,25b6dc012cdba63704ea9535c6987beb, -Sinistar,Atari,,Prototype,,,,,A2600NTSC,,,1e85f8bccb4b866d4daa9fcf89306474, -Sinistar,Atari,,Prototype,,CX26122,,,A2600NTSC,,,ea38fcfc06ad87a0aed1a3d1588744e4, -Sir Lancelot,Xonox,,,1983,99006,Extremely Rare,,A2600NTSC,,,4c8970f6c294a0a54c9c45e5e8445f93, -Sir Lancelot,Xonox,,,1983,99006,Extremely Rare,,A2600NTSC,,,7ead257e8b5a44cac538f5f54c7a0023, -Sir Lancelot,Xonox,,,1983,99006,Extremely Rare,,A2600PAL,,,dd0cbe5351551a538414fb9e37fc56e8, -Sirius,Tynesoft,Kevin Franklin,Prototype Hack,,,,A78SGR,A7800NTSC,,,2d643ac548c40e58c99d0fe433ba4ba0,http://www.atariage.com/software_page.html?SoftwareLabelID=2765 -Skate Boardin',Absolute,David Crane,,1987,AZ-042/AG-042,Rare,,A2600NTSC,,,f847fb8dba6c6d66d13724dbe5d95c4d, -Skate Boardin',Activision,David Crane,,1987,AZ-042,Extremely Rare,,A2600PAL,,,abe40542e4ff2d1c51aa2bb033f09984, -Skeet Shoot,Apollo,,,1981,AP 1001,Rare,,A2600NTSC,,,39c78d682516d79130b379fa9deb8d1c, -Skeet Shoot,Apollo,,,1981,AP 1001,Rare,,A2600NTSC,,,5f2b4c155949f01c06507fb32369d42a, -Skeleton (older version 2),,Eric Ball,,,,New Release,,A2600NTSC,,,4189adfc1b30c121248876e3a1a3ac7e, -Skeleton (older version),,Eric Ball,,,ELB002,New Release,,A2600NTSC,,,40e12c008037a323a1290c8fa4d2fe7f, -Skeleton (older version),,Eric Ball,,,ELB002,New Release,,A2600PAL,,,8e42674972d6805068fc653e014370fd, -Skeleton,,Eric Ball,,,ELB002,New Release,,A2600NTSC,,,28a4cd87fb9de4ee91693a38611cb53c, -Skeleton,,Eric Ball,,,ELB002,New Release,,A2600PAL,,,8e887d1ba5f3a71ae8a0ea16a4af9fc9, -Ski Hunt,,,,,,Extremely Rare,,A2600NTSC,,,8654d7f0fb351960016e06646f639b02, -Ski Run,,,,,TP-607,Extremely Rare,,A2600PAL,,,f10e3f45fb01416c87e5835ab270b53a, -Skiing (32-in-1),Atari,Bob Whitehead,,,,,,A2600PAL,,,367411b78119299234772c08df10e134,http://www.atariage.com/manual_thumbs.html?SoftwareID=1280 -Skiing,Activision,Bob Whitehead,,1980,AG-005,Uncommon,,A2600NTSC,,,0d90a0ee73d55539b7def24c88caa651,http://www.atariage.com/manual_thumbs.html?SoftwareID=1280 -Skiing,Activision,Bob Whitehead,,1980,AG-005,Uncommon,,A2600NTSC,,,60bbd425cb7214ddb9f9a31948e91ecb,http://www.atariage.com/manual_thumbs.html?SoftwareID=1280 -Skiing,Activision,Bob Whitehead,,1980,AG-005,Uncommon,,A2600NTSC,,,b76fbadc8ffb1f83e2ca08b6fb4d6c9f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1280 -Skiing,Activision,Bob Whitehead,,1980,AG-005,Uncommon,,A2600PAL,,,eec61cc4250df70939d48fe02d7122ac,http://www.atariage.com/manual_thumbs.html?SoftwareID=1280 -Skiing,Dactar,Bob Whitehead,,,,,,A2600PAL,,,40d9f5709877ecf3dd1184f9791dd35e,http://www.atariage.com/manual_thumbs.html?SoftwareID=1280 -Skindiver (a.k.a. Aquatak),Sancho,,,,,,,A2600PAL,,,340f546d59e72fb358c49ac2ca8482bb, -Sky Demo,,,,,,,,A2600NTSC,,,bc97d544f1d4834cc72bcc92a37b8c1b, -Sky Diver (32-in-1),Atari,Jim Huether,,,,,,A2600PAL,,,3f75a5da3e40d486b21dfc1c8517adc0,http://www.atariage.com/manual_thumbs.html?SoftwareID=1281 -Sky Diver (Vom Himmel durch die Hoelle),Rainbow Vision,,,,,,,A2600PAL,,,8108162bc88b5a14adc3e031cf4175ad,http://www.atariage.com/manual_thumbs.html?SoftwareID=1281 -Sky Diver,Atari,Jim Huether,,1978,CX2629,Uncommon,,A2600NTSC,,,46c021a3e9e2fd00919ca3dd1a6b76d8,http://www.atariage.com/manual_thumbs.html?SoftwareID=1281 -Sky Diver,Atari,Jim Huether,,1978,CX2629,Uncommon,,A2600PAL,,,756ca07a65a4fbbedeb5f0ddfc04d0be,http://www.atariage.com/manual_thumbs.html?SoftwareID=1281 -Sky Diver,Atari,Jim Huether,,1978,CX2629,Uncommon,,A2600PAL,,,8190b403d67bf9792fe22fa5d22f3556,http://www.atariage.com/manual_thumbs.html?SoftwareID=1281 -Sky Jinks,Activision,Bob Whitehead,,1982,AG-019,Rare,,A2600NTSC,,,05aff8f626ef870432ae3b3d9d5aa301, -Sky Jinks,Activision,Bob Whitehead,,1982,AG-019,Rare,,A2600NTSC,,,2a0ba55e56e7a596146fa729acf0e109, -Sky Jinks,Activision,Bob Whitehead,,1982,AG-019,Rare,,A2600NTSC,,,8bd8f65377023bdb7c5fcf46ddda5d31, -Sky Jinks,Activision,Bob Whitehead,,1982,AG-019,Rare,,A2600NTSC,,,fa447e4e2f0d5e67cbf0b060fac5944c, -Sky Jinks,Activision,Bob Whitehead,,1982,AG-019,Rare,,A2600PAL,,,50a410a5ded0fc9aa6576be45a04f215, -Sky Jinks,Activision,Bob Whitehead,,1982,AG-019,Rare,,A2600PAL,,,f992a39b46aa48188fab12ad3809ae4a, -Sky Jinks,CCE,Bob Whitehead,,,,,,A2600NTSC,,,93dc15d15e77a7b23162467f95a5f22d, -Sky Patrol,Imagic,Brad Steward,Prototype,,IA3409,,,A2600NTSC,,,4c9307de724c36fd487af6c99ca078f2, -Sky Skipper,Parker Bros,,,1983,PB5350,Rare,,A2600NTSC,,,3b91c347d8e6427edbe942a7a405290d, -Sky Skipper,Parker Bros,,,1983,PB5350,Rare,,A2600PAL,,,514f911ecff2be5eeff2f39c49a9725c, -Slot Invaders,,David Marli,Hack,,,,,A2600NTSC,,,1aa7344b563c597eecfbfcf8e7093c27, -Slot Machine (32-in-1),Atari,David Crane,,,,,,A2600PAL,,,75ea128ba96ac6db8edf54b071027c4e,http://www.atariage.com/manual_thumbs.html?SoftwareID=1285 -Slot Machine,Atari,,Hack,1979,CX2653,Rare,,A2600NTSC,,,705fe719179e65b0af328644f3a04900,http://www.atariage.com/manual_thumbs.html?SoftwareID=1285 -Slot Machine,Atari,David Crane,,1979,,,,A2600PAL,,,dbdd21e1ee3d72119e8cd14d943c585b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1285 -Slot Machine,Atari,David Crane,,1979,,,,A2600PAL,,,fc6052438f339aea373bbc999433388a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1285 -Slot Machine,Atari,David Crane,,1979,CX2653,Rare,,A2600NTSC,,,f90b5da189f24d7e1a2117d8c8abc952,http://www.atariage.com/manual_thumbs.html?SoftwareID=1285 -Slot Racers (32-in-1),Atari,Warren Robinett,,,,,,A2600PAL,,,d1d704a7146e95709b57b6d4cac3f788,http://www.atariage.com/manual_thumbs.html?SoftwareID=1287 -Slot Racers - Maze,Atari,,,1978,CX2606,Common,,A2600NTSC,,,5f708ca39627697e859d1c53f8d8d7d2,http://www.atariage.com/manual_thumbs.html?SoftwareID=1287 -Slot Racers - Maze,Atari,,,1978,CX2606,Common,,A2600NTSC,,,aed82052f7589df05a3f417bb4e45f0c,http://www.atariage.com/manual_thumbs.html?SoftwareID=1287 -Slot Racers,Atari,Warren Robinett,,1978,,,,A2600PAL,,,f6d512bef1bf253dc935d0e13c3d1462,http://www.atariage.com/manual_thumbs.html?SoftwareID=1287 -Slot Racers,Atari,Warren Robinett,,1978,CX2606,Uncommon,,A2600PAL,,,a7ed7dc5cbc901388afa59030fb11d26,http://www.atariage.com/manual_thumbs.html?SoftwareID=1287 -Smash Hit Pak - Frogr -Stampede -Seaqst -Boxng -Ski,HES,,,,,,,A2600PAL,,,92d1f6ac179ebe5963868d6bc1bdda8d, -Smurfs - Rescue in Gargamel's Castle,CBS Electronics,,,,,,,A2600PAL,,,73c545db2afd5783d37c46004e4024c2, -Smurfs - Rescue in Gargamel's Castle,Coleco,,,1982,2465,Uncommon,,A2600NTSC,,,3d1e83afdb4265fa2fb84819c9cfd39c, -Smurfs - Rescue in Gargamel's Castle,Coleco,,,1982,2465,Uncommon,,A2600PAL,,,24aff972d58990f9b88a6d787c796f1e, -Smurfs Save the Day,Coleco,,,1983,2511,Unbelievably Rare,,A2600NTSC,,,a204cd4fb1944c86e800120706512a64, -Snail Against Squirrel,,,,,,,,A2600PAL,,,ac26d7d37248d1d8eac5eccacdbef8db, -Snail Against Squirrel,CCE,,,1983,,,,A2600NTSC,,,68878250e106eb6c7754bc2519d780a0, -Sneek 'n Peek,,,,,,,,A2600PAL,,,f21813aa050437f0dbc8479864acec6d, -Sneek 'n Peek,CCE,,,,VC 1002,Rare,,A2600NTSC,,,9c6faa4ff7f2ae549bbcb14f582b70e4, -Sniper (02-30-01),,Billy Eno,Prototype,,,,,A2600NTSC,,,c54b4207ce1d4bf72fadbb1a805d4a39, -Snoopy and the Red Baron,Atari,,,1983,CX26111,Rare,,A2600NTSC,,,57939b326df86b74ca6404f64f89fce9, -Snoopy and the Red Baron,Atari,,,1983,CX26111,Rare,,A2600PAL,,,f844f4c6f3baaaf5322657442d6f29eb, -Snoopy and the Red Baron,CCE,,,,CX26111,,,A2600NTSC,,,c5d2834bf98e90245e545573eb7e6bbc, -Snow White,Atari,,Prototype,,CX26107,,,A2600NTSC,,,75ee371ccfc4f43e7d9b8f24e1266b55, -Solar Fox,CBS Electronics,,,1983,4L-2487,Uncommon,,A2600NTSC,,,947317a89af38a49c4864d6bdd6a91fb, -Solar Fox,CBS Electronics,,,1983,4L-2487,Uncommon,,A2600PAL,,,e03b0b091bea5bc9d3f14ee0221e714d, -Solar Storm,Imagic,Dennis Koble,,1983,O3206,Rare,,A2600NTSC,Paddles,Paddles,97842fe847e8eb71263d6f92f7e122bd, -Solar Storm,Imagic,Dennis Koble,,1983,O3206,Rare,,A2600PAL,Paddles,Paddles,e6de4ef9ab62e2196962aa6b0dedac59, -Solaris Trainer,,Chris Larkin,Hack,,,,A16K,A2600NTSC,,,f19aba18f86e415812480ad2be221425,http://www.atariage.com/manual_thumbs.html?SoftwareID=1296 -Solaris,Atari,,,1986,CX26136,Uncommon,A16K,A2600NTSC,,,e72eb8d4410152bdcb69e7fba327b420,http://www.atariage.com/manual_thumbs.html?SoftwareID=1296 -Solaris,Atari,,,1986,CX26136,Uncommon,A16K,A2600PAL,,,bc4cf38a4bee45752dc466c98ed7ad09,http://www.atariage.com/manual_thumbs.html?SoftwareID=1296 -Sorcerer's Apprentice,Atari,,,1983,CX26109,Rare,,A2600NTSC,,,5f7ae9a7f8d79a3b37e8fc841f65643a, -Sorcerer's Apprentice,Atari,,,1983,CX26109,Rare,,A2600PAL,,,2e82a1628ef6c735c0ab8fa92927e9b0, -Sorcerer,Mythicon,,,1983,MA-1001,Uncommon,,A2600NTSC,,,d2c4f8a4a98a905a9deef3ba7380ed64, -Sound Paddle (V1),,,,,,,,A2600NTSC,Paddles,Paddles,f78c125b5da483c41e51522947d6c4ce, -Sound Paddle (V2),,,,,,,,A2600NTSC,Paddles,Paddles,eee7695ae3eea7818321df0b790b31f3, -Sound X,,Ed Federmeyer,,1994,,Extremely Rare,,A2600NTSC,,,32f4e47a71601ab06cfb59e1c6a0b846, -Sound X,,Ed Federmeyer,,1996,,Extremely Rare,,A2600NTSC,,,7dbc8fa2e488e3f6b87fbe0f76c5b89f, -Sound X6,,Ed Federmeyer,,1994,,Extremely Rare,,A2600NTSC,,,310ba30e25ea8957e58180b663503c0c, -Space 2002,Angelino,,Hack,,,,,A2600NTSC,,,24b9adac1b4f85b0bac9bf9b9e180906, -Space Attack,Mattel,,,1982,MT5659,Common,,A2600NTSC,,,17badbb3f54d1fc01ee68726882f26a6, -Space Attack,Telegames,,,,,,,A2600PAL,,,abb741c83f665d73c86d90a7d9292a9b, -Space Canyon,Panda,,,,100,Rare,,A2600NTSC,,,559317712f989f097ea464517f1a8318, -Space Cavern,Apollo,,,1982,AP 2002,Uncommon,,A2600NTSC,,,df6a28a89600affe36d94394ef597214, -Space Cavern,Apollo,,,1982,AP 2002,Uncommon,,A2600PAL,,,d9548ad44e67edec202d1b8b325e5adf, -Space Duel,,Bob DeCrescenzo,Homebrew,2007,,,,A7800PAL,,,a84c1b2300fbfbf21b1c02387f613dad,http://www.atariage.com/software_page.html?SoftwareLabelID=2770 -Space Duel,,Bob DeCrescenzo,Homebrew,2007,,,A7832,A7800NTSC,,,771cb4609347657f63e6f0eb26036e35,http://www.atariage.com/software_page.html?SoftwareLabelID=2770 -Space Instigators,Xype,Christopher Tumber,Homebrew,,,,,A2600NTSC,,,84f4ce5ad5b469103978ec1cb85c9e5c, -Space Invaders (w/Explosions),,,Hack,,,,,A2600NTSC,,,2ef36341d1bf42e02c7ea2f71e024982,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders 2,,,Hack,,,,,A2600NTSC,,,270229c6d5578446e6a588492e4e5910,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,,Bob DeCrescenzo,Homebrew Hack,2008,,,,A7800NTSC,,,6adf79558a3d7f5beca1bb8d34337417,http://www.atariage.com/cart_page.html?SoftwareLabelID=2785 -Space Invaders,,Franklin Cruz,Hack,,,,,A2600NTSC,,,0963aa9f7f6cf5a36ff700001583624e,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,,Rob Kudla,Hack,,,,,A2600NTSC,,,e10bf1af6bf3b4a253c5bef6577fe923,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,,Ron Corcoran,Hack,,,,,A2600NTSC,,,17f31884e6f7868032bb79e3575d6caf,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,,Ron Corcoran,Hack,2002,,,,A2600NTSC,,,c126656df6badfa519cc63e681fb3596,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,Atari,Rick Maurer,,1978,CX2632,Common,,A2600NTSC,,,012020625a3227815e47b37fd025e480,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,Atari,Rick Maurer,,1978,CX2632,Common,,A2600NTSC,,,07f91e33e76f53bb9d2731fd5d8a35a5,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,Atari,Rick Maurer,,1978,CX2632,Common,,A2600NTSC,,,72ffbef6504b75e69ee1045af9075f66,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,Atari,Rick Maurer,,1978,CX2632,Common,,A2600PAL,,,8747ba79cd39fa83a529bb26010db21b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Invaders,Atari,Rick Maurer,,1978,CX2632,Common,,A2600PAL,,,f1b7edff81ceef5af7ae1fa76c8590fc,http://www.atariage.com/manual_thumbs.html?SoftwareID=1306 -Space Jockey (32-in-1),Atari,,,,,,,A2600PAL,,,6bb09bc915a7411fe160d0b2e4d66047, -Space Jockey,,,,,,,,A2600PAL,,,822a950f27ff0122870558a89a49cad3, -Space Jockey,Carrere Video,,,,,,,A2600PAL,,,457e7d4fcd56ebc47f5925dbea3ee427, -Space Jockey,US Games,,,1982,VC 1001,Common,,A2600NTSC,,,6f2aaffaaf53d23a28bf6677b86ac0e3, -Space Jockey,US Games,,,1982,VC 1001,Common,,A2600NTSC,,,d1a9478b99d6a55e13a9fd4262da7cd4, -Space Raid,,,,,,,,A2600NTSC,,,1a624e236526c4c8f31175e9c89b2a22, -Space Raid,,,,,,,,A2600PAL,,,345769d085113d57937198262af52298, -Space Robot (a.k.a. Robot Fight),Dimax,,,,SM8001,Unbelievably Rare,,A2600NTSC,,,3dfb7c1803f937fadc652a3e95ff7dc6, -Space Shuttle - Journey Into Space,Activision,Steve Kitchen,,1983,AZ-033,Rare,,A2600NTSC,,,5894c9c0c1e7e29f3ab86c6d3f673361,http://www.atariage.com/manual_thumbs.html?SoftwareID=1313 -Space Shuttle - Journey Into Space,Activision,Steve Kitchen,,1983,AZ-033,Rare,,A2600PAL,,,4f6702c3ba6e0ee2e2868d054b00c064,http://www.atariage.com/manual_thumbs.html?SoftwareID=1313 -Space Treat (2002-06-10),,Fabrizio Zavagli,Homebrew,,,,,A2600NTSC,,,d97e3d0b4575ce0b9a6132e19cfeac6e, -Space Treat,,Fabrizio Zavagli,Homebrew,,,,,A2600NTSC,,,6c9a32ad83bcfde3774536e52be1cce7, -Space Tunnel,,Cooper Black,,,,,,A2600PAL,,,df2745d585238780101df812d00b49f4, -Space Tunnel,Bitcorp,,,,PG202,Rare,,A2600PAL,,,8917f7c1ac5eb05b82331cf01c495af2, -Space War (32-in-1),Atari,,,,,,,A2600PAL,,,b702641d698c60bcdc922dbd8c9dd49c,http://www.atariage.com/manual_html_page.html?SoftwareID=1316 -Space War,Atari,,,1978,CX2604,Uncommon,,A2600NTSC,,,77887e4192a6b0a781530e6cf9be7199,http://www.atariage.com/manual_html_page.html?SoftwareID=1316 -Space War,Atari,,,1978,CX2604,Uncommon,,A2600NTSC,,,7e9da5cb84d5bc869854938fe3e85ffa,http://www.atariage.com/manual_html_page.html?SoftwareID=1316 -Space War,Atari,,,1978,CX2604,Uncommon,,A2600NTSC,,,a7ef44ccb5b9000caf02df3e6da71a92,http://www.atariage.com/manual_html_page.html?SoftwareID=1316 -Space War,Atari,,,1978,CX2604,Uncommon,,A2600PAL,,,8f60551db6d1535ef0030f155018c738,http://www.atariage.com/manual_html_page.html?SoftwareID=1316 -Space War,Atari,,,1978,CX2604,Uncommon,,A2600PAL,,,f9677b2ec8728a703eb710274474613d,http://www.atariage.com/manual_html_page.html?SoftwareID=1316 -SpaceMaster X-7,20th Century Fox,,,1983,11022,Extremely Rare,,A2600NTSC,,,45040679d72b101189c298a864a5b5ba, -Spacechase,Apollo,,,1981,AP 2001,Uncommon,,A2600NTSC,,,ec5c861b487a5075876ab01155e74c6c, -Spectrum Color Demo,,,,,,,,A2600NTSC,,,f3f92aad3a335f0a1ead24a0214ff446, -Spice Girls Rule Demo,,,,,,,,A2600NTSC,,,327fe8cf94f3a45c35a840a453df1235, -Spice Invaders,,Philip R. Frey,Hack,,,,,A2600NTSC,,,a8a703e073183a89c94d4d99b9661b7f, -Spider Fighter,Activision,Larry Miller,,1983,AX-021,Uncommon,,A2600NTSC,,,24d018c4a6de7e5bd19a36f2b879b335,http://www.atariage.com/manual_thumbs.html?SoftwareID=1325 -Spider Fighter,Activision,Larry Miller,,1983,AX-021,Uncommon,,A2600NTSC,,,ba3a17efd26db8b4f09c0cf7afdf84d1,http://www.atariage.com/manual_thumbs.html?SoftwareID=1325 -Spider Fighter,Activision,Larry Miller,,1983,AX-021,Uncommon,,A2600PAL,,,7778ac65d775a079f537e97cbdad541c,http://www.atariage.com/manual_thumbs.html?SoftwareID=1325 -Spider Kong (a.k.a. Karate),Goliath-Funvision,,,,,,,A2600PAL,,,ae465044dfba287d344ba468820995d7, -Spider Kong (a.k.a. Karate),Goliath-Funvision,,,,,,,A2600PAL,,,d39e29b03af3c28641084dd1528aae05, -Spider Maze,K-Tel Vision,,,,,Rare,,A2600NTSC,,,21299c8c3ac1d54f8289d88702a738fd, -Spider-Man,Parker Bros,,,1982,PB5900,Rare,,A2600NTSC,,,199eb0b8dce1408f3f7d46411b715ca9, -Spider-Man,Parker Bros,,,1982,PB5900,Rare,,A2600PAL,,,e77ec259e1387bc308b0534647a89198, -Spider-Man,Parker Bros,,,1982,PB5900,Rare,,A2600PAL,,,f7af41a87533524d9a478575b0d873d0, -Spiderdroid,Froggo,,,1987,,Rare,,A2600NTSC,,,8454ed9787c9d8211748ccddb673e920, -Spike's Peak,Xonox,,,1983,99001,Extremely Rare,,A2600NTSC,,,a4e885726af9d97b12bb5a36792eab63, -Spike's Peak,Xonox,,,1983,99001,Extremely Rare,,A2600PAL,,,b37f0fe822b92ca8f5e330bf62d56ea9, -Spitfire Attack,Milton Bradley,,,1983,4363,Uncommon,,A2600NTSC,,,cef2287d5fd80216b2200fb2ef1adfa8, -Split Screen (Ballblazer) Demo,,,,,,,,A2600NTSC,,,fb91da78455d9b1606913fbf8c859772, -Sports Action Pak - End -Hock -Fish -Drag,,,,1988,,,,A2600PAL,,,2c3b2843295c9d6b16996971180a3fe9, -Springer,Tigervision,,,1982,7-006,Extremely Rare,TV8K,A2600NTSC,,,4cd796b5911ed3f1062e805a3df33d98, -Sprintmaster DC,,Thomas Jentzsch,Hack,,,,A16KR,A2600NTSC,Driving,Driving,6b75f8fa4fd011a6698c58315f83d2ac, -Sprintmaster,Atari,,,1988,CX26155,Rare,A16KR,A2600NTSC,,,5a8afe5422abbfb0a342fb15afd7415f, -Sprintmaster,Atari,,,1988,CX26155,Rare,A16KR,A2600PAL,,,b2d5d200f0af8485413fad957828582a, -Sprite Color Demo,,,,,,,,A2600NTSC,,,d597d35c6022c590d6e75e865738558a, -Sprite Demo 0,,,,,,,,A2600NTSC,,,e15b5525cf8f77297b322838df8d999c, -Sprite Demo 1,,,,,,,,A2600NTSC,,,d5c6b81212ad86fd9542a1fedaf57cae, -Sprite Demo 2,,,,,,,,A2600NTSC,,,fe0bc4bb92c1c4de7d5706aaa8d8c10d, -Sprite Demo 3,,,,,,,,A2600NTSC,,,dbabb80e92ff18d8eecf615c0539151e, -Sprite Demo 4,,,,,,,,A2600NTSC,,,61728c6cfb052e62a9ed088c5bf407ba, -Sprite Demo 5,,,,,,,,A2600NTSC,,,ad7e97c19bd25d5aa3999430845c755b, -Sprite Demo 6,,,,,,,,A2600NTSC,,,acaa27d214039d89d7031609aafa55c3, -Sprite Demo 7,,,,,,,,A2600NTSC,,,2d6da0eb85eabc93270e5bb8a466ca51, -Spy Hunter,Sega,,,1983,011-02,Extremely Rare,A8K,A2600NTSC,,,3105967f7222cc36a5ac6e5f6e89a0b4, -Spy vs. Spy,,,,,,,,A2600PAL,,,2a360bc85bf22de438651cf92ffda1de, -Squeeze Box,US Games,,,1982,VC 2002,Extremely Rare,,A2600NTSC,,,ba257438f8a78862a9e014d831143690, -Squoosh,Apollo,,Prototype,,,,,A2600NTSC,,,22abbdcb094d014388d529352abe9b4b, -Sssnake,Data Age,,,1982,DA 1003,Common,,A2600NTSC,,,21a96301bb0df27fde2e7eefa49e0397, -Stampede (32-in-1),Atari,Bob Whitehead,,,,,,A2600PAL,,,c9196e28367e46f8a55e04c27743148f,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Stampede,Activision,Bob Whitehead,,1981,,,,A2600PAL,,,0945081a6bd00345ff3d58eb7a07330a,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Stampede,Activision,Bob Whitehead,,1981,,,,A2600PAL,,,75511bb694662301c9e71df645f4b5a7,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Stampede,Activision,Bob Whitehead,,1981,,,,A2600PAL,,,869abe0426e6e9fcb6d75a3c2d6e05d1,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Stampede,Activision,Bob Whitehead,,1981,AG-011,Uncommon,,A2600NTSC,,,21d7334e406c2407e69dbddd7cec3583,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Stampede,Activision,Bob Whitehead,,1981,AG-011,Uncommon,,A2600NTSC,,,9057694dce8449521e6164d263702185,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Stampede,Activision,Bob Whitehead,,1981,AG-011,Uncommon,,A2600NTSC,,,e66e5af5dea661d58420088368e4ef0d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1336 -Star Fire (in development),,Manuel Polik,Homebrew,,,,,A2600NTSC,,,bc6432cbed32c695658514c4eb41d905, -Star Fire (tech demo),,Manuel Polik,Homebrew,,,,,A2600NTSC,,,ec26fdc87b1d35f1d60ea89cda4f4dd4, -Star Fox,Mythicon,,,1982,MA-1003,Uncommon,,A2600NTSC,,,f526d0c519f5001adb1fc7948bfbb3ce, -Star Gunner,Telesys,,,1982,1005,Extremely Rare,,A2600NTSC,,,a3c1c70024d7aabb41381adbfb6d3b25, -Star Raiders,Atari,Carla Meninsky & Doug Neubauer,,1982,CX2660,Uncommon,,A2600NTSC,Joystick,Keypad,cbd981a23c592fb9ab979223bb368cd5, -Star Raiders,Atari,Carla Meninsky & Doug Neubauer,,1982,CX2660,Uncommon,,A2600PAL,Joystick,Keypad,c1a83f44137ea914b495fc6ac036c493, -Star Ship,Atari,Bob Whitehead,,1977,CX2603,Rare,,A2600NTSC,,,7b938c7ddf18e8362949b62c7eaa660a, -Star Ship,Atari,Bob Whitehead,,1977,CX2603,Rare,,A2600NTSC,,,e363e467f605537f3777ad33e74e113a, -Star Strike,Mattel,,,1982,MT4313,Rare,,A2600NTSC,,,79e5338dbfa6b64008bb0d72a3179d3c, -Star Strike,Telegames,,,,,,,A2600PAL,,,405f8591b6941cff56c9b392c2d5e4e5, -Star Trek - Strategic Operations Simulator,Sega,,,1983,004-01,Rare,,A2600NTSC,,,03c3f7ba4585e349dd12bfa7b34b7729, -Star Voyager,CCE,,,,,,,A2600NTSC,,,d912312349d90e9d41a9db0d5cd3db70,http://www.atariage.com/manual_html_page.html?SoftwareLabelID=498 -Star Voyager,Imagic,Bob Smith,,1982,IA3201,Common,,A2600NTSC,,,813985a940aa739cc28df19e0edd4722,http://www.atariage.com/manual_html_page.html?SoftwareLabelID=498 -Star Voyager,Imagic,Bob Smith,,1982,IA3201,Common,,A2600PAL,,,0aceb7c3bd13fe048b77a1928ed4267d,http://www.atariage.com/manual_html_page.html?SoftwareLabelID=498 -Star Wars - Death Star Battle,Parker Bros,,,1983,PB5060,Rare,PB8K,A2600NTSC,,,5336f86f6b982cc925532f2e80aa1e17, -Star Wars - Death Star Battle,Parker Bros,,,1983,PB5060,Rare,PB8K,A2600PAL,,,cb9b2e9806a7fbab3d819cfe15f0f05a, -Star Wars - Ewok Adventure,Parker Bros,,Prototype,,,,PB8K,A2600PAL,,,6dfad2dd2c7c16ac0fa257b6ce0be2f0, -Star Wars - Ewok Adventure,Parker Bros,Thomas Jentzsch,Prototype Hack,,,,PB8K,A2600NTSC,,,c246e05b52f68ab2e9aee40f278cd158, -Star Wars - Jedi Arena,Parker Bros,Rex Bradford,,1983,PB5000,Rare,,A2600NTSC,Paddles,Paddles,c9f6e521a49a2d15dac56b6ddb3fb4c7, -Star Wars - Jedi Arena,Parker Bros,Rex Bradford,,1983,PB5000,Rare,,A2600PAL,Paddles,Paddles,05b45ba09c05befa75ac70476829eda0, -Star Wars - The Arcade Game,Parker Bros,,,1983,PB5540,Extremely Rare,PB8K,A2600NTSC,,,6339d28c9a7f92054e70029eb0375837, -Star Wars - The Arcade Game,Parker Bros,,,1983,PB5540,Extremely Rare,PB8K,A2600PAL,,,6cf054cd23a02e09298d2c6f787eb21d, -Star Wars - The Battle of Alderaan,,Barry Laws Jr.,Hack,,,,,A2600NTSC,,,ffc0ff4305dd46b4b459885bd1818e2e, -Star Wars - The Empire Strikes Back,Parker Bros,Rex Bradford,,1982,PB5050,Common,,A2600NTSC,,,3c8e57a246742fa5d59e517134c0b4e6, -Star Wars - The Empire Strikes Back,Parker Bros,Rex Bradford,,1982,PB5050,Common,,A2600PAL,,,be060a704803446c02e6f039ab12eb91, -Stargate,Atari,,,1984,CX26120,Rare,A8KR,A2600NTSC,,,0c48e820301251fbb6bcdc89bd3555d9, -Stargate,Atari,,,1984,CX26120,Rare,A8KR,A2600NTSC,,,57fa2d09c9e361de7bd2aa3a9575a760, -Stargate,Atari,,,1984,CX26120,Rare,A8KR,A2600PAL,,,493de059b32f84ab29cde6213964aeee, -Starmaster,Activision,Alan Miller,,1982,AX-016,Uncommon,,A2600NTSC,,,d69559f9c9dc6ef528d841bf9d91b275, -Starmaster,Activision,Alan Miller,,1982,AX-016,Uncommon,,A2600PAL,,,348615ffa30fab3cec1441b5a76e9460, -Starmaster,Activision,Alan Miller,,1982,AX-016,Uncommon,,A2600PAL,,,d62d7d1a974c31c5803f96a8c1552510, -Steeple Chase,Video Gems,,,,,,,A2600PAL,Paddles,Paddles,f1eeeccc4bba6999345a2575ae96508e, -Steeple Chase,Video Gems,Thomas Jentzsch,Hack,,,,,A2600NTSC,Paddles,Paddles,1619bc27632f9148d8480cd813aa74c3, -Steeplechase,Sears,,,1980,CX2614,Rare,,A2600NTSC,Paddles,Paddles,656dc247db2871766dffd978c71da80c, -Steeplechase,Sears,,,1980,CX2614,Rare,,A2600NTSC,Paddles,Paddles,a174cece06b3abc0aec3516913cdf9cc, -Stell-a-Sketch,,,Homebrew,,,,,A2600NTSC,,,18ed63e3ce5bc3dd2d8bd188b807f1a2, -Stell-a-Sketch,,,Homebrew,,,,,A2600NTSC,Driving,Driving,47aef18509051bab493589cb2619170b, -Stellar Track,Sears,,,1980,CX2614,Rare,,A2600NTSC,,,0b8d3002d8f744a753ba434a4d39249a, -Steroid Pitfall,HCC Software,,,,,,,A2600NTSC,,,177504abd4260c4265e1338955e9fa47, -Stopp die Gangster,Starsoft,,,,,,,A2600PAL,,,b17b9cc4103844dcda54f77f44acc93a, -Strahlen der Teufelsvoegel,,,,,,,,A2600PAL,,,f240ba9f8092d2e8a4c7d82c554bf509, -Strategy X,Gakken,,,1982,,,,A2600PAL,,,ef76ea05655a0b62cb1018c92b9b4b7d, -Strategy X,Gakken,,,1982,10,Extremely Rare,,A2600PAL,,,9333172e3c4992ecf548d3ac1f2553eb, -Strawberry Shortcake - Musical Match-Ups,Parker Bros,,,1983,PB5910,Uncommon,,A2600NTSC,,,e10d2c785aadb42c06390fae0d92f282, -Strawberry Shortcake Musical Match-Ups,Parker Bros,,,1983,,,,A2600PAL,,,516ffd008057a1d78d007c851e6eff37, -Street Racer - Speedway II (128-in-1 Junior Console) (4K),128-in-1 Junior Console,Larry Kaplan,,,,,,A2600PAL,Paddles,Paddles,8a6c84f481acf42abcb78ba5064ad755, -Street Racer - Speedway II,Atari,Larry Kaplan,,1978,CX2612,,,A2600PAL,Paddles,Paddles,e12e32dee68201b6765fcd0ed54d6646, -Street Racer - Speedway II,Atari,Larry Kaplan,,1978,CX2612,Uncommon,,A2600NTSC,Paddles,Paddles,396f7bc90ab4fa4975f8c74abe4e81f0, -Street Racer - Speedway II,Atari,Larry Kaplan,,1978,CX2612,Uncommon,,A2600NTSC,Paddles,Paddles,6ff4156d10b357f61f09820d03c0f852, -Stronghold,CommaVid,,,,CM-009,Extremely Rare,,A2600NTSC,,,7b3cf0256e1fa0fdc538caf3d5d86337, -Stunt Cycle,Atari,,Prototype,,,,,A2600NTSC,Paddles,Paddles,c3bbc673acf2701b5275e85d9372facf, -Sub Rescue (Real Title Unknown),,,,,,,,A2600PAL,,,9193b6fff6897d43274741d4f9855b6d, -Sub Scan,Sega,,,1982,002-01,Uncommon,,A2600PAL,,,b095009004df341386d22b2a3fae3c81, -Sub Scan,Sega,,,1983,002-01,Uncommon,,A2600NTSC,,,5af9cd346266a1f2515e1fbc86f5186a, -Submarine Commander,Sears,,,1982,CX2647,Extremely Rare,,A2600NTSC,,,f3f5f72bfdd67f3d0e45d097e11b8091, -Subterranea,Imagic,Mark Klein,,1983,O3213,Rare,,A2600NTSC,,,93c52141d3c4e1b5574d072f1afde6cd, -Subterranea,Imagic,Mark Klein,,1983,O3213,Rare,,A2600PAL,,,38de7b68379770b9bd3f7bf000136eb0, -Sucky Zepplin,,Nick Bensema,Homebrew,,,,,A2600NTSC,,,4ab4af3adcdae8cdacc3d06084fc8d6a, -Suicide Adventure,,George Veeder,Homebrew,,,,,A2600NTSC,,,cff578e5c60de8caecbee7f2c9bbb57b, -Summer Games,Atari,,,1987,CX7826,Scarce,A78SGR,A7800NTSC,,,cbb0746192540a13b4c7775c7ce2021f,http://www.atariage.com/manual_thumbs.html?SoftwareID=2175 -Summer Games,Epyx,,,1987,8056100250,Rare,A16K,A2600NTSC,,,45027dde2be5bdd0cab522b80632717d, -Summer Games,Epyx,,,1987,8056100250,Rare,A16K,A2600PAL,,,12bca8305d5ab8ea51fe1cfd95d7ab0e, -Super Action Pak - Pitf -GPrix -LaserB -Barn(1988),,,,,,,,A2600PAL,,,4f2d47792a06da224ba996c489a87939, -Super Baseball,Atari,,,1988,CX26152,Uncommon,,A2600NTSC,,,7adbcf78399b19596671edbffc3d34aa, -Super Baseball,CCE,,,,,,,A2600NTSC,,,faed2ef6b44894f8c83f2b50891c35c6, -Super Box,CCE,,,,,,A16K,A2600NTSC,,,1c85c0fc480bbd69dc301591b6ecb422, -Super Breakout,Atari,Nick Turner,,1978,CX2608,Common,,A2600NTSC,Paddles,Paddles,0ad9a358e361256b94f3fb4f2fa5a3b1,http://www.atariage.com/manual_html_page.html?SoftwareID=1372 -Super Breakout,Atari,Nick Turner,,1978,CX2608,Common,,A2600PAL,Paddles,Paddles,8885d0ce11c5b40c3a8a8d9ed28cefef,http://www.atariage.com/manual_html_page.html?SoftwareID=1372 -Super Breakout,Atari,Nick Turner,,1978,CX2608,Common,,A2600PAL,Paddles,Paddles,ee4c186123d31a279ed7a84d3578df23,http://www.atariage.com/manual_html_page.html?SoftwareID=1372 -Super Challenge Baseball,Mattel,,,1982,MT5658,Common,,A2600PAL,,,9d37a1be4a6e898026414b8fee2fc826, -Super Challenge Football,Mattel,,,1982,MT5658,Common,,A2600NTSC,,,e275cbe7d4e11e62c3bfcfb38fca3d49, -Super Circus,,,,,,,,A2600PAL,,,feba8686fd0376015258d1152923958a, -Super Cobra,Parker Bros,,,1982,PB5320,Uncommon,PB8K,A2600NTSC,,,c29f8db680990cb45ef7fef6ab57a2c2, -Super Cobra,Parker Bros,,,1982,PB5320,Uncommon,PB8K,A2600NTSC,,,cd6b3dff86a55a4a6d23007ee360ea0e, -Super Cobra,Parker Bros,,,1982,PB5320,Uncommon,PB8K,A2600PAL,,,d326db524d93fa2897ab69c42d6fb698, -Super Ferrari,Quelle,,,,,Extremely Rare,,A2600PAL,,,724613effaf7743cbcd695fab469c2a8, -Super Ferrari,Rainbow Vision,,,,SS-011,Extremely Rare,,A2600PAL,,,638cc82ea96f67674595ba9ae05da6c6, -Super Ferrari,Starsoft,,,,SS-011,Extremely Rare,,A2600PAL,,,2b27eb194e13f3b38d23c879cc1e3abf, -Super Football,Atari,,,1988,CX26154,Uncommon,A16KR,A2600NTSC,,,09abfe9a312ce7c9f661582fdf12eab6, -Super Football,Atari,,,1988,CX26154,Uncommon,A16KR,A2600PAL,,,262ccb882ff617d9b4b51f24aee02cbe, -Super Futebol,,,,,,,,A2600NTSC,,,2447e17a4e18e6b609de498fe4ab52ba, -Super Futebol,CCE,,,,CX2668,Common,,A2600NTSC,,,2f0a8bb4e18839f9b1dcaa2f5d02fd1d, -Super Hit Pak - RRaid -GPrix -Fishing -SkyJ -Chckrs,,,,,,,,A2600PAL,,,c08d0cee43077d3055febb00e5745c1d, -Super Huey UH-IX,Atari,,,1989,CX7828,Scarce,,A7800NTSC,,,cc18e3b37a507c4217eb6cb1de8c8538,http://www.atariage.com/manual_thumbs.html?SoftwareID=2149 -Super Huey UH-IX,Atari,,,1989,CX7828,Scarce,,A7800PAL,,,162f9c953f0657689cc74ab20b40280f,http://www.atariage.com/manual_thumbs.html?SoftwareID=2149 -Super Kung-Fu,Xonox,,,1983,,,,A2600PAL,,,645bf7f9146f0e4811ff9c7898f5cd93, -Super Skateboardin',Absolute,,,1988,AV-047,Scarce,,A7800NTSC,,,59b5793bece1c80f77b55d60fb39cb94,http://www.atariage.com/manual_thumbs.html?SoftwareID=2150 -Super Skateboardin',Absolute,,,1988,AV-047,Scarce,,A7800PAL,,,95d7c321dce8f57623a9c5b4947bb375,http://www.atariage.com/manual_thumbs.html?SoftwareID=2150 -Super VoleyBall,CCE,,,,,,,A2600NTSC,,,cbc373fbcb1653b4c56bfabba33ea50d, -Super-Cowboy beim Rodeo,Starsoft,,,,,,,A2600PAL,,,bdecc81f740200780db04a107c3a1eba, -SuperCharger - Escape from the Mindmaster (4 of 4),Starpath,,,1982,,,,A2600NTSC,,,639ded0c9e53bc3f91defb5dde930286, -SuperCharger Loader,Starpath,,,1982,,,,A2600NTSC,,,4565c1a7abce773e53c75b35414adefd, -Superman,Atari,John Dunn,,1978,,,,A2600PAL,,,169d4c7bd3a4d09e184a3b993823d048,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Superman,Atari,John Dunn,,1978,,,,A2600PAL,,,6fac680fc9a72e0e54255567c72afe34,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Superman,Atari,John Dunn,,1978,,,,A2600PAL,,,fd10915633aea4f9cd8b518a25d62b55,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Superman,Atari,John Dunn,,1978,CX2631,Common,,A2600NTSC,,,5de8803a59c36725888346fdc6e7429d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Superman,Atari,John Dunn,,1978,CX2631,Common,,A2600NTSC,,,a9531c763077464307086ec9a1fd057d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Superman,Atari,John Dunn,,1978,CX2631,Common,,A2600PAL,,,dbb10b904242fcfb8428f372e00c01af,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Superman,CCE,John Dunn,,,CX2631,Common,,A2600NTSC,,,149b543c917c180a1b02d33c12415206,http://www.atariage.com/manual_thumbs.html?SoftwareID=1380 -Surf's Up,Amiga,,,,3125,Extremely Rare,,A2600NTSC,,,aec9b885d0e8b24e871925630884095c, -Surfer's Paradise - But Danger Below!,Video Gems,,,,,Extremely Rare,,A2600PAL,,,c20f15282a1aa8724d70c117e5c9709e, -Surfer's Paradise - But Danger Below!,Video Gems,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,59b70658f9dd0e2075770b07be1a35cf, -Surround (32-in-1),Atari,Alan Miller,,,,,,A2600PAL,,,a60598ad7ee9c5ccad42d5b0df1570a1, -Surround,Atari,Alan Miller,,1978,,,,A2600PAL,,,d89fedded0436fdeda7c3c37e2fb7cf1, -Surround,Atari,Alan Miller,,1978,CX2641,Common,,A2600NTSC,,,31d08cb465965f80d3541a57ec82c625, -Surround,Atari,Alan Miller,,1978,CX2641,Common,,A2600NTSC,,,4d7517ae69f95cfbc053be01312b7dba, -Surround,Atari,Alan Miller,,1978,CX2641,Common,,A2600NTSC,,,52a0003efb3b1c49fcde4dbc2c685d8f, -Surround,Atari,Alan Miller,,1978,CX2641,Common,,A2600PAL,,,c370c3268ad95b3266d6e36ff23d1f0c, -Survival Run,Milton Bradley,,,1983,4362,Rare,,A2600NTSC,,,85e564dae5687e431955056fbda10978, -SwordQuest - Earthworld,Atari,Tod Frye,,1982,,,,A2600PAL,,,a875f0a919129b4f1b5103ddd200d2fe, -SwordQuest - Earthworld,Atari,Tod Frye,,1982,CX2656,Common,,A2600NTSC,,,05ebd183ea854c0a1b56c218246fbbae, -SwordQuest - Earthworld,Atari,Tod Frye,,1982,CX2656,Common,,A2600NTSC,,,5aea9974b975a6a844e6df10d2b861c4, -SwordQuest - Fireworld,Atari,Tod Frye,,1982,CX2656,Common,,A2600NTSC,,,f9d51a4e5f8b48f68770c89ffd495ed1, -SwordQuest - Fireworld,Atari,Tod Frye,,1982,CX2656,Common,,A2600PAL,,,bf976cf80bcf52c5f164c1d45f2b316b, -SwordQuest - Waterworld,Atari,Tod Frye,,1983,CX2671,Unbelievably Rare,,A2600NTSC,,,bc5389839857612cfabeb810ba7effdc,http://www.atariage.com/manual_thumbs.html?SoftwareID=1391 -Swordfight,Intellivision Productions,,,,,New Release,,A2600NTSC,,,87662815bc4f3c3c86071dc994e3f30e, -Synthcart,,Paul Slocum,,,,,,A2600NTSC,,,2c2aea31b01c6126c1a43e10cacbfd58, -T.F. Space Invaders,,,,,,,,A2600NTSC,,,294762000e853b4319f9991c1ced5dfc, -THX-1138,Kyle Pittman,,Hack,,,,,A2600NTSC,,,becd908f9d7bb361982c3dc02d6475c6, -TP Bug,,Charles Morgan,Homebrew,,,,,A2600NTSC,,,6ffc95108e5add6f9b8abcaf330be835, -TRON - Deadly Discs,Mattel,,,,MT5662,Uncommon,,A2600NTSC,,,fb27afe896e7c928089307b32e5642ee, -TRON - Deadly Discs,Telegames,,,,MT5662,Uncommon,,A2600PAL,,,c1f209d80f0624dada5866ce05dd3399, -Tac-Scan,Sega,,,1982,,,,A2600PAL,,,06e5dc181a8eda1c31cc7c581c68b6ef, -Tac-Scan,Sega,,,1983,001-01,Uncommon,,A2600NTSC,Paddles,Paddles,d45ebf130ed9070ea8ebd56176e48a38, -Tac-Scan,Sega,Christopher Tumber,Hack,,,,,A2600NTSC,Paddles,Paddles,9e5007131695621d06902ab3c960622a, -Tank Brigade,Panda,,,,101,Rare,,A2600NTSC,,,c77d3b47f2293e69419b92522c6f6647, -Tank Command,Froggo,,,1988,FG2002,Rare,A78S4,A7800NTSC,,,5c4f752371a523f15e9980fea73b874d,http://www.atariage.com/manual_thumbs.html?SoftwareID=2180 -Tanks But No Tanks,Zimag,,,,707-111,Rare,,A2600NTSC,,,fa6fe97a10efb9e74c0b5a816e6e1958, -Tanks DX,,Charles Morgan,Hack,,,,,A2600NTSC,,,082fdc8bd47fef01482ce5883c4ffdb8, -Tape Worm,Spectravideo,,,,,,,A2600PAL,,,8ed73106e2f42f91447fb90b6f0ea4a4, -Tape Worm,Spectravideo,,,1982,SA-204,Rare,,A2600NTSC,,,de3d0e37729d85afcb25a8d052a6e236, -Tapper,Sega,,,1983,010-01,Extremely Rare,,A2600NTSC,,,c0d2434348de72fa6edcc6d8e40f28d7, -Task Force,Froggo,,,1987,FG 1003,Rare,,A2600NTSC,,,0c35806ff0019a270a7acae68de89d28, -Tax Avoiders,American Videogame,,,1982,,Rare,,A2600NTSC,,,a1ead9c181d67859aa93c44e40f1709c, -Taz,Atari,,,,CX2699,Rare,,A2600NTSC,,,4702d8d9b48a332724af198aeac9e469, -Taz,Atari,,,,CX2699,Rare,,A2600NTSC,,,7574480ae2ab0d282c887e9015fdb54c, -Tazer The Fish,,,Homebrew,,,,,A2600NTSC,,,ab60ea7b707c58d356cad858eb18db43, -Teddy Apple,HomeVision,,,,,,,A2600PAL,,,8c2fa33048f055f38358d51eefe417db, -Telepathy,Atari,,Prototype,,,,,A2600NTSC,,,3d7aad37c55692814211c8b590a0334c, -Teller-Jonglieren! (a.k.a. Tanzende Teller),Starsoft,,,,,,,A2600PAL,,,203b1efc6101d4b9d83bb6cc1c71f67f, -Tempest,Atari,Carla Meninsky,Prototype,1983,,,,A2600NTSC,,,c830f6ae7ee58bcc2a6712fb33e92d55, -Tennis (32-in-1),Atari,Alan Miller,,,,,,A2600PAL,,,16e04823887c547dc24bc70dff693df4, -Tennis,Activision,Alan Miller,,1981,,,,A2600PAL,,,e3ed4ba3361756970f076e46e9cad1d2, -Tennis,Activision,Alan Miller,,1981,AG-007,Common,,A2600NTSC,,,42cdd6a9e42a3639e190722b8ea3fc51, -Tennis,Activision,Alan Miller,,1981,AG-007,Common,,A2600NTSC,,,961112b74a920a5242e233480326c356, -Tennis,Activision,Alan Miller,,1981,AG-007,Common,,A2600NTSC,,,aca09ffea77174b148b96b205109db4d, -Tennis,Activision,Alan Miller,,1981,AG-007,Common,,A2600PAL,,,a5c96b046d5f8b7c96daaa12f925bef8, -Tennis,Dactar,Alan Miller,,,,,,A2600PAL,,,30685b9b6ebd9ba71536dd7632a1e3b6, -Tennis,Pet Boat,Alan Miller,,,,,,A2600PAL,,,1f5a2927a0b2faf87540b01d9d7d7fd1, -Tennis,Starsoft,Alan Miller,,,,,,A2600PAL,,,04b488d4eef622d022a0021375e7e339, -Test Cartridge,,,,,,,,A2600NTSC,,,5c73693a89b06e5a09f1721a13176f95, -Test Tape - Standalone,Atari,,,,MAO17600,,,A2600NTSC,,,38bd172da8b2a3a176e517c213fcd5a6, -Testcart,,Paul Slocum,,,,,,A2600NTSC,,,f0631c6675033428238408885d7e4fde, -Tetris 2600,,Colin Hughes,Homebrew,,,,,A2600NTSC,,,b0e1ee07fbc73493eac5651a52f90f00, -Tetris 2600,,Colin Hughes,Homebrew,,,,,A2600NTSC,,,cae8f83c06831ec7bb6a3c07e98e9342, -Texas Chainsaw Massacre,Wizard Video Games,,,,8,Extremely Rare,,A2600NTSC,,,5eeb81292992e057b290a5cd196f155d, -The Year 1999,Rainbow Vision,,,,,,,A2600PAL,,,522c9cf684ecd72db2f85053e6f6f720, -This Planet Sucks (16K),,,Homebrew,,,,,A2600NTSC,,,3b64a00ce147c3c29f7f8f8e531d08d8, -This Planet Sucks,,,Homebrew,,,,,A2600NTSC,,,0acaf71e60b89f6b6eab63db6ab84510, -This Planet Sucks,,,Homebrew,,,,,A2600NTSC,,,a98b649912b6ca19eaf5c2d2faf38562, -This Planet Sucks,,,Homebrew,,,,,A2600NTSC,,,dfe6aa7443bb813cefa35a4cf4887422, -Threshold,Tigervision,,,,7-003,Rare,,A2600NTSC,,,e63a87c231ee9a506f9599aa4ef7dfb9, -Threshold,Tigervision,,,,7-003,Rare,,A2600PAL,,,67684a1d18c85ffa5d82dab48fd1cb51, -Thrust (V1.2),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,4776046cec4b6a71f838e55656d5db94, -Thrust (V1.21),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,,,e1e09e2f280e8e142121a377d0dc1b46, -Thrust (V1.22) (Booster Grip),,Thomas Jentzsch,Homebrew,,,,,A2600NTSC,BoosterGrip,BoosterGrip,de7bca4e569ad9d3fd08ff1395e53d2d, -Thrust Demo (V0.1),,,Homebrew,,,,,A2600NTSC,,,346555779a2d51b48833463b5433472f, -Thrust Demo (V0.2),,,Homebrew,,,,,A2600NTSC,,,1442d1b35a6478fba22ae7dd1fcb5634, -Thrust Demo (V0.9),,,Homebrew,,,,,A2600NTSC,,,ba3b0eebccc7b791107de5b4abb671b4, -Thrust Demo (V1.0),,,Homebrew,,,,,A2600NTSC,,,041b5e56bbc650db574bd8db3fae2696, -Thunderground,Sega,,,1983,,,,A2600PAL,,,1428029e762797069ad795ce7c6a1a93, -Thunderground,Sega,,,1983,003-01,Rare,,A2600NTSC,,,cf507910d6e74568a68ac949537bccf9, -Thwocker,Activision,Charlie Heath,Prototype,1984,,,DC8K,A2600NTSC,,,c032c2bd7017fdfbba9a105ec50f800e, -Time Machine (a.k.a. Great Escape -Asteroid Belt),,,,,,,,A2600PAL,,,7576dd46c2f8d8ab159d97e3a3f2052f, -Time Pilot,Coleco,,,,2663,Rare,,A2600NTSC,,,4e99ebd65a967cabf350db54405d577c, -Time Pilot,Coleco,,,,2663,Rare,,A2600NTSC,,,fc2104dd2dadf9a6176c1c1c8f87ced9, -Time Race 2,Funvision,,,,,,,A2600PAL,,,6d9afd70e9369c2a6bff96c4964413b7, -Time Race,Goliath,,,,,,,A2600PAL,,,5db9e5bf663cad6bf159bc395f6ead53, -Time Test Demo,,,,,,,,A2600PAL,,,efb47d70b2965ce689e2c5757616b286, -Time Warp,CCE,,,,,,,A2600PAL,,,bc3057a35319aae3a5cd87a203736abe, -Time Warp/Time Warp,Zellers/CCE,,,,C-845,Extremely Rare,,A2600NTSC,,,332f01fd18e99c6584f61aa45ee7791e, -Title Match Pro Wrestling,Absolute,Alex DeMeo,,1987,AG-041,Rare,,A2600NTSC,,,12123b534bdee79ed7563b9ad74f1cbd, -Title Match Pro Wrestling,Absolute,Alex DeMeo,,1987,AG-041,Rare,,A2600NTSC,,,da6465a34d2e44d26aa9a2a0cd1bce4d, -Title Match Pro Wrestling,Activision,Alex DeMeo,,1989,AG-041,Rare,,A2600NTSC,,,784176346e9422733d55c427230e5bad, -Titlematch Pro Wrestling,Absolute,,,1989,AV-041,Rare,,A7800PAL,,,3bb9c8d9adc912dd7f8471c97445cd8d,http://www.atariage.com/manual_thumbs.html?SoftwareID=2177 -Titlematch Pro Wrestling,Absolute,,,1989,AV-041,Scarce,,A7800NTSC,,,1af475ff6429a160752b592f0f92b287,http://www.atariage.com/manual_thumbs.html?SoftwareID=2177 -Tom Boy,Suntek,,,,,Extremely Rare,,A2600NTSC,,,ece908d77ab944f7bac84322b9973549, -Tom's Eierjagd,Starsoft,,,,,,,A2600PAL,,,d85f1e35c5445ac898746719a3d93f09, -Tomarc the Barbarian,Xonox,,,,,Rare,DC8K,A2600NTSC,,,8bc0d2052b4f259e7a50a7c771b45241, -Tomcat - The F-14 Flight Simulator,Absolute,Dan Kitchen,,1988,AK-046,Extremely Rare,A16K,A2600PAL,,,2ac3a08cfbf1942ba169c3e9e6c47e09, -Tomcat F14,Absolute,Dan Kitchen,,1989,AV-046,Scarce,,A7800NTSC,,,c3903ab01a51222a52197dbfe6538ecf,http://www.atariage.com/manual_thumbs.html?SoftwareID=2176 -Tomcat F14,Absolute,Dan Kitchen,,1989,AV-046,Scarce,,A7800PAL,,,682338364243b023ecc9d24f0abfc9a7,http://www.atariage.com/manual_thumbs.html?SoftwareID=2176 -Tooth Protectors,DSD-Camelot,,,,,Unbelievably Rare,PB8K,A2600NTSC,,,fa2be8125c3c60ab83e1c0fe56922fcb, -Top Gun (a.k.a. Air Patrol),Starsoft,,,,,,,A2600PAL,,,e0b24c3f40a46cda52e29835ab7ad660, -Touchdown Football,Atari,,,1988,CX7823,Common,A78SG,A7800NTSC,,,208ef955fa90a29815eb097bce89bace,http://www.atariage.com/manual_thumbs.html?SoftwareID=2151 -Tower Toppler,Atari,,,1988,CX7856,Common,A78S4R,A7800NTSC,,,8d64763db3100aadc552db5e6868506a,http://www.atariage.com/manual_thumbs.html?SoftwareID=2152 -Tower Toppler,Atari,,,1988,CX7856,Common,A78S4R,A7800PAL,,,32a37244a9c6cc928dcdf02b45365aa8,http://www.atariage.com/manual_thumbs.html?SoftwareID=2152 -Towering Inferno,US Games,,,1982,VC 1009,Uncommon,,A2600NTSC,,,0aa208060d7c140f20571e3341f5a3f8, -Track and Field,Atari,,,,CX26125/7,Rare,,A2600NTSC,,,6ae4dc6d7351dacd1012749ca82f9a56, -Traffic,,,,,,,,A2600NTSC,,,4df9d7352a56a458abb7961bf10aba4e, -Treasure Below,Video Gems,,,,,,,A2600PAL,,,66706459e62514d0c39c3797cbf73ff1, -Treasure Below,Video Gems,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,81414174f1816d5c1e583af427ac89fc, -Tree Hugger (12-20-2002 Pave Demo),Billy Eno,,Homebrew,,,,,A2600NTSC,,,65c6406f5af934590097c8c032ebb482, -Trick Shot,Imagic,Dennis Koble,,1982,IA3000,Rare,,A2600NTSC,,,24df052902aa9de21c2b2525eb84a255, -Trick Shot,Imagic,Dennis Koble,,1982,IA3000,Rare,,A2600PAL,,,dca90ea1084a2fdbe300d7178ca1a138, -Tuby Bird (a.k.a. Vogel Flieh),Starsoft,,,,SS-020,,,A2600PAL,,,e17699a54c90f3a56ae4820f779f72c4, -Tunnel Runner,CBS Electronics,,,,4L-2520,Rare,CBS12K,A2600NTSC,,,b2737034f974535f5c0c6431ab8caf73, -Tunnel Runner,CBS Electronics,,,,4L-2520,Rare,CBS12K,A2600NTSC,,,efefc02bbc5258815457f7a5b8d8750a, -Turmoil,20th Century Fox,,,,,,,A2600NTSC,,,152e55f88af3ff647e75a3070b7b6842, -Turmoil,20th Century Fox,,,,11007,Uncommon,,A2600NTSC,,,7a5463545dfb2dcfdafa6074b2f2c15e, -Tutankham,Parker Bros,,,1983,,,PB8K,A2600PAL,,,66c2380c71709efa7b166621e5bb4558, -Tutankham,Parker Bros,,,1983,PB5340,Uncommon,PB8K,A2600NTSC,,,085322bae40d904f53bdcc56df0593fc, -UFO #6,,,Hack,,,,,A2600NTSC,,,6fc27a9233fc69d28d3f190b4ff80f03, -UFO Patrol,,,,,,Extremely Rare,,A2600NTSC,,,619de46281eb2e0adbb98255732483b4, -Universal Chaos,Telegames,,,,7062 A305,Rare,,A2600NTSC,,,81a010abdba1a640f7adf7f84e13d307, -Up 'n Down,Sega,,,1983,009-01,Extremely Rare,,A2600NTSC,,,a499d720e7ee35c62424de882a3351b6, -Vanguard,Atari,,,,CX2669,Common,A8K,A2600NTSC,,,c6556e082aac04260596b4045bc122de, -Vanguard,Atari,,,,CX2669,Common,A8K,A2600PAL,,,3caa902ac0ce4509308990645876426a, -Vanguard,CCE,,,,,,A8K,A2600NTSC,,,7ef74879d7cb9fa0ef161b91ad55b3bb, -Vault Assault,Prescott,,,,,,,A2600NTSC,,,787ebc2609a31eb5c57c4a18837d1aee, -Ventrra Invaders 2002,,Charles Morgan,Hack,,,,,A2600NTSC,,,39da69ff9833f8c143f03b6e0e7a996b, -Venture 2,Tim Snider,,Hack,,,,,A2600NTSC,,,7ca7a471d70305c673fedd08174a81e8, -Venture,Atari,,,,CX26145,Rare,,A2600PAL,,,c63a98ca404aa5ee9fcff1de488c3f43, -Venture,CBS Electronics,,,,,,,A2600PAL,,,345758747b893e4c9bdde8877de47788, -Venture,Coleco,,,,2457,Common,,A2600NTSC,,,3e899eba0ca8cd2972da1ae5479b4f0d, -Vertical Playfield Demo 1,,,,,,,,A2600NTSC,,,6cd1dc960e3e8d5c5e0fbe67ab49087a, -Vertical Playfield Demo 2,,,,,,,,A2600NTSC,,,ea6d40db5498d6386571a76df448aa4c, -Vertical Rainbow Demo,,,,,,,,A2600NTSC,,,ce6c4270f605ad3ce5e82678b0fc71f8, -Vertical Ship Demo 1,,,,,,,,A2600NTSC,,,bdc381baf7c252c63739c5e9ed087a5c, -Video Checkers,Atari,Carol Shaw,,1978,CX2636,Rare,,A2600NTSC,,,539d26b6e9df0da8e7465f0f5ad863b7,http://www.atariage.com/manual_thumbs.html?SoftwareID=1427 -Video Checkers,Atari,Carol Shaw,,1978,CX2636,Rare,,A2600PAL,,,193f060553ba0a2a2676f91d9ec0c555,http://www.atariage.com/manual_thumbs.html?SoftwareID=1427 -Video Chess,Atari,Bob Whitehead,,1978,CX2645,Uncommon,,A2600NTSC,,,f0b7db930ca0e548c41a97160b9f6275,http://www.atariage.com/manual_html_page.html?SoftwareID=1429 -Video Chess,Atari,Bob Whitehead,,1978,CX2645,Uncommon,,A2600PAL,,,3ef9573536730dcd6d9c20b6822dbdc4,http://www.atariage.com/manual_html_page.html?SoftwareID=1429 -Video Cube,CCE,,,,,,,A2600NTSC,,,ed1492d4cafd7ebf064f0c933249f5b0, -Video Jogger,Exus,,,,,Extremely Rare,,A2600NTSC,,,4191b671bcd8237fc8e297b4947f2990, -Video Life,CommaVid,,,,,Extremely Rare,,A2600NTSC,,,497f3d2970c43e5224be99f75e97cbbb, -Video Olympics - Pong Sports,Atari,Joe Decuir,,1977,CX2621,Common,,A2600NTSC,Paddles,Paddles,60e0ea3cbe0913d39803477945e9e5ec, -Video Olympics - Pong Sports,Atari,Joe Decuir,,1977,CX2621,Common,,A2600NTSC,Paddles,Paddles,c00b65d1bae0aef6a1b5652c9c2156a1, -Video Olympics - Pong Sports,Atari,Joe Decuir,,1977,CX2621,Common,,A2600PAL,Paddles,Paddles,77d0a577636e1c9212aeccde9d0baa4b, -Video Pinball,Atari,Bob Smith,,1980,,,,A2600PAL,,,a2424c1a0c783d7585d701b1c71b5fdc,http://www.atariage.com/manual_html_page.html?SoftwareID=1437 -Video Pinball,Atari,Bob Smith,,1980,CX2648,Uncommon,,A2600NTSC,,,107cc025334211e6d29da0b6be46aec7,http://www.atariage.com/manual_html_page.html?SoftwareID=1437 -Video Pinball,Atari,Bob Smith,,1980,CX2648,Uncommon,,A2600PAL,,,6e59dd52f88c00d5060eac56c1a0b0d3,http://www.atariage.com/manual_html_page.html?SoftwareID=1437 -Video Reflex,Exus,,,,,Extremely Rare,,A2600NTSC,,,ee659ae50e9df886ac4f8d7ad10d046a, -Video Simon,,Mark De Smet,Homebrew,,,,,A2600NTSC,,,16f494f20af5dc803bc35939ef924020, -Video Time Machine,,Chris Cracknell,Homebrew,,,,,A2600NTSC,,,93acd5020ae8eb5673601e2edecbc158, -Virtual Pet (Demo 1),,,,,,,,A2600NTSC,,,4f0071946e80ca68edfdccbac86dcce0, -Virtual Pet (Demo 2 update),,,,,,,,A2600NTSC,,,1f349dd41c3f93c4214e5e308dccb056, -Virtual Pet (V007) (after Demo 2 update),V007,,,,,,,A2600NTSC,,,3b80b8f52a0939e16b5059f93a3fc19a, -Volleyball,Dactar,,,,,,,A2600PAL,,,5faffe1c4c57430978dec5ced32b9f4a, -Volleyball,Starsoft,,,,,,,A2600PAL,,,4d8396deeabb40b5e8578276eb5a8b6d, -Wabbit,Apollo,,,,AP 2010,Rare,,A2600NTSC,,,6041f400b45511aa3a69fab4b8fc8f41, -Wachroboter Jagt Jupy (a.k.a. Hey! Stop!),Starsoft,,,,,,,A2600PAL,,,1c5796d277d9e4df3f6648f7012884c4, -Walker,,,,,,,,A2600PAL,,,d175258b2973b917a05b46df4e1cf15d, -Wall Ball,Avalon Hill,,,,50030,Extremely Rare,,A2600NTSC,,,d3456b4cf1bd1a7b8fb907af1a80ee15, -Wall Defender,Bomb,,,,CA285,Extremely Rare,,A2600NTSC,,,c16fbfdbfdf5590cc8179e4b0f5f5aeb, -War Of The Worlds,,Kyle Pittman,Homebrew,,,,,A2600NTSC,,,9436b7ad131b5a1f7753ce4309ba3dee, -Warlords,Atari,Carla Meninsky,,1981,CX2610,Uncommon,,A2600NTSC,Paddles,Paddles,cbe5a166550a8129a5e6d374901dffad,http://www.atariage.com/manual_html_page.html?SoftwareID=1442 -Warlords,Atari,Carla Meninsky,,1981,CX2610,Uncommon,,A2600PAL,Paddles,Paddles,0c80751f6f7a3b370cc9e9f39ad533a7,http://www.atariage.com/manual_html_page.html?SoftwareID=1442 -Warplock,Data Age,,,1982,DA 1002,Common,,A2600NTSC,,,679e910b27406c6a2072f9569ae35fc8, -Warring Worms (Beta 1),Baroque Gaming,Brian Eno,Homebrew,,,,,A2600NTSC,,,7a64b5a6e90619c6aacf244cdd7502f8, -Warring Worms (Beta 2),Baroque Gaming,Brian Eno,Homebrew,,,,,A2600NTSC,,,2f66ebf037321ed0442ac4b89ce22633, -Warring Worms,Baroque Gaming,Brian Eno,Homebrew,,,,,A2600NTSC,,,7e7c4c59d55494e66eef5e04ec1c6157, -Wasp (Standard Edition),,Mark Ball,Homebrew,2009,,,A7832,A7800NTSC,,,412cc5bfa08bd03244b9c4e8d46cd0a0, -Water Ski,Froggo,,,1988,FG2002,Scarce,A78S4,A7800NTSC,,,427cb05d0a1abb068998e2760d77f4fb,http://www.atariage.com/manual_thumbs.html?SoftwareID=2157 -Wavy Line Test,,,,,,,,A2600NTSC,,,0d7e630a14856f4d52c9666040961d4d, -Weltraum Tunnel,Bitcorp,,,,,,,A2600PAL,,,c5387fc1aa71f11d2fa82459e189a5f0, -Weltraum Tunnel,Starsoft,,,,,,,A2600PAL,,,bce4c291d0007f16997faa5c4db0a6b8, -Westward Ho,Playaround,,,,,,,A2600PAL,,,d47387658ed450db77c3f189b969cc00, -Wing War,,Thomas Jentzsch,Hack,,,,,A2600NTSC,,,0cdd9cc692e8b04ba8eb31fc31d72e5e, -Wing War,Imagic,Michael Greene,,,EIZ-002-04,Extremely Rare,,A2600PAL,,,4e02880beeb8dbd4da724a3f33f0971f, -Wing War,Imagic,Michael Greene,,,EIZ-002-04,Extremely Rare,,A2600PAL,,,9d2938eb2b17bb73e9a79bbc06053506, -Winter Games,Atari,,,1987,CX7831,Scarce,A78SGR,A7800NTSC,,,3799d72f78dda2ee87b0ef8bf7b91186,http://www.atariage.com/manual_thumbs.html?SoftwareID=2153 -Winter Games,Epyx,,,1987,,,,A2600PAL,,,8c36ed2352801031516695d1eeefe617, -Winter Games,Epyx,,,1987,8056100251,Rare,,A2600NTSC,,,83fafd7bd12e3335166c6314b3bde528, -Wizard of Wor,CBS Electronics,,,,M8774,Rare,,A2600NTSC,,,7e8aa18bc9502eb57daaf5e7c1e94da7, -Wizard of Wor,CBS Electronics,,,,M8774,Rare,,A2600PAL,,,663ef22eb399504d5204c543b8a86bcd, -Wizard,,,Prototype,,,,,A2600NTSC,,,3b86a27132fb74d9b35d4783605a1bcb, -Wizard,,,Prototype,,,,,A2600NTSC,,,7b24bfe1b61864e758ada1fe9adaa098, -Wizard,,,Prototype,,,,,A2600NTSC,,,c43bd363e1f128e73ba5f0380b6fd7e3, -Word Zapper,US Games,,,,,,,A2600PAL,,,37527966823ee9243d34c7da8302774f, -Word Zapper,US Games,,,,VC 1003,Uncommon,,A2600NTSC,,,ec3beb6d8b5689e867bafb5d5f507491, -Worm (0703),,Mark Ball,Homebrew,2010,,,A7816,A7800NTSC,,,6813ffff510f930c867b3f0aba78ac85, -Worm War I,20th Century Fox,,,1982,,,,A2600PAL,,,52b448757081fd9fabf859f4e2f91f6b, -Worm War I,20th Century Fox,,,1982,11001,Uncommon,,A2600NTSC,,,87f020daa98d0132e98e43db7d8fea7e, -Worm War I,CCE,,,,,,,A2600NTSC,,,007d18dedc1f0565f09c42aa61a6f585, -X-Doom V.26,,,,,,,,A2600NTSC,,,0d35618b6d76ddd46d2626e9e3e40db5, -X-Doom V.27,,,,,,,,A2600NTSC,,,f613aad84d2163d6b197b220bfec1b7e, -X-Man,CosmoVision-Universal Gamex,,,,GX-001,Unbelievably Rare,,A2600NTSC,,,5961d259115e99c30b64fe7058256bcf, -X-Man,CosmoVision-Universal Gamex,,,,GX-001,Unbelievably Rare,,A2600NTSC,,,f38358cd8f5ecfedffd5aca1aa939f18, -Xaxyrax Road,,Charles Morgan,Hack,,,,,A2600NTSC,,,9e2c7299c69b602443d327c7dad51cbf, -Xenophobe,Atari,,,1989,CX7858,Scarce,A78SG,A7800NTSC,,,05fb699db9eef564e2fe45c568746dbc,http://www.atariage.com/manual_thumbs.html?SoftwareID=2154 -Xenophobe,Atari,,,1989,CX7858,Scarce,A78SG,A7800PAL,,,70937c3184f0be33d06f7f4382ca54de,http://www.atariage.com/manual_thumbs.html?SoftwareID=2154 -Xenophobe,Atari,,,1990,,,,A2600PAL,,,f02ba8b5292bf3017d10553c9b7b2861, -Xenophobe,Atari,,,1990,CX26172,Extremely Rare,,A2600PAL,,,eaf744185d5e8def899950ba7c6e7bb5, -Xevious,Atari,,,1989,CX7810,Common,,A7800NTSC,,,d7dc17379aa25e5ae3c14b9e780c6f6d,http://www.atariage.com/manual_thumbs.html?SoftwareID=2155 -Xevious,Atari,,,1989,CX7810,Common,,A7800PAL,,,b1a9f196ce5f47ca8caf8fa7bc4ca46c,http://www.atariage.com/manual_thumbs.html?SoftwareID=2155 -Xevious,Atari,Tod Frye,Prototype,,CX2695,,,A2600NTSC,,,c6688781f4ab844852f4e3352772289b, -Xevious,CCE,,,,,,,A2600NTSC,,,24385ba7f5109fbe76aadc0a375de573, -Yahtzee,Hozer Video Games,,Homebrew,,,,,A2600NTSC,,,d090836f0a4ea8db9ac7abb7d6adf61e, -Yar vs. Yar,,Justin J. Scott,Hack,,,,,A2600NTSC,,,096649575e451508006b17e0353259a5, -Yars' Defeat,,Justin J. Scott,Hack,,,,,A2600NTSC,,,159e5cd6ccb968015f49aed5adbc91eb, -Yars' Revenge,Atari,Howard Scott Warshaw,,,CX2655,Common,,A2600NTSC,,,5f681403b1051a0822344f467b05a94d,http://www.atariage.com/manual_thumbs.html?SoftwareID=1452 -Yars' Revenge,Atari,Howard Scott Warshaw,,,CX2655,Common,,A2600NTSC,,,c5930d0e8cdae3e037349bfa08e871be,http://www.atariage.com/manual_thumbs.html?SoftwareID=1452 -Yars' Revenge,Atari,Howard Scott Warshaw,,,CX2655,Common,,A2600PAL,,,e91d2ecf8803ae52b55bbf105af04d4b,http://www.atariage.com/manual_thumbs.html?SoftwareID=1452 -Yellow Submarine,,Kyle Pittman,Hack,,,,,A2600NTSC,,,3856b9425cc0185ed770376a62af0282, -Z-Tack 2,,Steve Engelhardt,Hack,,13,,,A2600NTSC,,,97d0151beb84acbe82aa6db18cd91b98, -Z-Tack,Bomb,,,,13,Extremely Rare,,A2600NTSC,,,c469151655e333793472777052013f4f, -Zaxxon,CBS Electronics,,,,,,,A2600PAL,,,25bb080457351be724aac8a02021aa92, -Zaxxon,CBS Electronics,,,,4L-2277,Extremely Rare,,A2600NTSC,,,eea0da9b987d661264cce69a7c13c3bd, -Zero Patrol,,Charles Morgan,Hack,,,,,A2600NTSC,,,c5a76bafc4676edb76e0126fb9f0fb2d, -Zoo Fun,HomeVision,,,,,Extremely Rare,,A2600PAL,,,fb833ed50c865a9a505a125fc9d79a7e, -b*nQ,,Ken Siders,Homebrew,2007,,,,A7800NTSC,,,ce6fbdc7b037a4efdaf87267f5f292cc,http://www.atariage.com/software_page.html?SoftwareID=4105 \ No newline at end of file diff --git a/Assets/gamedb/gamedb_sega_gg.txt b/Assets/gamedb/gamedb_sega_gg.txt index 82224fb10d..a8a1d105bb 100644 --- a/Assets/gamedb/gamedb_sega_gg.txt +++ b/Assets/gamedb/gamedb_sega_gg.txt @@ -231,7 +231,7 @@ B19256C6716147A9744F5BD528F14450 Magic Knight Rayearth 2 - Making of Magic Knig 846D48D0F4024C8094117599D0E1EEF1 Magic Knight Rayearth (J) GG SRAM=8192 Japan E496FF2196C372F4D6111538950D25CA Magical Puzzle Popils (W) (En,Ja) GG Puzzle SRAM=8192 World 3AF0C6DDF5F00A493E1F159FCEDC0933 Magical Taruruuto-kun (J) GG Japan -B0C35BC53AB7C184D34E5624F69AAD24 The Majors Pro Baseball (U) GG Sports;Baseball SRAM=128;GGLink USA +B0C35BC53AB7C184D34E5624F69AAD24 The Majors Pro Baseball (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA A15C5219F766D516D1B8D9A09B9A2BB4 Mappy (J) GG Japan B83F36FD113A8F75F1A29652ACB641FC Marble Madness (UE) GG Arcade USA;Europe BA846684A66E90372C3C234955EE28BC Marko's Magic Football (E) (En,Fr,De,Es) GG Europe @@ -461,9 +461,9 @@ A23E89266DDAD3C856E7401D04A49C6C Woody Pop (W) (Rev 1) GG World 13F72ACFEA47587F9AA9F655BF98653C World Class Leader Board Golf (UE) GG Sports;Golf USA;Europe D95D381C6AFFB8345EE5457655E393D1 World Cup USA 94 (UE) (En,Fr,De,Es,It,Nl,Pt,Sv) GG Sports;Soccer USA;Europe D8939B64458FAF174CDC1241F777CB59 World Derby (J) GG GGLink Japan -E7EABBFC7A1F1339C4720249AEA92A32 World Series Baseball '95 (U) GG Sports;Baseball SRAM=128;GGLink USA -59359FC38865CFF00C90D6EB148DDC2F World Series Baseball (U) GG Sports;Baseball SRAM=128;GGLink USA -05CAC33029F0CAAC27774504C1AA8597 World Series Baseball (U) (Rev 1) GG Sports;Baseball SRAM=128;GGLink USA +E7EABBFC7A1F1339C4720249AEA92A32 World Series Baseball '95 (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA +59359FC38865CFF00C90D6EB148DDC2F World Series Baseball (U) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA +05CAC33029F0CAAC27774504C1AA8597 World Series Baseball (U) (Rev 1) GG Sports;Baseball SRAM=128;GGLink;EEPROM USA D810E851AD60ED5BA50B6246C2CE12F2 WWF Raw (UE) GG Sports;Wrestling USA;Europe 571AC03B80E3075C699CD583BF8651FD X-Men - Gamemaster's Legacy (UE) GG Marvel USA;Europe CA15F2BA2507EBD836C42D9D10231EB1 X-Men - Mojo World (UE) GG Marvel USA;Europe diff --git a/Assets/gamedb/gamedb_sega_sms.txt b/Assets/gamedb/gamedb_sega_sms.txt index 1f16380c3b..b3a7102c79 100644 --- a/Assets/gamedb/gamedb_sega_sms.txt +++ b/Assets/gamedb/gamedb_sega_sms.txt @@ -106,7 +106,7 @@ F2535DF9BDC3A84221303FA62D61AD6E Back to the Future Part II (E) SMS Europe 3D24A52E98E6C85D7C059386451CE749 Back to the Future Part III (E) SMS PAL Europe 8A94DED3D95AA46DAE8800B92E66D3EE Baku Baku (B) SMS Brazil 7A5D3B9963E316CB7F73BBDC2A7311C6 Bank Panic (E) SMS Europe -26DF4404950CB8DA47235833C0C101C6 Bart vs. the Space Mutants (E) SMS Europe +26DF4404950CB8DA47235833C0C101C6 Bart vs. the Space Mutants (E) SMS PAL Europe CBA2EC2940619956359801618E7AAB17 Bart vs. the World (E) SMS Europe 0069B1BD9C5B6B88ACE6324D7E61539F Basketball Nightmare (E) SMS Sports;Basketball Europe 215876A62D3CA48D28E98CD8A2C70A15 Batman Returns (E) SMS Europe diff --git a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs index 9db622672e..31b65c5df5 100644 --- a/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs +++ b/BizHawk.Client.ApiHawk/Classes/BizHawkSystemIdToCoreSystemEnumConverter.cs @@ -32,9 +32,6 @@ namespace BizHawk.Client.ApiHawk return CoreSystem.Atari2600; case "A78": - return CoreSystem.Atari2600; - - case "A7800": return CoreSystem.Atari7800; case "Coleco": diff --git a/BizHawk.Client.Common/PathManager.cs b/BizHawk.Client.Common/PathManager.cs index 9543368fd8..c77af2cca0 100644 --- a/BizHawk.Client.Common/PathManager.cs +++ b/BizHawk.Client.Common/PathManager.cs @@ -266,6 +266,12 @@ namespace BizHawk.Client.Common return Path.Combine(MakeAbsolutePath(pathEntry.Path, game.System), name) + ".SaveRAM"; } + + public static string AutoSaveRamPath(GameInfo game) + { + var path = SaveRamPath(game); + return path.Insert(path.Length - 8, ".AutoSaveRAM"); + } public static string RetroSaveRAMDirectory(GameInfo game) { diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 3dbd302b88..d20e74a845 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -8,7 +8,6 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores; using BizHawk.Emulation.Cores.Libretro; using BizHawk.Emulation.Cores.Atari.A7800Hawk; -using BizHawk.Emulation.Cores.Atari.Atari7800; using BizHawk.Emulation.Cores.Calculators; using BizHawk.Emulation.Cores.Computers.AppleII; using BizHawk.Emulation.Cores.Computers.Commodore64; @@ -471,7 +470,7 @@ namespace BizHawk.Client.Common System = "PSX" }; } - else if (ext == ".iso" || ext == ".cue" || ext == ".ccd") + else if (ext == ".iso" || ext == ".cue" || ext == ".ccd" || ext == ".mds") { if (file.IsArchive) { @@ -495,7 +494,7 @@ namespace BizHawk.Client.Common throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log); } - var disc = discMountJob.OUT_Disc; + var disc = discMountJob.OUT_Disc; // ----------- // TODO - use more sophisticated IDer @@ -515,7 +514,9 @@ namespace BizHawk.Client.Common // try to use our wizard methods game = new GameInfo { Name = Path.GetFileNameWithoutExtension(file.Name), Hash = discHash }; - switch (new DiscIdentifier(disc).DetectDiscType()) + var dt = new DiscIdentifier(disc).DetectDiscType(); + + switch (dt) { case DiscType.SegaSaturn: game.System = "SAT"; @@ -533,9 +534,23 @@ namespace BizHawk.Client.Common case DiscType.PCFX: game.System = "PCFX"; break; + case DiscType.TurboCD: + game.System = "PCECD"; + break; + + case DiscType.Amiga: + case DiscType.CDi: + case DiscType.Dreamcast: + case DiscType.GameCube: + case DiscType.NeoGeoCD: + case DiscType.Panasonic3DO: + case DiscType.Playdia: + case DiscType.Wii: + // no supported emulator core for these (yet) + game.System = dt.ToString(); + throw new NoAvailableCoreException(dt.ToString()); case DiscType.AudioDisc: - case DiscType.TurboCD: case DiscType.UnknownCDFS: case DiscType.UnknownFormat: if (PreferredPlatformIsDefined(ext)) @@ -544,7 +559,7 @@ namespace BizHawk.Client.Common } else { - game.System = "PCECD"; + game.System = "NULL"; // "PCECD"; } break; @@ -553,6 +568,9 @@ namespace BizHawk.Client.Common switch (game.System) { + case "NULL": + nextEmulator = null; + break; case "GEN": var genesis = new GPGX(nextComm, null, new[] { disc }, GetCoreSettings(), GetCoreSyncSettings()); nextEmulator = genesis; @@ -938,19 +956,8 @@ namespace BizHawk.Client.Common } break; case "A78": - var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "EMU7800.csv"); - - if (!VersionInfo.DeveloperBuild) - { - nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath); // Don't expose A7800Hawk in releases yet - } - else - { - nextEmulator = Global.Config.A78_UseEmu7800 - ? nextEmulator = new Atari7800(nextComm, game, rom.RomData, gamedbpath) - : nextEmulator = new A7800Hawk(nextComm, game, rom.RomData, gamedbpath, GetCoreSettings(), GetCoreSyncSettings()); - } - + var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb_a7800.csv"); + nextEmulator = new A7800Hawk(nextComm, game, rom.RomData, gamedbpath, GetCoreSettings(), GetCoreSyncSettings()); break; case "C64": var c64 = new C64(nextComm, Enumerable.Repeat(rom.RomData, 1), rom.GameInfo, GetCoreSettings(), GetCoreSyncSettings()); @@ -1041,7 +1048,14 @@ namespace BizHawk.Client.Common DoMessageCallback("Failed to load a GB rom in SGB mode. Disabling SGB Mode."); return LoadRom(path, nextComm, false, recursiveCount + 1); } - else + + // handle exceptions thrown by the new detected systems that bizhawk does not have cores for + else if (ex is NoAvailableCoreException) + { + DoLoadErrorCallback(ex.Message + "\n\n" + ex, system); + } + + else { DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system); } diff --git a/BizHawk.Client.Common/config/Config.cs b/BizHawk.Client.Common/config/Config.cs index 87a885805f..bcdeb39420 100644 --- a/BizHawk.Client.Common/config/Config.cs +++ b/BizHawk.Client.Common/config/Config.cs @@ -113,7 +113,6 @@ namespace BizHawk.Client.Common public bool InputConfigAutoTab = true; public bool ShowLogWindow = false; public bool BackupSavestates = true; - public bool BackupSaveram = true; public bool SaveScreenshotWithStates = true; public int BigScreenshotSize = 128 * 1024; public bool NoLowResLargeScreenshotWithStates = false; @@ -134,6 +133,21 @@ namespace BizHawk.Client.Common public string Update_IgnoreVersion = ""; public bool CDLAutoSave = true, CDLAutoStart = true; + /// + /// Makes a .bak file before any saveram-writing operation (could be extended to make timestamped backups) + /// + public bool BackupSaveram = true; + + /// + /// Whether to make AutoSave files at periodic intervals + /// + public bool AutosaveSaveRAM; + + /// + /// Intervals at which to make AutoSave files + /// + public int FlushSaveRamFrames; + //check CurrentDomain_AssemblyResolve if you change the defaults or name of this key public bool UseNLua = true; // Whether or not to use a good, reliable, memory-leak-free lua interface that is slower than the original luainterface @@ -542,7 +556,6 @@ namespace BizHawk.Client.Common public bool NES_InQuickNES = true; public bool SNES_InSnes9x = true; public bool GBA_UsemGBA = true; - public bool A78_UseEmu7800 = true; public bool SGB_UseBsnes = false; public bool CoreForcingViaGameDB = true; public string LibretroCore; diff --git a/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs b/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs index 1b9670dafc..69a04d4028 100644 --- a/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs +++ b/BizHawk.Client.Common/lua/EmuLuaLibrary.Memory.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using NLua; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; +using BizHawk.Common.BufferExtensions; namespace BizHawk.Client.Common { @@ -108,6 +109,37 @@ namespace BizHawk.Client.Common return false; } + [LuaMethod("hash_region", "Returns a hash as a string of a region of memory, starting from addr, through count bytes. If the domain is unspecified, it uses the current region.")] + public string HashRegion(int addr, int count, string domain = null) + { + var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)]; + + // checks + if (addr < 0 || addr >= d.Size) + { + string error = $"Address {addr} is outside the bounds of domain {d.Name}"; + Log(error); + throw new ArgumentOutOfRangeException(error); + } + if (addr + count > d.Size) + { + string error = $"Address {addr} + count {count} is outside the bounds of domain {d.Name}"; + Log(error); + throw new ArgumentOutOfRangeException(error); + } + + byte[] data = new byte[count]; + for (int i = 0; i < count; i++) + { + data[i] = d.PeekByte(addr + i); + } + + using (var hasher = System.Security.Cryptography.SHA256.Create()) + { + return hasher.ComputeHash(data).BytesToHexString(); + } + } + #endregion #region Common Special and Legacy Methods diff --git a/BizHawk.Client.Common/movie/MovieSession.cs b/BizHawk.Client.Common/movie/MovieSession.cs index 313e313cd9..a8b82e741a 100644 --- a/BizHawk.Client.Common/movie/MovieSession.cs +++ b/BizHawk.Client.Common/movie/MovieSession.cs @@ -8,7 +8,6 @@ using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.GBA; using BizHawk.Emulation.Cores.Atari.A7800Hawk; -using BizHawk.Emulation.Cores.Atari.Atari7800; namespace BizHawk.Client.Common { @@ -465,7 +464,6 @@ namespace BizHawk.Client.Common public bool? PreviousNES_InQuickNES { get; set; } public bool? PreviousSNES_InSnes9x { get; set; } public bool? PreviousGBA_UsemGBA { get; set; } - public bool? PreviousA78_UseEmu7800 { get; set; } public void QueueNewMovie(IMovie movie, bool record, IEmulator emulator) { @@ -533,22 +531,6 @@ namespace BizHawk.Client.Common Global.Config.GBA_UsemGBA = false; } } - else if (!record && emulator.SystemId == "A78") // meh, copy pasta one more time, last time, I promise - { - var atari7800HawkName = ((CoreAttribute)Attribute.GetCustomAttribute(typeof(A7800Hawk), typeof(CoreAttribute))).CoreName; - var emu7800HawkName = ((CoreAttribute)Attribute.GetCustomAttribute(typeof(Atari7800), typeof(CoreAttribute))).CoreName; - - if (movie.Core == atari7800HawkName) - { - PreviousA78_UseEmu7800 = Global.Config.A78_UseEmu7800; - Global.Config.A78_UseEmu7800 = true; - } - else if (movie.Core == emu7800HawkName) - { - PreviousA78_UseEmu7800 = Global.Config.A78_UseEmu7800; - Global.Config.A78_UseEmu7800 = false; - } - } if (record) // This is a hack really, we need to set the movie to its propert state so that it will be considered active later { diff --git a/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs b/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs index 92f3bd42d1..3c8b605edc 100644 --- a/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs +++ b/BizHawk.Client.Common/movie/interfaces/IMovieSession.cs @@ -20,7 +20,6 @@ namespace BizHawk.Client.Common bool? PreviousNES_InQuickNES { get; set; } bool? PreviousSNES_InSnes9x { get; set; } bool? PreviousGBA_UsemGBA { get; set; } - bool? PreviousA78_UseEmu7800 { get; set; } void HandleMovieOnFrameLoop(); void HandleMovieAfterFrameLoop(); diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index ed41d86b61..4b5c27aa04 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -514,14 +514,14 @@ namespace BizHawk.Client.Common Log?.Dispose(); Log = branch.InputLog.Clone(); - ////_changes = true; + + _lagLog.FromLagLog(branch.LagLog); // if there are branch states, they will be loaded anyway // but if there's none, or only *after* divergent point, don't invalidate the entire movie anymore if (divergentPoint.HasValue) { _stateManager.Invalidate(divergentPoint.Value); - _lagLog.FromLagLog(branch.LagLog); // don't truncate LagLog if the branch's one is shorter, but input is the same } else { @@ -530,8 +530,7 @@ namespace BizHawk.Client.Common _stateManager.LoadBranch(Branches.IndexOf(branch)); _stateManager.SetState(branch.Frame, branch.CoreData); - - ////ChangeLog = branch.ChangeLog; + if (BindMarkersToInput) // pretty critical not to erase them { Markers = branch.Markers; diff --git a/BizHawk.Client.Common/tools/Cheat.cs b/BizHawk.Client.Common/tools/Cheat.cs index 15ec5fb62a..4680168276 100644 --- a/BizHawk.Client.Common/tools/Cheat.cs +++ b/BizHawk.Client.Common/tools/Cheat.cs @@ -284,29 +284,61 @@ namespace BizHawk.Client.Common case WatchSize.Byte: return (byte?)_val; case WatchSize.Word: - if (addr == _watch.Address) + if (_watch.BigEndian) { + if (addr == _watch.Address) + { + return (byte)(_val & 0xFF); + } return (byte)(_val >> 8); } - - return (byte)(_val & 0xFF); - case WatchSize.DWord: - if (addr == _watch.Address) + else { + if (addr == _watch.Address) + { + return (byte)(_val >> 8); + } + return (byte)(_val & 0xFF); + } + case WatchSize.DWord: + if (_watch.BigEndian) + { + if (addr == _watch.Address) + { + return (byte)((_val >> 24) & 0xFF); + } + + if (addr == _watch.Address + 1) + { + return (byte)((_val >> 16) & 0xFF); + } + + if (addr == _watch.Address + 2) + { + return (byte)((_val >> 8) & 0xFF); + } + + return (byte)(_val & 0xFF); + } + else + { + if (addr == _watch.Address) + { + return (byte)(_val & 0xFF); + } + + if (addr == _watch.Address + 1) + { + return (byte)((_val >> 8) & 0xFF); + } + + if (addr == _watch.Address + 2) + { + return (byte)((_val >> 16) & 0xFF); + } + return (byte)((_val >> 24) & 0xFF); } - - if (addr == _watch.Address + 1) - { - return (byte)((_val >> 16) & 0xFF); - } - - if (addr == _watch.Address + 2) - { - return (byte)((_val >> 8) & 0xFF); - } - - return (byte)(_val & 0xFF); } } diff --git a/BizHawk.Client.DiscoHawk/MainDiscoForm.cs b/BizHawk.Client.DiscoHawk/MainDiscoForm.cs index f74b095c74..cdd2c1a0f7 100644 --- a/BizHawk.Client.DiscoHawk/MainDiscoForm.cs +++ b/BizHawk.Client.DiscoHawk/MainDiscoForm.cs @@ -111,7 +111,7 @@ namespace BizHawk.Client.DiscoHawk foreach (string str in files) { string ext = Path.GetExtension(str).ToUpper(); - if(!ext.In(new string[]{".CUE",".ISO",".CCD"})) + if(!ext.In(new string[]{".CUE",".ISO",".CCD", ".MDS"})) { return new List(); } diff --git a/BizHawk.Client.EmuHawk/ArgParser.cs b/BizHawk.Client.EmuHawk/ArgParser.cs index 939ca94b29..9e4c5ab1b9 100644 --- a/BizHawk.Client.EmuHawk/ArgParser.cs +++ b/BizHawk.Client.EmuHawk/ArgParser.cs @@ -112,7 +112,7 @@ namespace BizHawk.Client.EmuHawk } else { - cmdRom = arg; + cmdRom = args[i]; } } } diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index 3e3d4436b9..2a860dd082 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -822,6 +822,12 @@ GBGPUView.cs + + Form + + + GBPrinterView.cs + Form @@ -1167,7 +1173,6 @@ - @@ -1317,7 +1322,7 @@ A7800ControllerSettings.cs - + A7800FilterSettings.cs @@ -1490,6 +1495,9 @@ GBGPUView.cs + + GBPrinterView.cs + GenDbgWind.cs @@ -2085,7 +2093,6 @@ - diff --git a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs index 7266aaab82..110d8201e5 100644 --- a/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs +++ b/BizHawk.Client.EmuHawk/DisplayManager/DisplayManager.cs @@ -586,6 +586,13 @@ namespace BizHawk.Client.EmuHawk }; var filterProgram = UpdateSourceInternal(job); + //this only happens when we're forcing the client to size itself with autoload and the core says 0x0.... + //we need some other more sensible client size. + if (filterProgram == null) + { + return new Size(256, 192); + } + var size = filterProgram.Filters[filterProgram.Filters.Count - 1].FindOutput().SurfaceFormat.Size; return size; diff --git a/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs b/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs index f5004be398..613d465979 100644 --- a/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs +++ b/BizHawk.Client.EmuHawk/Extensions/CoreExtensions.cs @@ -3,7 +3,6 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; -using BizHawk.Emulation.Cores.Atari.Atari7800; using BizHawk.Emulation.Cores.Nintendo.GBA; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; using BizHawk.Emulation.Cores.Nintendo.SNES; @@ -36,10 +35,6 @@ namespace BizHawk.Client.EmuHawk.CoreExtensions { return Properties.Resources.bsnes; } - else if (core is Atari7800) - { - return Properties.Resources.emu7800; - } else if (core is GPGX) { return Properties.Resources.genplus; diff --git a/BizHawk.Client.EmuHawk/FileLoader.cs b/BizHawk.Client.EmuHawk/FileLoader.cs index 1e6d123c78..0009646fb4 100644 --- a/BizHawk.Client.EmuHawk/FileLoader.cs +++ b/BizHawk.Client.EmuHawk/FileLoader.cs @@ -51,11 +51,11 @@ namespace BizHawk.Client.EmuHawk return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", - ".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X" + ".EXE", ".PRG", ".D64", "*G64", ".CRT", ".TAP", ".32X", ".MDS" }; } - return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", ".32X" }; + return new[] { ".NES", ".FDS", ".UNF", ".SMS", ".GG", ".SG", ".GB", ".GBC", ".GBA", ".PCE", ".SGX", ".BIN", ".SMD", ".GEN", ".MD", ".SMC", ".SFC", ".A26", ".A78", ".LNX", ".COL", ".ROM", ".M3U", ".CUE", ".CCD", ".SGB", ".Z64", ".V64", ".N64", ".WS", ".WSC", ".XML", ".DSK", ".DO", ".PO", ".PSF", ".MINIPSF", ".NSF", ".32X", ".MDS" }; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Designer.cs b/BizHawk.Client.EmuHawk/MainForm.Designer.cs index 6e491f5a49..9d6774638e 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Designer.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Designer.cs @@ -73,7 +73,7 @@ this.LoadCurrentSlotMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SaveRAMSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.FlushSaveRAMMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator(); this.MovieSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ReadonlyMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator15 = new System.Windows.Forms.ToolStripSeparator(); @@ -192,8 +192,6 @@ this.GbaCoreSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.VbaNextCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.MgbaCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.Atari7800CoreSubMenu = new System.Windows.Forms.ToolStripMenuItem(); - this.Emu7800CoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.Atari7800HawkCoreMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.SGBCoreSubmenu = new System.Windows.Forms.ToolStripMenuItem(); this.SgbBsnesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -238,8 +236,9 @@ this.coreToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.quickNESToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.nesHawkToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator34 = new System.Windows.Forms.ToolStripSeparator(); - this.NESPPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator34 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripSeparator35 = new System.Windows.Forms.ToolStripSeparator(); + this.NESPPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.NESNametableViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.NESGameGenieCodesMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.musicRipperToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -307,7 +306,8 @@ this.LoadGBInSGBMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolStripSeparator28 = new System.Windows.Forms.ToolStripSeparator(); this.GBGPUViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.GBGameGenieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.GBPrinterViewerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.GBGameGenieMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.GBASubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.GBACoreSelectionSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.GBAmGBAMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -329,7 +329,6 @@ this.SnesOptionsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.ColecoSubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.ColecoControllerSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator35 = new System.Windows.Forms.ToolStripSeparator(); this.ColecoSkipBiosMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.N64SubMenu = new System.Windows.Forms.ToolStripMenuItem(); this.N64PluginSettingsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -443,7 +442,12 @@ this.ShowMenuContextMenuSeparator = new System.Windows.Forms.ToolStripSeparator(); this.ShowMenuContextMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.timerMouseIdle = new System.Windows.Forms.Timer(this.components); - this.MainformMenu.SuspendLayout(); + this.SMSControllerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerStandardToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerPaddleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerLightPhaserToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SMSControllerSportsPadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.MainformMenu.SuspendLayout(); this.MainStatusBar.SuspendLayout(); this.MainFormContextMenu.SuspendLayout(); this.SuspendLayout(); @@ -902,26 +906,26 @@ this.LoadCurrentSlotMenuItem.Size = new System.Drawing.Size(178, 22); this.LoadCurrentSlotMenuItem.Text = "Load Current Slot"; this.LoadCurrentSlotMenuItem.Click += new System.EventHandler(this.LoadCurrentSlotMenuItem_Click); - // - // SaveRAMSubMenu - // - this.SaveRAMSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.FlushSaveRAMMenuItem}); - this.SaveRAMSubMenu.Name = "SaveRAMSubMenu"; - this.SaveRAMSubMenu.Size = new System.Drawing.Size(159, 22); - this.SaveRAMSubMenu.Text = "Save &RAM"; - this.SaveRAMSubMenu.DropDownOpened += new System.EventHandler(this.FlushSaveRAMSubMenu_DropDownOpened); - // - // FlushSaveRAMMenuItem - // - this.FlushSaveRAMMenuItem.Name = "FlushSaveRAMMenuItem"; - this.FlushSaveRAMMenuItem.Size = new System.Drawing.Size(156, 22); - this.FlushSaveRAMMenuItem.Text = "&Flush Save Ram"; - this.FlushSaveRAMMenuItem.Click += new System.EventHandler(this.FlushSaveRAMMenuItem_Click); - // - // toolStripMenuItem2 - // - this.toolStripMenuItem2.Name = "toolStripMenuItem2"; + + // + // SaveRAMSubMenu + // + this.SaveRAMSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.FlushSaveRAMMenuItem}); + this.SaveRAMSubMenu.Name = "SaveRAMSubMenu"; + this.SaveRAMSubMenu.Size = new System.Drawing.Size(159, 22); + this.SaveRAMSubMenu.Text = "Save &RAM"; + this.SaveRAMSubMenu.DropDownOpened += new System.EventHandler(this.SaveRAMSubMenu_DropDownOpened); + // + // FlushSaveRAMMenuItem + // + this.FlushSaveRAMMenuItem.Name = "FlushSaveRAMMenuItem"; + this.FlushSaveRAMMenuItem.Size = new System.Drawing.Size(156, 22); + this.FlushSaveRAMMenuItem.Text = "&Flush Save Ram"; + this.FlushSaveRAMMenuItem.Click += new System.EventHandler(this.FlushSaveRAMMenuItem_Click); + // toolStripMenuItem2 + // + this.toolStripMenuItem2.Name = "toolStripMenuItem2"; this.toolStripMenuItem2.Size = new System.Drawing.Size(156, 6); // // MovieSubMenu @@ -1805,7 +1809,6 @@ this.NesCoreSubMenu, this.CoreSNESSubMenu, this.GbaCoreSubMenu, - this.Atari7800CoreSubMenu, this.SGBCoreSubmenu, this.GBInSGBMenuItem, this.toolStripMenuItem16, @@ -1890,29 +1893,11 @@ this.MgbaCoreMenuItem.Text = "mGBA"; this.MgbaCoreMenuItem.Click += new System.EventHandler(this.GbaCorePick_Click); // - // Atari7800CoreSubMenu - // - this.Atari7800CoreSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.Emu7800CoreMenuItem, - this.Atari7800HawkCoreMenuItem}); - this.Atari7800CoreSubMenu.Name = "Atari7800CoreSubMenu"; - this.Atari7800CoreSubMenu.Size = new System.Drawing.Size(239, 22); - this.Atari7800CoreSubMenu.Text = "Atari 7800"; - this.Atari7800CoreSubMenu.DropDownOpened += new System.EventHandler(this.Atari7800CoreSubMenu_DropDownOpened); - // - // Emu7800CoreMenuItem - // - this.Emu7800CoreMenuItem.Name = "Emu7800CoreMenuItem"; - this.Emu7800CoreMenuItem.Size = new System.Drawing.Size(153, 22); - this.Emu7800CoreMenuItem.Text = "EMU7800"; - this.Emu7800CoreMenuItem.Click += new System.EventHandler(this.Atari7800CorePick_Click); - // // Atari7800HawkCoreMenuItem // this.Atari7800HawkCoreMenuItem.Name = "Atari7800HawkCoreMenuItem"; this.Atari7800HawkCoreMenuItem.Size = new System.Drawing.Size(153, 22); this.Atari7800HawkCoreMenuItem.Text = "Atari7800Hawk"; - this.Atari7800HawkCoreMenuItem.Click += new System.EventHandler(this.Atari7800CorePick_Click); // // SGBCoreSubmenu // @@ -2495,7 +2480,8 @@ this.SMSSubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.SMSregionToolStripMenuItem, this.SMSdisplayToolStripMenuItem, - this.SMStoolStripMenuItem2, + this.SMSControllerToolStripMenuItem, + this.SMStoolStripMenuItem2, this.SMSenableBIOSToolStripMenuItem, this.SMSEnableFMChipMenuItem, this.SMSOverclockMenuItem, @@ -2562,9 +2548,44 @@ this.SMSdisplayNtscToolStripMenuItem.Text = "NTSC"; this.SMSdisplayNtscToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayNTSC_Click); // - // SMSdisplayPalToolStripMenuItem + // SMSControllerToolStripMenuItem // - this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; + this.SMSControllerToolStripMenuItem.Name = "SMSControllerToolStripMenuItem"; + this.SMSControllerToolStripMenuItem.Text = "&Controller Type"; + this.SMSControllerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.SMSControllerStandardToolStripMenuItem, + this.SMSControllerPaddleToolStripMenuItem, + this.SMSControllerLightPhaserToolStripMenuItem, + this.SMSControllerSportsPadToolStripMenuItem}); + // + // SMSControllerStandardToolStripMenuItem + // + this.SMSControllerStandardToolStripMenuItem.Name = "SMSControllerStandardToolStripMenuItem"; + this.SMSControllerStandardToolStripMenuItem.Text = "Standard"; + this.SMSControllerStandardToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerStandardToolStripMenuItem_Click); + // + // SMSControllerPaddleToolStripMenuItem + // + this.SMSControllerPaddleToolStripMenuItem.Name = "SMSControllerPaddleToolStripMenuItem"; + this.SMSControllerPaddleToolStripMenuItem.Text = "Paddle"; + this.SMSControllerPaddleToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerPaddleToolStripMenuItem_Click); + // + // SMSControllerLightPhaserToolStripMenuItem + // + this.SMSControllerLightPhaserToolStripMenuItem.Name = "SMSControllerLightPhaserToolStripMenuItem"; + this.SMSControllerLightPhaserToolStripMenuItem.Text = "Light Phaser"; + this.SMSControllerLightPhaserToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerLightPhaserToolStripMenuItem_Click); + // + // SMSControllerSportsPadToolStripMenuItem + // + this.SMSControllerSportsPadToolStripMenuItem.Name = "SMSControllerSportsPadToolStripMenuItem"; + this.SMSControllerSportsPadToolStripMenuItem.Text = "Sports Pad"; + this.SMSControllerSportsPadToolStripMenuItem.Click += new System.EventHandler(this.SMSControllerSportsPadToolStripMenuItem_Click); + + // + // SMSdisplayPalToolStripMenuItem + // + this.SMSdisplayPalToolStripMenuItem.Name = "SMSdisplayPalToolStripMenuItem"; this.SMSdisplayPalToolStripMenuItem.Size = new System.Drawing.Size(104, 22); this.SMSdisplayPalToolStripMenuItem.Text = "PAL"; this.SMSdisplayPalToolStripMenuItem.Click += new System.EventHandler(this.SMS_DisplayPAL_Click); @@ -2765,7 +2786,8 @@ this.LoadGBInSGBMenuItem, this.toolStripSeparator28, this.GBGPUViewerMenuItem, - this.GBGameGenieMenuItem}); + this.GBGameGenieMenuItem, + this.GBPrinterViewerMenuItem}); this.GBSubMenu.Name = "GBSubMenu"; this.GBSubMenu.Size = new System.Drawing.Size(34, 19); this.GBSubMenu.Text = "&GB"; @@ -2803,10 +2825,17 @@ this.GBGameGenieMenuItem.Size = new System.Drawing.Size(233, 22); this.GBGameGenieMenuItem.Text = "&Game Genie Encoder/Decoder"; this.GBGameGenieMenuItem.Click += new System.EventHandler(this.GBGameGenieMenuItem_Click); - // - // GBASubMenu - // - this.GBASubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + // + // GBPrinterViewerMenuItem + // + this.GBPrinterViewerMenuItem.Name = "GBPrinterViewerMenuItem"; + this.GBPrinterViewerMenuItem.Size = new System.Drawing.Size(233, 22); + this.GBPrinterViewerMenuItem.Text = "&Printer Viewer"; + this.GBPrinterViewerMenuItem.Click += new System.EventHandler(this.GBPrinterViewerMenuItem_Click); + // + // GBASubMenu + // + this.GBASubMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.GBACoreSelectionSubMenu, this.GBAcoresettingsToolStripMenuItem1, this.toolStripSeparator33, @@ -4176,6 +4205,7 @@ private System.Windows.Forms.ToolStripMenuItem SaveMovieContextMenuItem; private System.Windows.Forms.ToolStripMenuItem VirtualPadMenuItem; private System.Windows.Forms.ToolStripMenuItem GBGPUViewerMenuItem; + private System.Windows.Forms.ToolStripMenuItem GBPrinterViewerMenuItem; private System.Windows.Forms.ToolStripMenuItem AudioThrottleMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator27; private System.Windows.Forms.ToolStripMenuItem VsyncEnabledMenuItem; @@ -4309,6 +4339,7 @@ private System.Windows.Forms.ToolStripMenuItem quickNESToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem nesHawkToolStripMenuItem; private System.Windows.Forms.ToolStripSeparator toolStripSeparator34; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator35; private System.Windows.Forms.ToolStripMenuItem GBACoreSelectionSubMenu; private System.Windows.Forms.ToolStripMenuItem GBAmGBAMenuItem; private System.Windows.Forms.ToolStripMenuItem GBAVBANextMenuItem; @@ -4358,7 +4389,6 @@ private System.Windows.Forms.ToolStripMenuItem IntvSubMenu; private System.Windows.Forms.ToolStripMenuItem IntVControllerSettingsMenuItem; private System.Windows.Forms.ToolStripMenuItem SNESControllerConfigurationMenuItem; - private System.Windows.Forms.ToolStripSeparator toolStripSeparator35; private System.Windows.Forms.ToolStripMenuItem C64DisksSubMenu; private System.Windows.Forms.ToolStripSeparator toolStripSeparator36; private System.Windows.Forms.ToolStripMenuItem sNESToolStripMenuItem; @@ -4373,13 +4403,16 @@ private System.Windows.Forms.ToolStripMenuItem GbaCoreSubMenu; private System.Windows.Forms.ToolStripMenuItem VbaNextCoreMenuItem; private System.Windows.Forms.ToolStripMenuItem MgbaCoreMenuItem; - private System.Windows.Forms.ToolStripMenuItem Atari7800CoreSubMenu; - private System.Windows.Forms.ToolStripMenuItem Emu7800CoreMenuItem; private System.Windows.Forms.ToolStripMenuItem Atari7800HawkCoreMenuItem; private System.Windows.Forms.ToolStripMenuItem SGBCoreSubmenu; private System.Windows.Forms.ToolStripMenuItem SgbBsnesMenuItem; private System.Windows.Forms.ToolStripMenuItem SgbSameBoyMenuItem; private System.Windows.Forms.ToolStripMenuItem pCFXToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem preferencesToolStripMenuItem3; + private System.Windows.Forms.ToolStripMenuItem SMSControllerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerStandardToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerPaddleToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerLightPhaserToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem SMSControllerSportsPadToolStripMenuItem; } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index b247428b60..fd1d42f241 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -6,7 +6,6 @@ using System.Windows.Forms; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Cores.Atari.A7800Hawk; -using BizHawk.Emulation.Cores.Atari.Atari7800; using BizHawk.Emulation.Cores.Calculators; using BizHawk.Emulation.Cores.ColecoVision; using BizHawk.Emulation.Cores.Nintendo.NES; @@ -226,9 +225,9 @@ namespace BizHawk.Client.EmuHawk } } - private void FlushSaveRAMSubMenu_DropDownOpened(object sender, EventArgs e) + private void SaveRAMSubMenu_DropDownOpened(object sender, EventArgs e) { - FlushSaveRAMMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Flush SRAM"].Bindings; + FlushSaveRAMMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Flush SaveRAM"].Bindings; } private void MovieSubMenu_DropDownOpened(object sender, EventArgs e) @@ -1187,7 +1186,6 @@ namespace BizHawk.Client.EmuHawk private void CoresSubMenu_DropDownOpened(object sender, EventArgs e) { - Atari7800CoreSubMenu.Visible = VersionInfo.DeveloperBuild; GBInSGBMenuItem.Checked = Global.Config.GB_AsSGB; allowGameDBCoreOverridesToolStripMenuItem.Checked = Global.Config.CoreForcingViaGameDB; @@ -1240,21 +1238,6 @@ namespace BizHawk.Client.EmuHawk } } - private void Atari7800CoreSubMenu_DropDownOpened(object sender, EventArgs e) - { - Emu7800CoreMenuItem.Checked = Global.Config.A78_UseEmu7800; - Atari7800HawkCoreMenuItem.Checked = !Global.Config.A78_UseEmu7800; - } - - private void Atari7800CorePick_Click(object sender, EventArgs e) - { - Global.Config.A78_UseEmu7800 ^= true; - if (Emulator.SystemId == "A78") - { - FlagNeedsReboot(); - } - } - private void SGBCoreSubmenu_DropDownOpened(object sender, EventArgs e) { SgbBsnesMenuItem.Checked = Global.Config.SGB_UseBsnes; @@ -1762,6 +1745,10 @@ namespace BizHawk.Client.EmuHawk SMSdisplayNtscToolStripMenuItem.Checked = ss.DisplayType == "NTSC"; SMSdisplayPalToolStripMenuItem.Checked = ss.DisplayType == "PAL"; SMSdisplayAutoToolStripMenuItem.Checked = ss.DisplayType == "Auto"; + SMSControllerStandardToolStripMenuItem.Checked = ss.ControllerType == "Standard"; + SMSControllerPaddleToolStripMenuItem.Checked = ss.ControllerType == "Paddle"; + SMSControllerLightPhaserToolStripMenuItem.Checked = ss.ControllerType == "Light Phaser"; + SMSControllerSportsPadToolStripMenuItem.Checked = ss.ControllerType == "Sports Pad"; SMSenableBIOSToolStripMenuItem.Checked = ss.UseBIOS; SMSEnableFMChipMenuItem.Checked = ss.EnableFM; SMSOverclockMenuItem.Checked = ss.AllowOverlock; @@ -1775,9 +1762,11 @@ namespace BizHawk.Client.EmuHawk SMSEnableFMChipMenuItem.Visible = SMSFix3DGameDisplayToolStripMenuItem.Visible = SMSenableBIOSToolStripMenuItem.Visible = - SMSDisplayOverscanMenuItem.Visible = Global.Game.System == "SMS"; + SMSDisplayOverscanMenuItem.Visible = + Global.Game.System == "SMS" || Global.Game.System == "SG"; + SMSOverclockMenuItem.Visible = SMSForceStereoMenuItem.Visible = SMSdisplayToolStripMenuItem.Visible = @@ -1914,6 +1903,34 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.Load(); } + private void SMSControllerStandardToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Standard"; + PutCoreSyncSettings(s); + } + + private void SMSControllerPaddleToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Paddle"; + PutCoreSyncSettings(s); + } + + private void SMSControllerLightPhaserToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Light Phaser"; + PutCoreSyncSettings(s); + } + + private void SMSControllerSportsPadToolStripMenuItem_Click(object sender, EventArgs e) + { + var s = ((SMS)Emulator).GetSyncSettings(); + s.ControllerType = "Sports Pad"; + PutCoreSyncSettings(s); + } + #endregion #region TI83 @@ -2033,6 +2050,11 @@ namespace BizHawk.Client.EmuHawk GlobalWin.Tools.LoadGameGenieEc(); } + private void GBPrinterViewerMenuItem_Click(object sender, EventArgs e) + { + GlobalWin.Tools.Load(); + } + #endregion #region GBA diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 3e469b7929..170dbb2322 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -34,6 +34,7 @@ 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; +using BizHawk.Emulation.Cores.Atari.A7800Hawk; namespace BizHawk.Client.EmuHawk { @@ -273,7 +274,8 @@ namespace BizHawk.Client.EmuHawk if (argParse.cmdRom != null) { // Commandline should always override auto-load - LoadRom(argParse.cmdRom, new LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom() }); + var ioa = OpenAdvancedSerializer.ParseWithLegacy(argParse.cmdRom); + LoadRom(argParse.cmdRom, new LoadRomArgs { OpenAdvanced = ioa }); if (Global.Game == null) { MessageBox.Show("Failed to load " + argParse.cmdRom + " specified on commandline"); @@ -404,7 +406,7 @@ namespace BizHawk.Client.EmuHawk { PauseEmulator(); } - + // start dumping, if appropriate if (argParse.cmdDumpType != null && argParse.cmdDumpName != null) { @@ -1414,6 +1416,8 @@ namespace BizHawk.Client.EmuHawk public PresentationPanel PresentationPanel { get; } + //countdown for saveram autoflushing + public int AutoFlushSaveRamIn { get; set; } #endregion #region Private methods @@ -1566,6 +1570,16 @@ namespace BizHawk.Client.EmuHawk { try // zero says: this is sort of sketchy... but this is no time for rearchitecting { + if (Global.Config.AutosaveSaveRAM) + { + var saveram = new FileInfo(PathManager.SaveRamPath(Global.Game)); + var autosave = new FileInfo(PathManager.AutoSaveRamPath(Global.Game)); + if (autosave.Exists && autosave.LastWriteTime > saveram.LastWriteTime) + { + GlobalWin.OSD.AddMessage("AutoSaveRAM is newer than last saved SaveRAM"); + } + } + byte[] sram; // GBA meteor core might not know how big the saveram ought to be, so just send it the whole file @@ -1595,47 +1609,66 @@ namespace BizHawk.Client.EmuHawk } Emulator.AsSaveRam().StoreSaveRam(sram); + AutoFlushSaveRamIn = Global.Config.FlushSaveRamFrames; } catch (IOException) { GlobalWin.OSD.AddMessage("An error occurred while loading Sram"); } } - } + } - public void FlushSaveRAM() + public void FlushSaveRAM(bool autosave = false) { if (Emulator.HasSaveRam()) { - var path = PathManager.SaveRamPath(Global.Game); - var f = new FileInfo(path); - if (f.Directory != null && !f.Directory.Exists) + string path; + if (autosave) { - f.Directory.Create(); + path = PathManager.AutoSaveRamPath(Global.Game); + AutoFlushSaveRamIn = Global.Config.FlushSaveRamFrames; + } + else + { + path = PathManager.SaveRamPath(Global.Game); + } + var file = new FileInfo(path); + var newPath = path + ".new"; + var newFile = new FileInfo(newPath); + var backupPath = path + ".bak"; + var backupFile = new FileInfo(backupPath); + if (file.Directory != null && !file.Directory.Exists) + { + file.Directory.Create(); } - // Make backup first - if (Global.Config.BackupSaveram && f.Exists) - { - var backup = path + ".bak"; - var backupFile = new FileInfo(backup); - if (backupFile.Exists) - { - backupFile.Delete(); - } - - f.CopyTo(backup); - } - - var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write)); + var writer = new BinaryWriter(new FileStream(newPath, FileMode.Create, FileAccess.Write)); var saveram = Emulator.AsSaveRam().CloneSaveRam(); if (saveram != null) { writer.Write(saveram, 0, saveram.Length); } - writer.Close(); + + if (file.Exists) + { + if (Global.Config.BackupSaveram) + { + if (backupFile.Exists) + { + backupFile.Delete(); + } + + file.MoveTo(backupPath); + } + else + { + file.Delete(); + } + } + + newFile.MoveTo(path); } } @@ -1725,8 +1758,11 @@ namespace BizHawk.Client.EmuHawk case "A26": AtariSubMenu.Visible = true; break; - case "A7800": - A7800SubMenu.Visible = true; + case "A78": + if (Emulator is A7800Hawk) + { + A7800SubMenu.Visible = true; + } break; case "PSX": PSXSubMenu.Visible = true; @@ -2041,13 +2077,13 @@ namespace BizHawk.Client.EmuHawk if (VersionInfo.DeveloperBuild) { return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;%ARCH%", + "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.pce;*.sgx;*.bin;*.smd;*.rom;*.a26;*.a78;*.lnx;*.m3u;*.cue;*.ccd;*.mds;*.exe;*.gb;*.gbc;*.gba;*.gen;*.md;*.32x;*.col;*.int;*.smc;*.sfc;*.prg;*.d64;*.g64;*.crt;*.tap;*.sgb;*.xml;*.z64;*.v64;*.n64;*.ws;*.wsc;*.dsk;*.do;*.po;*.vb;*.ngp;*.ngc;*.psf;*.minipsf;*.nsf;%ARCH%", "Music Files", "*.psf;*.minipsf;*.sid;*.nsf", - "Disc Images", "*.cue;*.ccd;*.m3u", + "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%", + "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%", "TI-83", "*.rom;%ARCH%", "Archive Files", "%ARCH%", "Savestate", "*.state", @@ -2059,7 +2095,7 @@ namespace BizHawk.Client.EmuHawk "Gameboy Advance", "*.gba;%ARCH%", "Colecovision", "*.col;%ARCH%", "Intellivision", "*.int;*.bin;*.rom;%ARCH%", - "PlayStation", "*.cue;*.ccd;*.m3u", + "PlayStation", "*.cue;*.ccd;*.mds;*.m3u", "PSX Executables (experimental)", "*.exe", "PSF Playstation Sound File", "*.psf;*.minipsf", "Commodore 64", "*.prg; *.d64, *.g64; *.crt; *.tap;%ARCH%", @@ -2073,17 +2109,17 @@ namespace BizHawk.Client.EmuHawk } return FormatFilter( - "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;%ARCH%", - "Disc Images", "*.cue;*.ccd;*.m3u", + "Rom Files", "*.nes;*.fds;*.unf;*.sms;*.gg;*.sg;*.gb;*.gbc;*.gba;*.pce;*.sgx;*.bin;*.smd;*.gen;*.md;*.32x;*.smc;*.sfc;*.a26;*.a78;*.lnx;*.col;*.int;*.rom;*.m3u;*.cue;*.ccd;*.mds;*.sgb;*.z64;*.v64;*.n64;*.ws;*.wsc;*.xml;*.dsk;*.do;*.po;*.psf;*.ngp;*.ngc;*.prg;*.d64;*.g64;*.minipsf;*.nsf;%ARCH%", + "Disc Images", "*.cue;*.ccd;*.mds;*.m3u", "NES", "*.nes;*.fds;*.unf;*.nsf;%ARCH%", "Super NES", "*.smc;*.sfc;*.xml;%ARCH%", - "PlayStation", "*.cue;*.ccd;*.m3u", + "PlayStation", "*.cue;*.ccd;*.mds;*.m3u", "PSF Playstation Sound File", "*.psf;*.minipsf", "Nintendo 64", "*.z64;*.v64;*.n64", "Gameboy", "*.gb;*.gbc;*.sgb;%ARCH%", "Gameboy Advance", "*.gba;%ARCH%", "Master System", "*.sms;*.gg;*.sg;%ARCH%", - "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;%ARCH%", + "PC Engine", "*.pce;*.sgx;*.cue;*.ccd;*.mds;%ARCH%", "Atari 2600", "*.a26;%ARCH%", "Atari 7800", "*.a78;%ARCH%", "Atari Lynx", "*.lnx;%ARCH%", @@ -2902,6 +2938,13 @@ namespace BizHawk.Client.EmuHawk Global.MovieSession.HandleMovieOnFrameLoop(); + if (Global.Config.AutosaveSaveRAM) + { + if (AutoFlushSaveRamIn-- <= 0) + { + FlushSaveRAM(true); + } + } // why not skip audio if the user doesnt want sound bool renderSound = (Global.Config.SoundEnabled && !IsTurboing) || (_currAviWriter?.UsesAudio ?? false); if (!renderSound) @@ -3540,6 +3583,12 @@ namespace BizHawk.Client.EmuHawk } } + if (ioa is OpenAdvanced_OpenRom) + { + var ioa_openrom = (OpenAdvanced_OpenRom)ioa; + path = ioa_openrom.Path; + } + CoreFileProvider.SyncCoreCommInputSignals(nextComm); var result = loader.LoadRom(path, nextComm); @@ -3616,9 +3665,16 @@ namespace BizHawk.Client.EmuHawk JumpLists.AddRecentItem(loaderName, ioa.DisplayName); // Don't load Save Ram if a movie is being loaded - if (!Global.MovieSession.MovieIsQueued && File.Exists(PathManager.SaveRamPath(loader.Game))) + if (!Global.MovieSession.MovieIsQueued) { - LoadSaveRam(); + if (File.Exists(PathManager.SaveRamPath(loader.Game))) + { + LoadSaveRam(); + } + else if (Global.Config.AutosaveSaveRAM && File.Exists(PathManager.AutoSaveRamPath(loader.Game))) + { + GlobalWin.OSD.AddMessage("AutoSaveRAM found, but SaveRAM was not saved"); + } } GlobalWin.Tools.Restart(); diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs index 2214ac2864..72c965441f 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs +++ b/BizHawk.Client.EmuHawk/Properties/Resources.Designer.cs @@ -489,17 +489,7 @@ namespace BizHawk.Client.EmuHawk.Properties { return ((System.Drawing.Bitmap)(obj)); } } - - /// - /// Looks up a localized resource of type System.Drawing.Bitmap. - /// - internal static System.Drawing.Bitmap emu7800 { - get { - object obj = ResourceManager.GetObject("emu7800", resourceCulture); - return ((System.Drawing.Bitmap)(obj)); - } - } - + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/BizHawk.Client.EmuHawk/Properties/Resources.resx b/BizHawk.Client.EmuHawk/Properties/Resources.resx index 086445bff7..8d9fb1b714 100644 --- a/BizHawk.Client.EmuHawk/Properties/Resources.resx +++ b/BizHawk.Client.EmuHawk/Properties/Resources.resx @@ -205,9 +205,6 @@ ..\images\calculator.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\images\emu7800.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\images\tastudio\ts_v_piano_16_green_blue.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -1560,4 +1557,4 @@ ..\images\ControllerImages\NGPController.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - \ No newline at end of file + diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs index 285a747eb2..70e35459eb 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.Designer.cs @@ -48,6 +48,17 @@ this.EnableContextMenuCheckbox = new System.Windows.Forms.CheckBox(); this.PauseWhenMenuActivatedCheckbox = new System.Windows.Forms.CheckBox(); this.tabPage3 = new System.Windows.Forms.TabPage(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.AutosaveSRAMtextBox = new System.Windows.Forms.NumericUpDown(); + this.AutosaveSRAMradioButton1 = new System.Windows.Forms.RadioButton(); + this.label8 = new System.Windows.Forms.Label(); + this.AutosaveSRAMradioButton2 = new System.Windows.Forms.RadioButton(); + this.AutosaveSRAMradioButton3 = new System.Windows.Forms.RadioButton(); + this.AutosaveSRAMCheckbox = new System.Windows.Forms.CheckBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label7 = new System.Windows.Forms.Label(); + this.LuaInterfaceRadio = new System.Windows.Forms.RadioButton(); + this.NLuaRadio = new System.Windows.Forms.RadioButton(); this.label6 = new System.Windows.Forms.Label(); this.cbMoviesInAWE = new System.Windows.Forms.CheckBox(); this.label5 = new System.Windows.Forms.Label(); @@ -56,20 +67,18 @@ this.label12 = new System.Windows.Forms.Label(); this.label13 = new System.Windows.Forms.Label(); this.FrameAdvSkipLagCheckbox = new System.Windows.Forms.CheckBox(); - this.label9 = new System.Windows.Forms.Label(); - this.label10 = new System.Windows.Forms.Label(); this.BackupSRamCheckbox = new System.Windows.Forms.CheckBox(); this.label4 = new System.Windows.Forms.Label(); this.LogWindowAsConsoleCheckbox = new System.Windows.Forms.CheckBox(); this.toolTip1 = new System.Windows.Forms.ToolTip(this.components); - this.panel1 = new System.Windows.Forms.Panel(); - this.NLuaRadio = new System.Windows.Forms.RadioButton(); - this.LuaInterfaceRadio = new System.Windows.Forms.RadioButton(); - this.label7 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); this.groupBox1.SuspendLayout(); this.tabPage3.SuspendLayout(); + this.groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.AutosaveSRAMtextBox)).BeginInit(); this.panel1.SuspendLayout(); this.SuspendLayout(); // @@ -123,7 +132,7 @@ this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(386, 368); + this.tabPage1.Size = new System.Drawing.Size(386, 376); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "General"; this.tabPage1.UseVisualStyleBackColor = true; @@ -270,6 +279,8 @@ // // tabPage3 // + this.tabPage3.Controls.Add(this.groupBox2); + this.tabPage3.Controls.Add(this.AutosaveSRAMCheckbox); this.tabPage3.Controls.Add(this.panel1); this.tabPage3.Controls.Add(this.label6); this.tabPage3.Controls.Add(this.cbMoviesInAWE); @@ -279,8 +290,6 @@ this.tabPage3.Controls.Add(this.label12); this.tabPage3.Controls.Add(this.label13); this.tabPage3.Controls.Add(this.FrameAdvSkipLagCheckbox); - this.tabPage3.Controls.Add(this.label9); - this.tabPage3.Controls.Add(this.label10); this.tabPage3.Controls.Add(this.BackupSRamCheckbox); this.tabPage3.Controls.Add(this.label4); this.tabPage3.Controls.Add(this.LogWindowAsConsoleCheckbox); @@ -291,6 +300,128 @@ this.tabPage3.Text = "Advanced"; this.tabPage3.UseVisualStyleBackColor = true; // + // groupBox2 + // + this.groupBox2.Controls.Add(this.label10); + this.groupBox2.Controls.Add(this.label9); + this.groupBox2.Controls.Add(this.AutosaveSRAMtextBox); + this.groupBox2.Controls.Add(this.AutosaveSRAMradioButton1); + this.groupBox2.Controls.Add(this.label8); + this.groupBox2.Controls.Add(this.AutosaveSRAMradioButton2); + this.groupBox2.Controls.Add(this.AutosaveSRAMradioButton3); + this.groupBox2.Location = new System.Drawing.Point(27, 59); + this.groupBox2.Margin = new System.Windows.Forms.Padding(0); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(265, 60); + this.groupBox2.TabIndex = 27; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "AutoSaveRAM"; + // + // AutosaveSRAMtextBox + // + this.AutosaveSRAMtextBox.Location = new System.Drawing.Point(151, 33); + this.AutosaveSRAMtextBox.Maximum = new decimal(new int[] { + 100000, + 0, + 0, + 0}); + this.AutosaveSRAMtextBox.Name = "AutosaveSRAMtextBox"; + this.AutosaveSRAMtextBox.Size = new System.Drawing.Size(50, 20); + this.AutosaveSRAMtextBox.TabIndex = 27; + // + // AutosaveSRAMradioButton1 + // + this.AutosaveSRAMradioButton1.AutoSize = true; + this.AutosaveSRAMradioButton1.Location = new System.Drawing.Point(48, 33); + this.AutosaveSRAMradioButton1.Name = "AutosaveSRAMradioButton1"; + this.AutosaveSRAMradioButton1.Size = new System.Drawing.Size(36, 17); + this.AutosaveSRAMradioButton1.TabIndex = 22; + this.AutosaveSRAMradioButton1.TabStop = true; + this.AutosaveSRAMradioButton1.Text = "5s"; + this.AutosaveSRAMradioButton1.UseVisualStyleBackColor = true; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(202, 35); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(12, 13); + this.label8.TabIndex = 26; + this.label8.Text = "s"; + // + // AutosaveSRAMradioButton2 + // + this.AutosaveSRAMradioButton2.AutoSize = true; + this.AutosaveSRAMradioButton2.Location = new System.Drawing.Point(90, 34); + this.AutosaveSRAMradioButton2.Name = "AutosaveSRAMradioButton2"; + this.AutosaveSRAMradioButton2.Size = new System.Drawing.Size(39, 17); + this.AutosaveSRAMradioButton2.TabIndex = 23; + this.AutosaveSRAMradioButton2.TabStop = true; + this.AutosaveSRAMradioButton2.Text = "5m"; + this.AutosaveSRAMradioButton2.UseVisualStyleBackColor = true; + // + // AutosaveSRAMradioButton3 + // + this.AutosaveSRAMradioButton3.AutoSize = true; + this.AutosaveSRAMradioButton3.Location = new System.Drawing.Point(131, 35); + this.AutosaveSRAMradioButton3.Name = "AutosaveSRAMradioButton3"; + this.AutosaveSRAMradioButton3.Size = new System.Drawing.Size(14, 13); + this.AutosaveSRAMradioButton3.TabIndex = 24; + this.AutosaveSRAMradioButton3.TabStop = true; + this.AutosaveSRAMradioButton3.UseVisualStyleBackColor = true; + this.AutosaveSRAMradioButton3.CheckedChanged += new System.EventHandler(this.AutosaveSRAMradioButton3_CheckedChanged); + // + // AutosaveSRAMCheckbox + // + this.AutosaveSRAMCheckbox.AutoSize = true; + this.AutosaveSRAMCheckbox.Location = new System.Drawing.Point(6, 62); + this.AutosaveSRAMCheckbox.Name = "AutosaveSRAMCheckbox"; + this.AutosaveSRAMCheckbox.Size = new System.Drawing.Size(15, 14); + this.AutosaveSRAMCheckbox.TabIndex = 21; + this.AutosaveSRAMCheckbox.UseVisualStyleBackColor = true; + this.AutosaveSRAMCheckbox.CheckedChanged += new System.EventHandler(this.AutosaveSRAMCheckbox_CheckedChanged); + // + // panel1 + // + this.panel1.Controls.Add(this.label7); + this.panel1.Controls.Add(this.LuaInterfaceRadio); + this.panel1.Controls.Add(this.NLuaRadio); + this.panel1.Location = new System.Drawing.Point(6, 312); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(377, 61); + this.panel1.TabIndex = 20; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(3, 1); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(50, 13); + this.label7.TabIndex = 2; + this.label7.Text = "Lua Core"; + // + // LuaInterfaceRadio + // + this.LuaInterfaceRadio.AutoSize = true; + this.LuaInterfaceRadio.Location = new System.Drawing.Point(4, 36); + this.LuaInterfaceRadio.Name = "LuaInterfaceRadio"; + this.LuaInterfaceRadio.Size = new System.Drawing.Size(338, 17); + this.LuaInterfaceRadio.TabIndex = 1; + this.LuaInterfaceRadio.TabStop = true; + this.LuaInterfaceRadio.Text = "Lua+LuaInterface - Faster but memory leaks, use at your own risk!"; + this.LuaInterfaceRadio.UseVisualStyleBackColor = true; + // + // NLuaRadio + // + this.NLuaRadio.AutoSize = true; + this.NLuaRadio.Location = new System.Drawing.Point(4, 17); + this.NLuaRadio.Name = "NLuaRadio"; + this.NLuaRadio.Size = new System.Drawing.Size(194, 17); + this.NLuaRadio.TabIndex = 0; + this.NLuaRadio.TabStop = true; + this.NLuaRadio.Text = "NLua+KopiLua - Reliable but slower"; + this.NLuaRadio.UseVisualStyleBackColor = true; + // // label6 // this.label6.AutoSize = true; @@ -335,7 +466,7 @@ // LuaDuringTurboCheckbox // this.LuaDuringTurboCheckbox.AutoSize = true; - this.LuaDuringTurboCheckbox.Location = new System.Drawing.Point(6, 174); + this.LuaDuringTurboCheckbox.Location = new System.Drawing.Point(6, 178); this.LuaDuringTurboCheckbox.Name = "LuaDuringTurboCheckbox"; this.LuaDuringTurboCheckbox.Size = new System.Drawing.Size(166, 17); this.LuaDuringTurboCheckbox.TabIndex = 15; @@ -345,7 +476,7 @@ // label12 // this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(24, 149); + this.label12.Location = new System.Drawing.Point(24, 162); this.label12.Name = "label12"; this.label12.Size = new System.Drawing.Size(231, 13); this.label12.TabIndex = 14; @@ -354,7 +485,7 @@ // label13 // this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(24, 136); + this.label13.Location = new System.Drawing.Point(24, 149); this.label13.Name = "label13"; this.label13.Size = new System.Drawing.Size(268, 13); this.label13.TabIndex = 13; @@ -363,45 +494,27 @@ // FrameAdvSkipLagCheckbox // this.FrameAdvSkipLagCheckbox.AutoSize = true; - this.FrameAdvSkipLagCheckbox.Location = new System.Drawing.Point(6, 116); + this.FrameAdvSkipLagCheckbox.Location = new System.Drawing.Point(6, 129); this.FrameAdvSkipLagCheckbox.Name = "FrameAdvSkipLagCheckbox"; this.FrameAdvSkipLagCheckbox.Size = new System.Drawing.Size(241, 17); this.FrameAdvSkipLagCheckbox.TabIndex = 12; this.FrameAdvSkipLagCheckbox.Text = "Frame advance button skips non-input frames"; this.FrameAdvSkipLagCheckbox.UseVisualStyleBackColor = true; // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(24, 94); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(99, 13); - this.label9.TabIndex = 11; - this.label9.Text = "before overwriting it"; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(24, 81); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(277, 13); - this.label10.TabIndex = 10; - this.label10.Text = "When set, the client will make a backup copy of saveram"; - // // BackupSRamCheckbox // this.BackupSRamCheckbox.AutoSize = true; - this.BackupSRamCheckbox.Location = new System.Drawing.Point(6, 61); + this.BackupSRamCheckbox.Location = new System.Drawing.Point(6, 39); this.BackupSRamCheckbox.Name = "BackupSRamCheckbox"; - this.BackupSRamCheckbox.Size = new System.Drawing.Size(108, 17); + this.BackupSRamCheckbox.Size = new System.Drawing.Size(203, 17); this.BackupSRamCheckbox.TabIndex = 9; - this.BackupSRamCheckbox.Text = "Backup Saveram"; + this.BackupSRamCheckbox.Text = "Backup SaveRAM to .SaveRAM.bak"; this.BackupSRamCheckbox.UseVisualStyleBackColor = true; // // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(24, 37); + this.label4.Location = new System.Drawing.Point(24, 23); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(234, 13); this.label4.TabIndex = 2; @@ -410,53 +523,30 @@ // LogWindowAsConsoleCheckbox // this.LogWindowAsConsoleCheckbox.AutoSize = true; - this.LogWindowAsConsoleCheckbox.Location = new System.Drawing.Point(6, 17); + this.LogWindowAsConsoleCheckbox.Location = new System.Drawing.Point(6, 3); this.LogWindowAsConsoleCheckbox.Name = "LogWindowAsConsoleCheckbox"; this.LogWindowAsConsoleCheckbox.Size = new System.Drawing.Size(233, 17); this.LogWindowAsConsoleCheckbox.TabIndex = 1; this.LogWindowAsConsoleCheckbox.Text = "Create the log window as a console window"; this.LogWindowAsConsoleCheckbox.UseVisualStyleBackColor = true; // - // panel1 + // label9 // - this.panel1.Controls.Add(this.label7); - this.panel1.Controls.Add(this.LuaInterfaceRadio); - this.panel1.Controls.Add(this.NLuaRadio); - this.panel1.Location = new System.Drawing.Point(6, 312); - this.panel1.Name = "panel1"; - this.panel1.Size = new System.Drawing.Size(377, 61); - this.panel1.TabIndex = 20; + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(6, 16); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(225, 13); + this.label9.TabIndex = 28; + this.label9.Text = "Save SaveRAM to .AutoSaveRAM.SaveRAM"; // - // NLuaRadio + // label10 // - this.NLuaRadio.AutoSize = true; - this.NLuaRadio.Location = new System.Drawing.Point(4, 17); - this.NLuaRadio.Name = "NLuaRadio"; - this.NLuaRadio.Size = new System.Drawing.Size(194, 17); - this.NLuaRadio.TabIndex = 0; - this.NLuaRadio.TabStop = true; - this.NLuaRadio.Text = "NLua+KopiLua - Reliable but slower"; - this.NLuaRadio.UseVisualStyleBackColor = true; - // - // LuaInterfaceRadio - // - this.LuaInterfaceRadio.AutoSize = true; - this.LuaInterfaceRadio.Location = new System.Drawing.Point(4, 36); - this.LuaInterfaceRadio.Name = "LuaInterfaceRadio"; - this.LuaInterfaceRadio.Size = new System.Drawing.Size(338, 17); - this.LuaInterfaceRadio.TabIndex = 1; - this.LuaInterfaceRadio.TabStop = true; - this.LuaInterfaceRadio.Text = "Lua+LuaInterface - Faster but memory leaks, use at your own risk!"; - this.LuaInterfaceRadio.UseVisualStyleBackColor = true; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(3, 1); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(50, 13); - this.label7.TabIndex = 2; - this.label7.Text = "Lua Core"; + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(9, 34); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(33, 13); + this.label10.TabIndex = 29; + this.label10.Text = "every"; // // EmuHawkOptions // @@ -480,6 +570,9 @@ this.groupBox1.PerformLayout(); this.tabPage3.ResumeLayout(false); this.tabPage3.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.AutosaveSRAMtextBox)).EndInit(); this.panel1.ResumeLayout(false); this.panel1.PerformLayout(); this.ResumeLayout(false); @@ -508,8 +601,6 @@ private System.Windows.Forms.Label label4; private System.Windows.Forms.ToolTip toolTip1; private System.Windows.Forms.CheckBox BackupSRamCheckbox; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.Label label10; private System.Windows.Forms.CheckBox FrameAdvSkipLagCheckbox; private System.Windows.Forms.Label label12; private System.Windows.Forms.Label label13; @@ -525,5 +616,14 @@ private System.Windows.Forms.Label label7; private System.Windows.Forms.RadioButton LuaInterfaceRadio; private System.Windows.Forms.RadioButton NLuaRadio; + private System.Windows.Forms.CheckBox AutosaveSRAMCheckbox; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.RadioButton AutosaveSRAMradioButton3; + private System.Windows.Forms.RadioButton AutosaveSRAMradioButton2; + private System.Windows.Forms.RadioButton AutosaveSRAMradioButton1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.NumericUpDown AutosaveSRAMtextBox; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label9; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/GuiOptions.cs b/BizHawk.Client.EmuHawk/config/GuiOptions.cs index 12cbf0d4a9..d5106c9d24 100644 --- a/BizHawk.Client.EmuHawk/config/GuiOptions.cs +++ b/BizHawk.Client.EmuHawk/config/GuiOptions.cs @@ -7,6 +7,34 @@ namespace BizHawk.Client.EmuHawk { public partial class EmuHawkOptions : Form { + public int AutosaveSaveRAMSeconds { + get { + if (AutosaveSRAMradioButton1.Checked) + return 5; + if (AutosaveSRAMradioButton2.Checked) + return 5 * 60; + return (int)AutosaveSRAMtextBox.Value; + } + set { + switch (value) + { + case 5: + AutosaveSRAMradioButton1.Checked = true; + AutosaveSRAMtextBox.Enabled = false; + break; + case 5 * 60: + AutosaveSRAMradioButton2.Checked = true; + AutosaveSRAMtextBox.Enabled = false; + break; + default: + AutosaveSRAMradioButton3.Checked = true; + AutosaveSRAMtextBox.Enabled = true; + break; + } + AutosaveSRAMtextBox.Value = value; + } + } + public EmuHawkOptions() { InitializeComponent(); @@ -25,6 +53,9 @@ namespace BizHawk.Client.EmuHawk SingleInstanceModeCheckbox.Checked = Global.Config.SingleInstanceMode; BackupSRamCheckbox.Checked = Global.Config.BackupSaveram; + AutosaveSRAMCheckbox.Checked = Global.Config.AutosaveSaveRAM; + groupBox2.Enabled = AutosaveSRAMCheckbox.Checked; + AutosaveSaveRAMSeconds = Global.Config.FlushSaveRamFrames / 60; FrameAdvSkipLagCheckbox.Checked = Global.Config.SkipLagFrame; LogWindowAsConsoleCheckbox.Checked = Global.Config.WIN32_CONSOLE; LuaDuringTurboCheckbox.Checked = Global.Config.RunLuaDuringTurbo; @@ -56,6 +87,10 @@ namespace BizHawk.Client.EmuHawk Global.Config.SingleInstanceMode = SingleInstanceModeCheckbox.Checked; Global.Config.BackupSaveram = BackupSRamCheckbox.Checked; + Global.Config.AutosaveSaveRAM = AutosaveSRAMCheckbox.Checked; + Global.Config.FlushSaveRamFrames = AutosaveSaveRAMSeconds * 60; + if (GlobalWin.MainForm.AutoFlushSaveRamIn > Global.Config.FlushSaveRamFrames) + GlobalWin.MainForm.AutoFlushSaveRamIn = Global.Config.FlushSaveRamFrames; Global.Config.SkipLagFrame = FrameAdvSkipLagCheckbox.Checked; Global.Config.WIN32_CONSOLE = LogWindowAsConsoleCheckbox.Checked; Global.Config.RunLuaDuringTurbo = LuaDuringTurboCheckbox.Checked; @@ -77,5 +112,15 @@ namespace BizHawk.Client.EmuHawk DialogResult = DialogResult.Cancel; GlobalWin.OSD.AddMessage("Customizing aborted."); } + + private void AutosaveSRAMCheckbox_CheckedChanged(object sender, EventArgs e) + { + groupBox2.Enabled = AutosaveSRAMCheckbox.Checked; + } + + private void AutosaveSRAMradioButton3_CheckedChanged(object sender, EventArgs e) + { + AutosaveSRAMtextBox.Enabled = AutosaveSRAMradioButton3.Checked; + } } } diff --git a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs index 3eeacc6191..22e5372ca6 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.Designer.cs @@ -28,220 +28,87 @@ /// private void InitializeComponent() { - this.OK = new System.Windows.Forms.Button(); - this.Cancel = new System.Windows.Forms.Button(); - this.trackBar1 = new System.Windows.Forms.TrackBar(); - this.trackBar2 = new System.Windows.Forms.TrackBar(); - this.trackBar3 = new System.Windows.Forms.TrackBar(); - this.trackBar4 = new System.Windows.Forms.TrackBar(); - this.trackBar5 = new System.Windows.Forms.TrackBar(); - this.label1 = new System.Windows.Forms.Label(); - this.label2 = new System.Windows.Forms.Label(); - this.label3 = new System.Windows.Forms.Label(); - this.label4 = new System.Windows.Forms.Label(); - this.label5 = new System.Windows.Forms.Label(); - this.label6 = new System.Windows.Forms.Label(); - this.label7 = new System.Windows.Forms.Label(); - this.label8 = new System.Windows.Forms.Label(); - this.label9 = new System.Windows.Forms.Label(); - this.label10 = new System.Windows.Forms.Label(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar2)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar3)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar4)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar5)).BeginInit(); - this.SuspendLayout(); - // - // OK - // - this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.OK.Location = new System.Drawing.Point(41, 262); - this.OK.Name = "OK"; - this.OK.Size = new System.Drawing.Size(75, 23); - this.OK.TabIndex = 0; - this.OK.Text = "&OK"; - this.OK.UseVisualStyleBackColor = true; - this.OK.Click += new System.EventHandler(this.Ok_Click); - // - // Cancel - // - this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.Cancel.Location = new System.Drawing.Point(122, 262); - this.Cancel.Name = "Cancel"; - this.Cancel.Size = new System.Drawing.Size(75, 23); - this.Cancel.TabIndex = 1; - this.Cancel.Text = "&Cancel"; - this.Cancel.UseVisualStyleBackColor = true; - this.Cancel.Click += new System.EventHandler(this.Cancel_Click); - // - // trackBar1 - // - this.trackBar1.Location = new System.Drawing.Point(12, 12); - this.trackBar1.Name = "trackBar1"; - this.trackBar1.Size = new System.Drawing.Size(104, 45); - this.trackBar1.TabIndex = 2; - this.trackBar1.ValueChanged += new System.EventHandler(this.TrackBar1_ValueChanged); - // - // trackBar2 - // - this.trackBar2.Location = new System.Drawing.Point(12, 60); - this.trackBar2.Name = "trackBar2"; - this.trackBar2.Size = new System.Drawing.Size(104, 45); - this.trackBar2.TabIndex = 3; - this.trackBar2.ValueChanged += new System.EventHandler(this.TrackBar2_ValueChanged); - // - // trackBar3 - // - this.trackBar3.Location = new System.Drawing.Point(12, 108); - this.trackBar3.Name = "trackBar3"; - this.trackBar3.Size = new System.Drawing.Size(104, 45); - this.trackBar3.TabIndex = 4; - this.trackBar3.ValueChanged += new System.EventHandler(this.TrackBar3_ValueChanged); - // - // trackBar4 - // - this.trackBar4.Location = new System.Drawing.Point(12, 156); - this.trackBar4.Name = "trackBar4"; - this.trackBar4.Size = new System.Drawing.Size(104, 45); - this.trackBar4.TabIndex = 5; - this.trackBar4.ValueChanged += new System.EventHandler(this.TrackBar4_ValueChanged); - // - // trackBar5 - // - this.trackBar5.Location = new System.Drawing.Point(12, 204); - this.trackBar5.Name = "trackBar5"; - this.trackBar5.Size = new System.Drawing.Size(104, 45); - this.trackBar5.TabIndex = 6; - this.trackBar5.ValueChanged += new System.EventHandler(this.TrackBar5_ValueChanged); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(122, 12); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(50, 13); - this.label1.TabIndex = 7; - this.label1.Text = "Square 1"; - // - // label2 - // - this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(122, 60); - this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(50, 13); - this.label2.TabIndex = 8; - this.label2.Text = "Square 2"; - // - // label3 - // - this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(122, 108); - this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(45, 13); - this.label3.TabIndex = 9; - this.label3.Text = "Triangle"; - // - // label4 - // - this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(122, 156); - this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(34, 13); - this.label4.TabIndex = 10; - this.label4.Text = "Noise"; - // - // label5 - // - this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(122, 204); - this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(31, 13); - this.label5.TabIndex = 11; - this.label5.Text = "DMC"; - // - // label6 - // - this.label6.AutoSize = true; - this.label6.Location = new System.Drawing.Point(122, 25); - this.label6.Name = "label6"; - this.label6.Size = new System.Drawing.Size(13, 13); - this.label6.TabIndex = 12; - this.label6.Text = "0"; - // - // label7 - // - this.label7.AutoSize = true; - this.label7.Location = new System.Drawing.Point(122, 73); - this.label7.Name = "label7"; - this.label7.Size = new System.Drawing.Size(13, 13); - this.label7.TabIndex = 13; - this.label7.Text = "0"; - // - // label8 - // - this.label8.AutoSize = true; - this.label8.Location = new System.Drawing.Point(122, 121); - this.label8.Name = "label8"; - this.label8.Size = new System.Drawing.Size(13, 13); - this.label8.TabIndex = 14; - this.label8.Text = "0"; - // - // label9 - // - this.label9.AutoSize = true; - this.label9.Location = new System.Drawing.Point(122, 169); - this.label9.Name = "label9"; - this.label9.Size = new System.Drawing.Size(13, 13); - this.label9.TabIndex = 15; - this.label9.Text = "0"; - // - // label10 - // - this.label10.AutoSize = true; - this.label10.Location = new System.Drawing.Point(122, 217); - this.label10.Name = "label10"; - this.label10.Size = new System.Drawing.Size(13, 13); - this.label10.TabIndex = 16; - this.label10.Text = "0"; - // - // NESSoundConfig - // - this.AcceptButton = this.OK; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.CancelButton = this.Cancel; - this.ClientSize = new System.Drawing.Size(209, 297); - this.Controls.Add(this.label10); - this.Controls.Add(this.label9); - this.Controls.Add(this.label8); - this.Controls.Add(this.label7); - this.Controls.Add(this.label6); - this.Controls.Add(this.label5); - this.Controls.Add(this.label4); - this.Controls.Add(this.label3); - this.Controls.Add(this.label2); - this.Controls.Add(this.label1); - this.Controls.Add(this.trackBar5); - this.Controls.Add(this.trackBar4); - this.Controls.Add(this.trackBar3); - this.Controls.Add(this.trackBar2); - this.Controls.Add(this.trackBar1); - this.Controls.Add(this.Cancel); - this.Controls.Add(this.OK); - this.MaximizeBox = false; - this.Name = "NESSoundConfig"; - this.ShowIcon = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "NES Sound Channels"; - this.Load += new System.EventHandler(this.NESSoundConfig_Load); - ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar2)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar3)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar4)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.trackBar5)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); + this.OK = new System.Windows.Forms.Button(); + this.Cancel = new System.Windows.Forms.Button(); + this.trackBar1 = new System.Windows.Forms.TrackBar(); + this.label1 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit(); + this.SuspendLayout(); + // + // OK + // + this.OK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OK.Location = new System.Drawing.Point(41, 117); + this.OK.Name = "OK"; + this.OK.Size = new System.Drawing.Size(75, 23); + this.OK.TabIndex = 0; + this.OK.Text = "&OK"; + this.OK.UseVisualStyleBackColor = true; + this.OK.Click += new System.EventHandler(this.Ok_Click); + // + // Cancel + // + this.Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.Cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.Cancel.Location = new System.Drawing.Point(122, 117); + this.Cancel.Name = "Cancel"; + this.Cancel.Size = new System.Drawing.Size(75, 23); + this.Cancel.TabIndex = 1; + this.Cancel.Text = "&Cancel"; + this.Cancel.UseVisualStyleBackColor = true; + this.Cancel.Click += new System.EventHandler(this.Cancel_Click); + // + // trackBar1 + // + this.trackBar1.LargeChange = 1; + this.trackBar1.Location = new System.Drawing.Point(12, 12); + this.trackBar1.Minimum = 1; + this.trackBar1.Name = "trackBar1"; + this.trackBar1.Size = new System.Drawing.Size(104, 45); + this.trackBar1.TabIndex = 2; + this.trackBar1.Value = 1; + this.trackBar1.ValueChanged += new System.EventHandler(this.TrackBar1_ValueChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(122, 12); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(67, 13); + this.label1.TabIndex = 7; + this.label1.Text = "APU Volume"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(122, 25); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(13, 13); + this.label6.TabIndex = 12; + this.label6.Text = "0"; + // + // NESSoundConfig + // + this.AcceptButton = this.OK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.Cancel; + this.ClientSize = new System.Drawing.Size(209, 152); + this.Controls.Add(this.label6); + this.Controls.Add(this.label1); + this.Controls.Add(this.trackBar1); + this.Controls.Add(this.Cancel); + this.Controls.Add(this.OK); + this.MaximizeBox = false; + this.Name = "NESSoundConfig"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "NES Sound Channels"; + this.Load += new System.EventHandler(this.NESSoundConfig_Load); + ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); } @@ -250,19 +117,7 @@ private System.Windows.Forms.Button OK; private System.Windows.Forms.Button Cancel; private System.Windows.Forms.TrackBar trackBar1; - private System.Windows.Forms.TrackBar trackBar2; - private System.Windows.Forms.TrackBar trackBar3; - private System.Windows.Forms.TrackBar trackBar4; - private System.Windows.Forms.TrackBar trackBar5; private System.Windows.Forms.Label label1; - private System.Windows.Forms.Label label2; - private System.Windows.Forms.Label label3; - private System.Windows.Forms.Label label4; - private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label6; - private System.Windows.Forms.Label label7; - private System.Windows.Forms.Label label8; - private System.Windows.Forms.Label label9; - private System.Windows.Forms.Label label10; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs index 725f4ba2c4..ac3a8f198f 100644 --- a/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs +++ b/BizHawk.Client.EmuHawk/config/NES/NESSoundConfig.cs @@ -38,11 +38,7 @@ namespace BizHawk.Client.EmuHawk // get baseline maxes from a default config object var d = new NES.NESSettings(); - trackBar1.Maximum = d.Square1; - trackBar2.Maximum = d.Square2; - trackBar3.Maximum = d.Triangle; - trackBar4.Maximum = d.Noise; - trackBar5.Maximum = d.DMC; + trackBar1.Minimum = d.APU_vol; } private void NESSoundConfig_Load(object sender, EventArgs e) @@ -50,11 +46,7 @@ namespace BizHawk.Client.EmuHawk _oldSettings = NES.GetSettings(); _settings = _oldSettings.Clone(); - trackBar1.Value = _settings.Square1; - trackBar2.Value = _settings.Square2; - trackBar3.Value = _settings.Triangle; - trackBar4.Value = _settings.Noise; - trackBar5.Value = _settings.DMC; + trackBar1.Value = _settings.APU_vol; } private void Ok_Click(object sender, EventArgs e) @@ -72,35 +64,7 @@ namespace BizHawk.Client.EmuHawk private void TrackBar1_ValueChanged(object sender, EventArgs e) { label6.Text = trackBar1.Value.ToString(); - _settings.Square1 = trackBar1.Value; - NES.PutSettings(_settings); - } - - private void TrackBar2_ValueChanged(object sender, EventArgs e) - { - label7.Text = trackBar2.Value.ToString(); - _settings.Square2 = trackBar2.Value; - NES.PutSettings(_settings); - } - - private void TrackBar3_ValueChanged(object sender, EventArgs e) - { - label8.Text = trackBar3.Value.ToString(); - _settings.Triangle = trackBar3.Value; - NES.PutSettings(_settings); - } - - private void TrackBar4_ValueChanged(object sender, EventArgs e) - { - label9.Text = trackBar4.Value.ToString(); - _settings.Noise = trackBar4.Value; - NES.PutSettings(_settings); - } - - private void TrackBar5_ValueChanged(object sender, EventArgs e) - { - label10.Text = trackBar5.Value.ToString(); - _settings.DMC = trackBar5.Value; + _settings.APU_vol = trackBar1.Value; NES.PutSettings(_settings); } } diff --git a/BizHawk.Client.EmuHawk/images/emu7800.png b/BizHawk.Client.EmuHawk/images/emu7800.png deleted file mode 100644 index ec37d9fa26..0000000000 Binary files a/BizHawk.Client.EmuHawk/images/emu7800.png and /dev/null differ diff --git a/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.Designer.cs b/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.Designer.cs new file mode 100644 index 0000000000..f285047c54 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.Designer.cs @@ -0,0 +1,148 @@ +namespace BizHawk.Client.EmuHawk +{ + partial class GBPrinterView + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GBPrinterView)); + this.paperView = new BmpView(); + this.label1 = new System.Windows.Forms.Label(); + this.paperScroll = new System.Windows.Forms.VScrollBar(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.saveImageToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.copyToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.menuStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.editToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(336, 24); + this.menuStrip1.TabIndex = 2; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.saveImageToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "&File"; + // + // saveImageToolStripMenuItem + // + this.saveImageToolStripMenuItem.Name = "saveImageToolStripMenuItem"; + this.saveImageToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); + this.saveImageToolStripMenuItem.Size = new System.Drawing.Size(183, 22); + this.saveImageToolStripMenuItem.Text = "&Save Image..."; + this.saveImageToolStripMenuItem.Click += new System.EventHandler(this.saveImageToolStripMenuItem_Click); + // + // editToolStripMenuItem + // + this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.copyToolStripMenuItem}); + this.editToolStripMenuItem.Name = "editToolStripMenuItem"; + this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20); + this.editToolStripMenuItem.Text = "&Edit"; + // + // copyToolStripMenuItem + // + this.copyToolStripMenuItem.Name = "copyToolStripMenuItem"; + this.copyToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); + this.copyToolStripMenuItem.Size = new System.Drawing.Size(152, 22); + this.copyToolStripMenuItem.Text = "&Copy"; + this.copyToolStripMenuItem.Click += new System.EventHandler(this.copyToolStripMenuItem_Click); + // + // paperView + // + this.paperView.Name = "paperView"; + this.paperView.Location = new System.Drawing.Point(0, 48); + this.paperView.Size = new System.Drawing.Size(320, 320); + this.paperView.BackColor = System.Drawing.Color.Black; + this.paperView.TabIndex = 0; + // + // label1 + // + this.label1.Name = "label1"; + this.label1.Location = new System.Drawing.Point(0, 24); + this.label1.Size = new System.Drawing.Size(336, 24); + this.label1.Text = "Note: the printer is only connected while this window is open."; + this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // paperScroll + // + this.paperScroll.Name = "paperScroll"; + this.paperScroll.Location = new System.Drawing.Point(320, 48); + this.paperScroll.Size = new System.Drawing.Size(16, 320); + this.paperScroll.Minimum = 0; + this.paperScroll.SmallChange = 8; + this.paperScroll.LargeChange = 160; + this.paperScroll.ValueChanged += PaperScroll_ValueChanged; + // + // GBPrinterView + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(336, 358); + this.Controls.Add(this.menuStrip1); + this.Controls.Add(this.paperView); + this.Controls.Add(this.label1); + this.Controls.Add(this.paperScroll); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip1; + this.MaximizeBox = false; + this.Name = "GBPrinterView"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Printer Viewer"; + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.FormClosed += GBPrinterView_FormClosed; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem saveImageToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem copyToolStripMenuItem; + private BmpView paperView; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.VScrollBar paperScroll; + } +} \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.cs b/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.cs new file mode 100644 index 0000000000..549df688ea --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.cs @@ -0,0 +1,215 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.Text; +using System.Windows.Forms; + +using BizHawk.Common.NumberExtensions; +using BizHawk.Client.Common; +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 GBPrinterView : Form, IToolFormAutoConfig + { + const int PaperWidth = 160; + + // the bg color + private static readonly uint PaperColor = (uint)Color.AntiqueWhite.ToArgb(); + + private ColorMatrix PaperAdjustment; + + [RequiredService] + public IGameboyCommon Gb { get; private set; } + + // If we've connected the printer yet + bool connected = false; + + // the entire bitmap + Bitmap printerHistory; + + public GBPrinterView() + { + InitializeComponent(); + + // adjust the color of the printed output to be more papery + PaperAdjustment = new ColorMatrix(); + PaperAdjustment.Matrix00 = (0xFA - 0x10) / 255F; + PaperAdjustment.Matrix40 = 0x10 / 255F; + PaperAdjustment.Matrix11 = (0xEB - 0x10) / 255F; + PaperAdjustment.Matrix41 = 0x10 / 255F; + PaperAdjustment.Matrix22 = (0xD7 - 0x18) / 255F; + PaperAdjustment.Matrix42 = 0x18 / 255F; + + paperView.ChangeBitmapSize(PaperWidth, PaperWidth); + + ClearPaper(); + } + + private void GBPrinterView_FormClosed(object sender, FormClosedEventArgs e) + { + if (Gb != null) + { + Gb.SetPrinterCallback(null); + } + } + + public bool UpdateBefore => false; + + public bool AskSaveChanges() => true; + + public void FastUpdate() + { + } + + public void NewUpdate(ToolFormUpdateType type) + { + } + + public void Restart() + { + // Really, there's not necessarilly a reason to clear it at all, + // since the paper would still be there, + // but it just seems right to get a blank slate on reset. + ClearPaper(); + + connected = false; + } + + public void UpdateValues() + { + // Automatically connect once the game is running + if (!connected) + { + Gb.SetPrinterCallback(OnPrint); + connected = true; + } + } + + /// + /// The printer callback that . See PrinterCallback for details. + /// + void OnPrint(IntPtr image, byte height, byte topMargin, byte bottomMargin, byte exposure) + { + // In this implementation: + // the bottom margin and top margin are just white lines at the top and bottom + // exposure is ignored + + // The page received image + Bitmap page = new Bitmap(PaperWidth, height); + + var bmp = page.LockBits(new Rectangle(0, 0, PaperWidth, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < PaperWidth; x++) + { + uint pixel; + unsafe + { + // Pixel of the image; it's just sent from the core as a big bitmap that's 160xheight + pixel = *(uint*)(image + (x + y * PaperWidth) * sizeof(uint)); + } + + SetPixel(bmp, x, y, pixel); + } + } + + page.UnlockBits(bmp); + + // add it to the bottom of the history + int oldHeight = printerHistory.Height; + ResizeHistory(printerHistory.Height + page.Height + topMargin + bottomMargin); + using (var g = Graphics.FromImage(printerHistory)) + { + // Make it brown + ImageAttributes a = new ImageAttributes(); + a.SetColorMatrix(PaperAdjustment); + + g.DrawImage(page, new Rectangle(0, oldHeight + topMargin, page.Width, page.Height), 0F, 0F, page.Width, page.Height, GraphicsUnit.Pixel, a); + g.Flush(); + } + RefreshView(); + } + + /// + /// Set a 2x pixel + /// + /// The bitmap data to draw to + /// X position + /// Y position + /// The ARGB color to set that pixel to + unsafe void SetPixel(BitmapData bmp, int x, int y, uint c) + { + uint* pixel = (uint*)(bmp.Scan0 + x * 4 + y * bmp.Stride); + *pixel = c; + } + + void ClearPaper() + { + ResizeHistory(8); + RefreshView(); + } + + void ResizeHistory(int height) + { + // copy to a new image of height + var newHistory = new Bitmap(PaperWidth, height); + using (var g = Graphics.FromImage(newHistory)) + { + g.Clear(Color.FromArgb((int)PaperColor)); + if (printerHistory != null) + g.DrawImage(printerHistory, Point.Empty); + g.Flush(); + } + + if (printerHistory != null) + printerHistory.Dispose(); + printerHistory = newHistory; + + // Update scrollbar, viewport is a square + paperScroll.Maximum = Math.Max(0, height); + } + + void RefreshView() + { + using (Graphics g = Graphics.FromImage(paperView.BMP)) + { + g.Clear(Color.FromArgb((int)PaperColor)); + g.DrawImage(printerHistory, new Point(0, -paperScroll.Value)); + g.Flush(); + } + + paperView.Refresh(); + } + + private void saveImageToolStripMenuItem_Click(object sender, EventArgs e) + { + // slight hack to use the nice SaveFile() feature of a BmpView + + BmpView toSave = new BmpView(); + toSave.ChangeBitmapSize(printerHistory.Size); + using (var g = Graphics.FromImage(toSave.BMP)) + { + g.DrawImage(printerHistory, Point.Empty); + g.Flush(); + } + toSave.SaveFile(); + } + + private void copyToolStripMenuItem_Click(object sender, EventArgs e) + { + Clipboard.SetImage(printerHistory); + } + + private void PaperScroll_ValueChanged(object sender, System.EventArgs e) + { + RefreshView(); + } + } +} diff --git a/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.resx b/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.resx new file mode 100644 index 0000000000..5be3d7bf98 --- /dev/null +++ b/BizHawk.Client.EmuHawk/tools/GB/GBPrinterView.resx @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAAQAICAAAAEAIACoEAAARgAAACAgAAABAAgAqAgAAO4QAAAQEAAAAQAgAGgEAACWGQAAEBAAAAEA + CABoBQAA/h0AACgAAAAgAAAAQAAAAAEAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAB7e3tAfHx8v3d3d/9tbW3/aWlp/2lpaf9paWn/aWlp/2lpaf9paWn/aWlp/2lpaf9paWn/aWlp/2lp + af9paWn/aWlp/2lpaf9oaGj/ZmZm/3BwcP+EhIT/jo6Ov4+Pj0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAHt7e0B6enq/fX19/4GBgf+Dg4P/g4OD/4ODg/+Dg4P/g4OD/4KCgv+BgYH/fn5+/3x8 + fP98fHz/fn5+/4GBgf+CgoL/goKC/3x8fP9ycnL/dXV1/4WFhf+MjIzPiIiIcISEhDB/f38QAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAd3d3QHl5eb+JiYn/qKio/7i4uP+3t7f/t7e3/7e3t/+3t7f/tra2/7Gx + sf+oqKj/o6Oj/6SkpP+pqan/s7Oz/7a2tv+0tLT/paWl/4iIiP9+fn7/h4eH/4mJie+FhYXPgoKCj4SE + hDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3d3dAeHh4v4+Pj/+7u7v/0dHR/8/Pz//Pz8//0NDQ/9HR + 0f/Q0ND/ycnJ/729vf+3t7f/uLi4/729vv/IyMr/zs7P/83Nzv+9vb3/np6e/46Ojv+NjY3/ioqK/4KC + gv9+fn6/f39/QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHd3d0B4eHi/jo6O/7q6uv/Ozs7/ysrK/8rK + yv/Ozs7/0NDQ/9DQ0P/Kysr/vb29/7e3t/+3t7f/urq8/8LCx//IyM3/zMzO/8TExf+ysrL/o6Oj/5iY + mP+MjIz/fn5+/3Z2dr93d3dAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd3d3QHZ2dr+JiYn/ra2t/7e3 + t/+lpaX/p6en/7y8vP/Jycn/zs7O/8zMzP/Dw8L/urq9/7Kyu/+oqLz/nZ3C/6Cgxf+xscf/ubnD/7i4 + vP+vr7D/oKCh/5OTlP+JiYr/hYWFz4aGhnCKioowj4+PEAAAAAAAAAAAAAAAAAAAAAB3d3dAdXV1v4CA + gP+VlZX/ioqK/2BgYP9mZmb/mpqa/7u7u//Jycn/z8/O/8zMzP/AwMj/qqrE/4iIv/9ZWbn/Vla3/39/ + uP+cnLn/rq66/7GxtP+kpKf/n5+i/6Skpf+hoaHvkpKSz4uLi4+KioowAAAAAAAAAAAAAAAAAAAAAHNz + c0B0dHS/dHR0/3R0dP9gYGD/NjY2/zs7O/9wcHD/m5ub/7y8vP/Ozs7/0NDQ/8PDzv+mpsn/eHjD/zg4 + u/8xMbf/ZGS1/4SEtf+Rkbf/lJS1/4yMrf+UlK7/ra22/62trv+Wlpb/ioqKv4uLi0AAAAAAAAAAAAAA + AAAAAAAAb29vQHBwcL9jY2P/S0tL/zY2Nv8mJib/KCgo/zw8PP9nZ2f/qKio/8rKyv/Pz87/wsLO/6am + yv94eMj/ODjJ/zAwxf9hYb7/cXG4/19fsv9YWLH/WVmz/3Jyt/+jo73/sLCy/5eXmP+Kioq/i4uLQAAA + AAAAAAAAAAAAAAAAAABvb29AcHBwv2VlZf9QUFD/PDw8/ygoKP8pKSn/Pz8//2pqav+pqan/ysrK/87O + zv/Gxs//sLDM/42NzP9cXND/VFTN/3d3w/90dLv/S0u0/zo6tf9AQL3/YWHC/5+fwv+xsbX/l5eZ/4qK + ir+Li4tAAAAAAAAAAAAAAAAAAAAAAHNzc0B1dXW/enp6/4WFhf9wcHD/PDw8/z8/P/94eHj/o6Oj/7+/ + v//Ozs7/0NDQ/83N0P/Gxs//uLjP/6Sk0f+ens3/paXD/42Nvv9VVb3/OzvB/0BAzP9hYc7/n5/H/7Gx + tf+Xl5n/ioqKv4uLi0AAAAAAAAAAAAAAAAAAAAAAd3d3QHh4eL+Hh4f/pqam/5ubm/9nZ2f/ampq/6Oj + o//ExMT/zMzM/9DQ0P/Q0ND/0dHR/9HR0f/OztH/ysrS/8bGzv/Cwsf/p6fE/3Z2xf9fX8r/YmLT/3t7 + 0/+oqMj/srK1/5iYmf+Kioq/i4uLQAAAAAAAAAAAAAAAAAAAAAB3d3dAeHh4v4yMjP+0tLT/vb29/6io + qP+pqan/v7+//8zMzP/Pz8//0NDQ/9DQ0P/R0dH/0dHR/9DQ0f/OztH/zc3Q/8zMzf/Bwcz/r6/N/6am + z/+oqNP/r6/Q/7u7x/+0tLX/mJiZ/4qKir+Li4tAAAAAAAAAAAAAAAAAAAAAAHd3d0B4eHi/jo6O/7q6 + uv/Nzc3/yMjI/8fHx//Ly8v/zc3N/87Ozv/Ozs7/zs7O/87Ozv/Ozs7/zs7O/87Ozv/Ozs7/zs7O/8zM + zv/Kys7/ycnP/8nJz//IyMz/xMTG/7W1tf+ZmZn/ioqKv4uLi0AAAAAAAAAAAAAAAAAAAAAAd3d3QHh4 + eL+Ojo7/uLi4/8zMzP/IyMj/xsbG/8fHx//IyMj/yMjI/8jIyP/IyMj/yMjI/8jIyP/IyMj/yMjI/8jI + yP/IyMj/yMjI/8fHyP/Hx8n/x8fJ/8bGyP/ExMT/tbW1/5mZmf+Kioq/i4uLQAAAAAAAAAAAAAAAAAAA + AAB3d3dAdnZ2v4aGhv+jo6P/r6+v/6qqqv+nqKj/pqio/6WpqP+lqaj/pamo/6WpqP+lqaj/pamo/6Wp + qP+lqaj/pamo/6WpqP+mqaj/pqio/6eoqP+oqKj/rKys/7Kysv+rq6v/lZWV/4qKir+Li4tAAAAAAAAA + AAAAAAAAAAAAAHNzc0B0dHS/dnZ2/3t7e/94eXn/b3Bw/2lsbP9nbm3/ZW9t/2Vvbf9lb23/ZW9t/2Vv + bf9lb23/ZW9t/2Vvbf9lb23/ZW9t/2Zvbf9obmz/am1s/2xtbP94eHj/j4+P/5eXl/+Pj4//ioqKv4uL + i0AAAAAAAAAAAAAAAAAAAAAAb29vQHFxcb9sbGz/Y2Nj/11eXv9bXV3/UWNf/0FtY/84c2b/NnNm/zZz + Zv82c2b/NnNm/zZzZv82c2b/NnNm/zZzZv82c2b/O3Bl/0RrYv9OZV//Vl5c/2VkZf95eHn/hYWF/4mJ + if+Kioq/i4uLQAAAAAAAAAAAAAAAAAAAAABra2tAbW1tv2dnZ/9bW1v/XV9e/2xzcf9eioD/NKWM/x2z + kv8atJP/GLWT/xi1k/8YtZP/GLWT/xi1k/8YtZP/GLWT/xi1k/8krZD/PZ6J/1OOgf9oe3f/cXBx/25u + bv90dHT/hISE/4qKir+Li4tAAAAAAAAAAAAAAAAAAAAAAGtra0BsbGy/ZWVl/1dXV/9cX1//dH17/2Se + kf8swaD/DdSp/wnWqv8H16r/B9eq/wfXqv8H16r/B9eq/wfXqv8H16r/B9eq/xfNpv83uZ3/VaOS/3GK + hf93d3f/aWlp/2xsbP+BgYH/jIyMv4uLi0AAAAAAAAAAAAAAAAAAAAAAa2trQGxsbL9lZWX/V1dX/1xf + Xv90fXv/Y5+R/yjDof8J1qr/BNir/wLZq/8C2av/Atmr/wLZq/8C2av/Atmr/wLZq/8C2av/E8+m/zS6 + nf9To5L/cIqE/3d3d/9paWn/bGxs/4GBgf+MjIy/i4uLQAAAAAAAAAAAAAAAAAAAAABra2tAbGxsv2Vl + Zf9XV1f/XF9e/3R9e/9in5L/JsOi/wbXqv8C2av/ANus/wDbrP8A26z/ANus/wDbrP8A26z/ANus/wDb + rP8R0Kf/M7ud/1Kkkv9wioT/d3d3/2lpaf9sbGz/gYGB/4yMjL+Li4tAAAAAAAAAAAAAAAAAAAAAAGtr + a0BsbGy/ZWVl/1dXV/9cX17/dH17/2Kfkv8mw6L/Bteq/wLZq/8A26z/ANus/wDbrP8A26z/ANus/wDb + rP8A26z/ANus/xHQp/8zu53/UqSS/3CKhP93d3f/aWlp/2xsbP+BgYH/jIyMv4uLi0AAAAAAAAAAAAAA + AAAAAAAAa2trQGxsbL9lZWX/V1dX/1xfXv90fXv/Yp+S/ybDov8G16r/Atmr/wDbrP8A26z/ANus/wDb + rP8A26z/ANus/wDbrP8A26z/EdCn/zO7nf9SpJL/cIqE/3d3d/9paWn/bGxs/4GBgf+MjIy/i4uLQAAA + AAAAAAAAAAAAAAAAAABra2tAbGxsv2VlZf9XV1f/XF9e/3R9e/9in5L/JsOi/wbXqv8C2av/ANus/wDb + rP8A26z/ANus/wDbrP8A26z/ANus/wDbrP8R0Kf/M7ud/1Kkkv9wioT/d3d3/2lpaf9sbGz/gYGB/4yM + jL+Li4tAAAAAAAAAAAAAAAAAAAAAAGtra0BsbGy/ZWVl/1dXV/9cX17/dH17/2Ofkf8ow6H/Cdaq/wTY + q/8C2qv/Atqr/wLaq/8C2qv/Atqr/wLaq/8C2qv/Atqr/xPPpv80up3/U6OS/3CKhP93d3f/aWlp/2xs + bP+BgYH/jIyMv4uLi0AAAAAAAAAAAAAAAAAAAAAAa2trQGxsbL9lZWX/V1dX/1xfX/90fXv/ZJ6R/yzB + oP8N1Kn/Cdaq/wfYqv8H2Kr/B9iq/wfYqv8H2Kr/B9iq/wfYqv8H2Kr/F82m/ze5nf9Vo5L/cYqE/3d3 + d/9paWn/bGxs/4GBgf+MjIy/i4uLQAAAAAAAAAAAAAAAAAAAAABra2tAbW1tv2dnZ/9bW1v/XWBf/210 + cv9fi4H/NaaN/x60k/8btpT/GbeU/xm3lP8Zt5T/GbeU/xm3lP8Zt5T/GbeU/xm3lP8lr5H/Pp+K/1SP + gv9pfHj/cnFx/25ubv90dHT/hISE/4qKir+Li4tAAAAAAAAAAAAAAAAAAAAAAG9vb0BxcXG/bGxs/2Rk + ZP9fYGD/XWBg/1RmYv9EcGb/O3Zp/zl2af85d2n/OXdp/zl3af85d2n/OXdp/zl3af85d2n/OXdp/z5z + aP9HbWX/UWdi/1lhX/9nZ2f/enp6/4WFhf+JiYn/ioqKv4uLi0AAAAAAAAAAAAAAAAAAAAAAc3NzQHV1 + db9xcXH/aGho/2BgYP9XWFj/UVRU/09WVf9NV1X/TVdV/01XVf9NV1X/TVdV/01XVf9NV1X/TVdV/01X + Vf9NV1X/TldV/1BWVP9SVVT/VFVU/2FhYf95eXn/hoaG74iIiM+Li4uPioqKMAAAAAAAAAAAAAAAAAAA + AAB3d3dAeXl5v3R0dP9oaGj/YGBg/1paWv9XWFj/VlhY/1VZWP9VWVj/VVlY/1VZWP9VWVj/VVlY/1VZ + WP9VWVj/VVlY/1VZWP9WWVj/VlhY/1dYWP9YWFj/X19f/2xsbP91dXXPfX19cIqKijCPj48QAAAAAAAA + AAAAAAAAAAAAAHt7e0B8fHy/dXV1/2hoaP9gYGD/XFxc/1paWv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1pa + Wv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1paWv9eXl7/ZmZm/2lpab9ra2tAAAAAAAAA + AAAAAAAA8AAAP/AAAD/wAAAP8AAAD/AAAA/wAAAP8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA + AAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA + AAPwAAAD8AAAD/AAAA8oAAAAIAAAAEAAAAABAAgAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA/zMz + M/82Njb/ODg4/z57bv87fW//OH9v/zd/cP9DQ0P/SEhI/01NTf9MX1v/T15b/1FRUf9XV1f/VFlY/1dY + WP9TXFr/UF5b/1RcWv9YWln/Wlpa/1ldXP9aXFz/XFxc/11eXv9KYVz/TGBc/11lY/9UbWf/XWhm/1Jt + aP9HdWv/RnZs/1dzbf9Zcm3/THpw/0t8cf9gYGD/YGJi/2JiYv9hZGP/YWVk/2FmZP9kZGT/ZmZm/2Nq + af9ibmv/aGho/2pqav9pbGv/bGxs/25ubv9jcm//ZHNv/29xcf9tcnH/bnNy/2R6dv9ofHf/aHx4/2h/ + ev9sf3v/b357/3BwcP9ycnL/cXd2/3R0dP92dnb/cnl3/3N8ev90fHr/eHh4/3p6ev95fHv/en18/3x8 + fP9+fn7/NoBw/zuFdf88hHT/Q4Bz/0CCdP9Whnz/Uol9/2qAfP9sgHz/Skq5/0tLvP9PT77/UVG//1pa + uP9jY7T/Z2e1/2pqtv9mZrn/YWG+/2Rkv/9vb7n/bW28/3FxvP99fbj/SkrD/05Owv9RUcf/UlLI/25u + wf9pacr/dXXD/3l5xP9wcMr/cXHO/3p6yf87m4b/PpiE/zych/8crY7/HqyN/x2vj/8ero//K6SK/yym + i/8mqIv/IKuN/yepjP8hrY7/OLKX/zS2mf84spj/M7ud/zW6nf8wvp//Lr+g/1Sdjf9Ymov/WJqM/1if + kP9piIL/aoiB/2qMhf9To5H/V6CQ/1Kkkv8ewp//D8yj/wvOpP8OzaT/DM6k/w7OpP8Yx6H/EM2j/xbN + pv8Wzqb/Gcyl/wbXqv8P0qj/CNaq/wPZq/8E2Kv/Btiq/wDarP8R0aj/gICA/4KCgv+DhIT/hISE/4aG + hv+IiIj/ioqK/4yMjP+Ojo7/j4+Q/5CQkP+SkpL/lJSU/5aWl/+YmJj/mpqa/5ubnf+cnJ3/np6i/5yc + pP+Tk6//n5+p/4qKsf+Kirf/gYG5/5WVv/+amrr/nqKh/6Ghof+jpKT/pKSk/6ampv+lpan/pqau/6mp + qf+rq67/ra2t/6KisP+lpbL/qamz/66usv+mprn/pKS+/7CwsP+1tbX/srK4/7e3uv+xsb7/t7e+/7i4 + uP+9vb7/hobA/4ODxv+KisD/h4fP/5aWw/+amsH/nJzD/5iYxv+QkM3/mprM/6Kixf+oqMT/o6PJ/6Wl + y/+goM7/qqrN/7KywP+zs8X/u7vA/76+wf+6usX/vb3H/7e3yf+wsM3/u7vL/7+/yv++vs3/oKDQ/7Gx + 0P+/wMD/wMHB/8TExf/Bwcr/wMDN/8bGzf/Jycn/y8vN/83Nzf/BwdD/ycnQ/83N0P/Q0ND/AAAA/wBM + TExJSURDQ0NDQ0FBQUFBOUFCQ0A0RKOoqaelo6QAAExMTE2ipqmpqaqqqaimpKWnqKmno0lJo6enpqOl + pQAASUlJoqq+xs3Nzc3NxMC+vb/FxsazqqWnqKalo6KiAABISEmirs30+Pj4+PTz087O0PL0886+r6qo + paJNTaOoAEhISKOvzfP09Pj6/vjy09DS6e716M2+r6qmoqKlp6kASEhITaq/xL7BzvT6+PTn0cza2+DR + z8W/r6qpqKipqABERERJpKmlQ0SvzfT5+Org12Nj1bzLyLW1tLOvq6ipAENDQ0NBNBkJCjOvzvj97+Ft + Wlhfurm5uLbHwbCsqagAQEBBNDAQCAEDDUnB9Pn24nBpZmBkXlxdZbzIsqyoqQBBQUE0MBgJAgMNS8T0 + +fvs3W9rbGNbV1pq2ce0rKmoAEREQ0RJSDANDUOx0/j+/fvx8N7c1WBnaW7ZybOsqakARERITaiwq0lM + s9P4+v7+/fz77+vf1m5v2N/Js6yoqABISEmircTNwcHT+Pr+/v7+/vr59+7k4/Dk5sqzrKmpAEhISKKu + zfPz8/T5+P36+vr6/vr59/f1+/bozb6tqKgASEhJoq7G1PPy8vP08/Pz8/Pz8/Py8+ry6NTNs6ypqQBI + SERMp7G/v769vb29vb29vb29vb29vr7BxMCwqqioAENDRERMTaJKRz9VVVVVVVVVPVU+Pz9GSqSsrqyq + qakAQEBAQDMxLS4jJVJQUE9PT09PT1BRJCMvN0mlqKioqAA0NDQzLSYqNVNzfHV2dHZ0dnR2fXhyVDo4 + QUmjqKmpADMzMzEsGSo7h3+VlJSbk5uTm5OUj4CFiUJAQU2nqakAMzMzMSwZKz6Ig6GfnZ2dnZ2dnZyZ + go6LRTRBTaepqQAzMzMwKBcrPY2Em5+goKCgoKCgn5iBjotFNEBNp6mpADMzMzEsGSs9jYSbnaCgoKCg + oKCemIGOi0U0QU2nqakAMzMzMCgYKz2NhJudnaCgoKCgoJ+YgY6LRTRATaepqQAzMzMxLBkrPYiDm52g + oKCgoKCgnpiBjotFNEFNp6mpADMzMzAoGCtViIShn52dnZ2dnZ2cmYKMi0U0QE2nqakAMzMzMSwZKzyH + f5WUk5GRkZGRkZaPgIWJRTRDoqepqQA0NDQzLScqNlNzfHV3dnZ2dnZ2fXlyVDs5QUijp6ipAEFBQUAz + LCccHSEFB05OTk5OTk4GBCAfHjJEoqaoqakAQ0NDQTQwJhcTDBsaGhoaGhoaGhoLDBMWLEOipqioqABJ + SUlIQTEoFRQQDw8PDw8PDw8PDw8QEBUoNEiipqmpAElJSUhBMCYYFBQUFBQUFBQUFBQUFBQUFSYtM0FM + p6jwAAA/8AAAP/AAAA/wAAAP8AAAD/AAAA/wAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA + AAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AA + AAPwAAAP8AAADygAAAAQAAAAIAAAAAEAIAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHx8 + fP9paWn/aWlp/2lpaf9paWn/aWlp/2lpaf9paWn/aWlp/2ZmZv+Pj4//AAAAAAAAAAAAAAAAAAAAAAAA + AAB5eXn/09PT/9LS0v/S0tL/z8/P/7e3t/+5ubn/0tLS/83Nzf+BgYH/i4uL/4ODg/8AAAAAAAAAAAAA + AAAAAAAAeHh4/9DQ0P/Gxsb/0NDQ/9HR0f+4uLj/tra2/8PDzP/Ozs//t7e3/5aWlv90dHT/AAAAAAAA + AAAAAAAAAAAAAHZ2dv+QkJD/IyMj/6ysrP/Q0ND/0tLR/5iYx/8YGK//gICy/7i4vf+goKX/uLi4/4uL + i/8AAAAAAAAAAAAAAABubm7/JCQk/xwcHP8lJSX/xsbG/9HR0f+YmMn/GBjS/3h4vv83N6z/Q0O6/76+ + w/+Li4v/AAAAAAAAAAAAAAAAeHh4/62trf8lJSX/u7u7/9DQ0P/R0dH/0dHR/8bG0/+6ur//OjrC/0JC + 2v++vsT/i4uL/wAAAAAAAAAAAAAAAHh4eP/R0dH/xsbG/9DQ0P/R0dH/0dHR/9HR0f/R0dH/0dHR/8rK + 0v/Ly9P/w8PD/4uLi/8AAAAAAAAAAAAAAAB5eXn/zc3N/8bGxv/Gxsb/xsbG/8bGxv/Gxsb/xsbG/8bG + xv/Gxsb/x8fH/8PDw/+Li4v/AAAAAAAAAAAAAAAAc3Nz/2NjY/9NTk7/RlNQ/0VTUP9FU1D/RVNQ/0VT + UP9FU1D/SlFP/09PT/+Ojo7/i4uL/wAAAAAAAAAAAAAAAGxsbP9RUVH/gY2K/xLSqP8K1qr/Ctaq/wrW + qv8K1qr/Ctaq/0mvmf9/fn//YmJi/4yMjP8AAAAAAAAAAAAAAABsbGz/UFBQ/4CNiv8J1qr/ANus/wDb + rP8A26z/ANus/wDbrP9EsZn/f35+/2JiYv+MjIz/AAAAAAAAAAAAAAAAbGxs/1BQUP+AjYr/Cdaq/wDb + rP8A26z/ANus/wDbrP8A26z/RLGZ/39+fv9iYmL/jIyM/wAAAAAAAAAAAAAAAGxsbP9QUFD/gI2K/wnW + qv8A26z/ANus/wDbrP8A26z/ANus/0Sxmf9/fn7/YmJi/4yMjP8AAAAAAAAAAAAAAABsbGz/UVFR/4GN + iv8S0qj/Cteq/wrXqv8K16r/Cteq/wrXqv9Jr5n/f35+/2JiYv+MjIz/AAAAAAAAAAAAAAAAc3Nz/2Vl + Zf9RUlL/SldU/0lXVP9JV1T/SVdU/0lXVP9JV1T/TlRT/1NTU/+Pj4//i4uL/wAAAAAAAAAAAAAAAHx8 + fP9iYmL/Wlpa/1paWv9aWlr/Wlpa/1paWv9aWlr/Wlpa/1paWv9bW1v/ampq/wAAAAAAAAAAwAcAAMAD + AADAAwAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAMAACgA + AAAQAAAAIAAAAAEACAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAcHBz/IyMj/yQkJP8lJSX/TU5O/09P + T/9KUU//RVNQ/0ZTUP9OVFP/SVdU/0pXVP9QUFD/UVFR/1FSUv9TU1P/Wlpa/1tbW/9iYmL/Y2Nj/2Vl + Zf9mZmb/aWlp/2pqav9sbGz/bm5u/3Nzc/90dHT/dnZ2/3h4eP95eXn/fHx8/39+fv8YGK//Nzes/0ND + uv94eL7/GBjS/zo6wv9CQtr/Sa+Z/0Sxmf8J1qr/Ctaq/wDbrP8S0qj/gYGB/4ODg/+AjYr/gY2K/4uL + i/+MjIz/jo6O/4+Pj/+QkJD/lpaW/4CAsv+goKX/rKys/62trf+2trb/t7e3/7i4uP+5ubn/u7u7/7i4 + vf+6ur//mJjH/5iYyf++vsP/vr7E/8PDw//Gxsb/x8fH/8PDzP/Nzc3/zs7P/8/Pz//GxtP/ysrS/8vL + 0//Q0ND/0dHR/9LS0f/T09P//////wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAA + AP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/AAAA/wAAAP8AAAD/VVUfFhYWFhYWFxYVNVVVVVVV + HlRTU009P1NLLjIvVVVVVR1RSFFSPjxKTD03G1VVVVUcNgE6UVNDIThBOT4yVVVVGQIAA0hSRCUkIiNF + MlVVVR07A0BRUlJOQiYnRjJVVVUdUkhRUlJSUlJPUEcyVVVVHktISEhISEhISElHMlVVVRoTBAgHBwcH + BwYFNDJVVVUYDTEtKysrKysoIBIzVVVVGAwwKiwsLCwsKSASM1VVVRgMMCosLCwsLCkgEjNVVVUYDDAq + LCwsLCwpIBIzVVVVGA0xLSsrKysrKCASM1VVVRoUDgsKCgoKCgkPNTJVVVUfEhAQEBAQEBAQERdVVcAH + AADAAwAAwAMAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMABAADAAQAAwAEAAMAD + AAA= + + + \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs index 02752e22b6..b237bf0a68 100644 --- a/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs +++ b/BizHawk.Client.EmuHawk/tools/HexEditor/HexEditor.cs @@ -526,7 +526,16 @@ namespace BizHawk.Client.EmuHawk { if (_addr + j + DataSize <= _domain.Size) { - rowStr.AppendFormat(_digitFormatString, MakeValue(_addr + j)); + int t_val = 0; + int t_next = 0; + + for (int k = 0; k < DataSize; k++) + { + t_next = MakeValue(1, _addr + j + k); + t_val += (t_next << ((DataSize - k - 1) * 8)); + } + + rowStr.AppendFormat(_digitFormatString, t_val); } else { @@ -569,7 +578,7 @@ namespace BizHawk.Client.EmuHawk { if (Global.CheatList.IsActive(_domain, address)) { - return Global.CheatList.GetCheatValue(_domain, address, (WatchSize)DataSize ).Value; + return Global.CheatList.GetCheatValue(_domain, address, (WatchSize)dataSize ).Value; } switch (dataSize) diff --git a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs index a1c7ad4194..831cc599e8 100644 --- a/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs +++ b/BizHawk.Client.EmuHawk/tools/Lua/Libraries/EmuLuaLibrary.Tastudio.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; @@ -289,5 +290,74 @@ namespace BizHawk.Client.EmuHawk } } } + + public class TastudioBranchInfo + { + public string Id { get; set; } + public int Frame { get; set; } + public string Text { get; set; } + } + + [LuaMethod("getbranches", "Returns a list of the current tastudio branches. Each entry will have the Id, Frame, and Text properties of the branch")] + public LuaTable GetBranches() + { + var table = Lua.NewTable(); + + if (Engaged()) + { + var branches = Tastudio.CurrentTasMovie.Branches.Select(b => new + { + Id = b.UniqueIdentifier.ToString(), + Frame = b.Frame, + Text = b.UserText + }) + .ToList(); + + for (int i = 0; i < branches.Count; i++) + { + table[i] = branches[i]; + } + } + + return table; + } + + + [LuaMethod("getbranchinput", "Gets the controller state of the given frame with the given branch identifier")] + public LuaTable GetBranchInput(string branchId, int frame) + { + var table = Lua.NewTable(); + + if (Engaged()) + { + if (Tastudio.CurrentTasMovie.Branches.Any(b => b.UniqueIdentifier.ToString() == branchId)) + { + var branch = Tastudio.CurrentTasMovie.Branches.First(b => b.UniqueIdentifier.ToString() == branchId); + if (frame < branch.InputLog.Count) + { + var input = branch.InputLog[frame]; + + var adapter = new Bk2ControllerAdapter + { + Definition = Global.MovieSession.MovieControllerAdapter.Definition + }; + + adapter.SetControllersAsMnemonic(input); + + foreach (var button in adapter.Definition.BoolButtons) + { + table[button] = adapter.IsPressed(button); + } + + foreach (var button in adapter.Definition.FloatControls) + { + table[button] = adapter.GetFloat(button); + } + } + } + } + + return table; + } } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs index 295976bb22..bb3d0089d8 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.ListView.cs @@ -55,7 +55,7 @@ namespace BizHawk.Client.EmuHawk private bool _triggerAutoRestore; // If true, autorestore will be called on mouse up private bool? _autoRestorePaused = null; private int? _seekStartFrame = null; - private bool _shouldUnpauseFromRewind = false; + private bool _unpauseAfterSeeking = false; private ControllerDefinition ControllerType => Global.MovieSession.MovieControllerAdapter.Definition; @@ -111,10 +111,10 @@ namespace BizHawk.Client.EmuHawk } Mainform.PauseOnFrame = null; - if (_shouldUnpauseFromRewind) + if (_unpauseAfterSeeking) { Mainform.UnpauseEmulator(); - _shouldUnpauseFromRewind = false; + _unpauseAfterSeeking = false; } if (CurrentTasMovie != null) @@ -762,7 +762,8 @@ namespace BizHawk.Client.EmuHawk private void TasView_MouseUp(object sender, MouseEventArgs e) { - if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && !_supressContextMenu && TasView.SelectedRows.Any()) + if (e.Button == MouseButtons.Right && !TasView.IsPointingAtColumnHeader && + !_supressContextMenu && TasView.SelectedRows.Any() && !_leftButtonHeld) { if (Global.MovieSession.Movie.FrameCount < TasView.SelectedRows.Max()) { diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 30c4349282..63be9aa051 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -72,11 +72,10 @@ namespace BizHawk.Client.EmuHawk } else if (ofd.FileName.EndsWith(".bkm") || ofd.FileName.EndsWith(".bk2")) // todo: proper extention iteration { - Mainform.StartNewMovie(MovieService.Get(ofd.FileName), false); - var result1 = MessageBox.Show("This is a regular movie, a new project must be created from it, in order to use in TAStudio\nProceed?", "Convert movie", MessageBoxButtons.OKCancel, MessageBoxIcon.Question); if (result1 == DialogResult.OK) { + Mainform.StartNewMovie(MovieService.Get(ofd.FileName), false); ConvertCurrentMovieToTasproj(); StartNewMovieWrapper(false); SetUpColumns(); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index d2d48907b7..84405c107b 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -829,7 +829,7 @@ namespace BizHawk.Client.EmuHawk if (frame == Emulator.Frame) return; - _shouldUnpauseFromRewind = fromRewinding && !Mainform.EmulatorPaused; + _unpauseAfterSeeking = (fromRewinding || WasRecording) && !Mainform.EmulatorPaused; TastudioPlayMode(); KeyValuePair closestState = CurrentTasMovie.TasStateManager.GetStateClosestToFrame(frame); if (closestState.Value != null && (frame < Emulator.Frame || closestState.Key > Emulator.Frame)) @@ -871,7 +871,8 @@ namespace BizHawk.Client.EmuHawk // frame == Emulator.Frame when frame == 0 if (frame > Emulator.Frame) { - if (Mainform.EmulatorPaused || Mainform.IsSeeking || fromRewinding) // make seek frame keep up with emulation on fast scrolls + // make seek frame keep up with emulation on fast scrolls + if (Mainform.EmulatorPaused || Mainform.IsSeeking || fromRewinding || WasRecording) { StartSeeking(frame); } diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A7800HawkSchema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A7800HawkSchema.cs deleted file mode 100644 index 2f7fb562e4..0000000000 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A7800HawkSchema.cs +++ /dev/null @@ -1,265 +0,0 @@ -using System.Collections.Generic; -using System.Drawing; - -using BizHawk.Common.ReflectionExtensions; -using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Atari.A7800Hawk; - -namespace BizHawk.Client.EmuHawk -{ - [Schema("A7800")] - public class A7800HawkSchema : IVirtualPadSchema - { - private string UnpluggedControllerName => typeof(UnpluggedController).DisplayName(); - private string StandardControllerName => typeof(StandardController).DisplayName(); - private string ProLineControllerName => typeof(ProLineController).DisplayName(); - - public IEnumerable GetPadSchemas(IEmulator core) - { - var A78SyncSettings = ((A7800Hawk)core).GetSyncSettings().Clone(); - var port1 = A78SyncSettings.Port1; - var port2 = A78SyncSettings.Port2; - - if (port1 == StandardControllerName) - { - yield return JoystickController(1); - } - - if (port2 == StandardControllerName) - { - yield return JoystickController(2); - } - - if (port1 == ProLineControllerName) - { - yield return ProLineController(1); - } - - if (port2 == ProLineControllerName) - { - yield return ProLineController(2); - } - - } - - private static PadSchema ProLineController(int controller) - { - return new PadSchema - { - DisplayName = "Player " + controller, - IsConsole = false, - DefaultSize = new Size(174, 74), - MaxSize = new Size(174, 74), - Buttons = new[] - { - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Up", - DisplayName = "", - Icon = Properties.Resources.BlueUp, - Location = new Point(23, 15), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Down", - DisplayName = "", - Icon = Properties.Resources.BlueDown, - Location = new Point(23, 36), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Left", - DisplayName = "", - Icon = Properties.Resources.Back, - Location = new Point(2, 24), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Right", - DisplayName = "", - Icon = Properties.Resources.Forward, - Location = new Point(44, 24), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Trigger", - DisplayName = "1", - Location = new Point(120, 24), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Trigger 2", - DisplayName = "2", - Location = new Point(145, 24), - Type = PadSchema.PadInputType.Boolean - } - } - }; - } - - private static PadSchema JoystickController(int controller) - { - return new PadSchema - { - DisplayName = "Player " + controller, - IsConsole = false, - DefaultSize = new Size(174, 74), - MaxSize = new Size(174, 74), - Buttons = new[] - { - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Up", - DisplayName = "", - Icon = Properties.Resources.BlueUp, - Location = new Point(23, 15), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Down", - DisplayName = "", - Icon = Properties.Resources.BlueDown, - Location = new Point(23, 36), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Left", - DisplayName = "", - Icon = Properties.Resources.Back, - Location = new Point(2, 24), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Right", - DisplayName = "", - Icon = Properties.Resources.Forward, - Location = new Point(44, 24), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Trigger", - DisplayName = "1", - Location = new Point(120, 24), - Type = PadSchema.PadInputType.Boolean - } - } - }; - } - - private static PadSchema PaddleController(int controller) - { - return new PadSchema - { - DisplayName = "Player " + controller, - IsConsole = false, - DefaultSize = new Size(250, 74), - Buttons = new[] - { - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Paddle", - DisplayName = "Paddle", - Location = new Point(23, 15), - Type = PadSchema.PadInputType.FloatSingle - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Trigger", - DisplayName = "1", - Location = new Point(12, 90), - Type = PadSchema.PadInputType.Boolean - } - } - }; - } - - private static PadSchema LightGunController(int controller) - { - return new PadSchema - { - DisplayName = "Light Gun", - IsConsole = false, - DefaultSize = new Size(356, 290), - MaxSize = new Size(356, 290), - Buttons = new[] - { - new PadSchema.ButtonSchema - { - Name = "P" + controller + " VPos", - Location = new Point(14, 17), - Type = PadSchema.PadInputType.TargetedPair, - TargetSize = new Size(256, 240), - SecondaryNames = new[] - { - "P" + controller + " HPos", - } - }, - new PadSchema.ButtonSchema - { - Name = "P" + controller + " Trigger", - DisplayName = "Trigger", - Location = new Point(284, 17), - Type = PadSchema.PadInputType.Boolean - } - } - }; - } - - private static PadSchema ConsoleButtons() - { - return new PadSchema - { - DisplayName = "Console", - IsConsole = true, - DefaultSize = new Size(215, 50), - Buttons = new[] - { - new PadSchema.ButtonSchema - { - Name = "Select", - DisplayName = "Select", - Location = new Point(10, 15), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "Reset", - DisplayName = "Reset", - Location = new Point(60, 15), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "Power", - DisplayName = "Power", - Location = new Point(108, 15), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "Pause", - DisplayName = "Pause", - Location = new Point(158, 15), - Type = PadSchema.PadInputType.Boolean - }, - new PadSchema.ButtonSchema - { - Name = "BW", - DisplayName = "BW", - Location = new Point(158, 15), - Type = PadSchema.PadInputType.Boolean - } - } - }; - } - } -} diff --git a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A78Schema.cs b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A78Schema.cs index 2b7fd97471..61de5d9c5c 100644 --- a/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A78Schema.cs +++ b/BizHawk.Client.EmuHawk/tools/VirtualPads/schema/A78Schema.cs @@ -2,7 +2,9 @@ using System.Drawing; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Atari.Atari7800; + +using BizHawk.Common.ReflectionExtensions; +using BizHawk.Emulation.Cores.Atari.A7800Hawk; namespace BizHawk.Client.EmuHawk { @@ -11,33 +13,42 @@ namespace BizHawk.Client.EmuHawk { public IEnumerable GetPadSchemas(IEmulator core) { - switch (((Atari7800)core).ControlAdapter.ControlType.Name) + return Atari7800HawkSchema.GetPadSchemas((A7800Hawk)core); + } + } + + internal static class Atari7800HawkSchema + { + private static string UnpluggedControllerName => typeof(UnpluggedController).DisplayName(); + private static string StandardControllerName => typeof(StandardController).DisplayName(); + private static string ProLineControllerName => typeof(ProLineController).DisplayName(); + + public static IEnumerable GetPadSchemas(A7800Hawk core) + { + var A78SyncSettings = core.GetSyncSettings().Clone(); + var port1 = A78SyncSettings.Port1; + var port2 = A78SyncSettings.Port2; + + if (port1 == StandardControllerName) { - case "Atari 7800 Joystick Controller": - yield return JoystickController(1); - yield return JoystickController(2); - break; - case "Atari 7800 Paddle Controller": - yield return PaddleController(1); - yield return PaddleController(2); - break; - case "Atari 7800 Keypad Controller": - break; - case "Atari 7800 Driving Controller": - break; - case "Atari 7800 Booster Grip Controller": - break; - case "Atari 7800 ProLine Joystick Controller": - yield return ProLineController(1); - yield return ProLineController(2); - break; - case "Atari 7800 Light Gun Controller": - yield return LightGunController(1); - yield return LightGunController(2); - break; + yield return JoystickController(1); + } + + if (port2 == StandardControllerName) + { + yield return JoystickController(2); + } + + if (port1 == ProLineControllerName) + { + yield return ProLineController(1); + } + + if (port2 == ProLineControllerName) + { + yield return ProLineController(2); } - yield return ConsoleButtons(); } private static PadSchema ProLineController(int controller) diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index c9919ebed4..af786ec123 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -91,6 +91,7 @@ + diff --git a/BizHawk.Emulation.Common/EmulationExceptions.cs b/BizHawk.Emulation.Common/EmulationExceptions.cs index f0bc2a5860..ea85be6924 100644 --- a/BizHawk.Emulation.Common/EmulationExceptions.cs +++ b/BizHawk.Emulation.Common/EmulationExceptions.cs @@ -20,6 +20,20 @@ namespace BizHawk.Emulation.Common } } + public class NoAvailableCoreException : Exception + { + public NoAvailableCoreException() + : base("System is currently NOT emulated") + { + } + + public NoAvailableCoreException(string message) + : base ("System is currently NOT emulated: " + message) + { + + } + } + public class CGBNotSupportedException : Exception { public CGBNotSupportedException() diff --git a/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs b/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs new file mode 100644 index 0000000000..5fd648e9f7 --- /dev/null +++ b/BizHawk.Emulation.Common/Interfaces/Services/ICycleTiming.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BizHawk.Emulation.Common +{ + public interface ICycleTiming + { + /// + /// Total elapsed emulation time relative to + /// + long CycleCount { get; } + /// + /// Clock Rate in hz for + /// + double ClockRate { get; } + } +} diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 7e99f6ac12..0acda8f08e 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -63,9 +63,6 @@ ..\References\ELFSharp.dll - - ..\References\EMU7800.dll - ..\References\Newtonsoft.Json.dll @@ -368,30 +365,10 @@ + - - - - Atari7800.cs - - - Atari7800.cs - - - Atari7800.cs - - - Atari7800.cs - - - Atari7800.cs - - - - Atari7800.cs - @@ -486,6 +463,9 @@ Gambatte.cs + + Gambatte.cs + Gambatte.cs @@ -535,6 +515,7 @@ GambatteLink.cs + GambatteLink.cs @@ -771,6 +752,7 @@ + @@ -899,6 +881,9 @@ NES.cs + + NES.cs + NES.cs @@ -1090,6 +1075,8 @@ + + SMS.cs @@ -1205,12 +1192,14 @@ - - - - - - + + + + + + + + True True diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Execute.cs deleted file mode 100644 index 996ed875e1..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Execute.cs +++ /dev/null @@ -1,12493 +0,0 @@ -using BizHawk.Common.NumberExtensions; -using BizHawk.Emulation.Common; -using System; - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - private int totalExecutedCycles; - public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } } - - private int expectedExecutedCycles; - public int ExpectedExecutedCycles { get { return expectedExecutedCycles; } set { expectedExecutedCycles = value; } } - - private int pendingCycles; - public int PendingCycles { get { return pendingCycles; } set { pendingCycles = value; } } - - private int EI_pending; - - private ushort temp_WZ; - - public bool Debug; - public Action Logger; - - /// - /// Runs the CPU for a particular number of clock cycles. - /// - /// The number of cycles to run the CPU emulator for. Specify -1 to run for a single instruction. - public void ExecuteCycles(int cycles) - { - expectedExecutedCycles += cycles; - pendingCycles += cycles; - - sbyte Displacement; - - byte TB; byte TBH; byte TBL; byte TB1; byte TB2; sbyte TSB; ushort TUS; int TI1; int TI2; int TIR; - - bool Interruptable; - - while (pendingCycles > 0) - { - Interruptable = true; - - if (halted) - { - ++RegR; - totalExecutedCycles += 4; pendingCycles -= 4; - } - else - { - if (Debug) - { - Logger(State()); - } - - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallExecutes(RegPC.Word, "System Bus"); - } - - ++RegR; - switch (FetchFirstMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // LD BC, nn - RegBC.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x02: // LD (BC), A - RegWZ.Low = (byte)((RegBC.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegBC.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x03: // INC BC - ++RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x04: // INC B - RegAF.Low = (byte)(TableInc[++RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // DEC B - RegAF.Low = (byte)(TableDec[--RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // LD B, n - RegBC.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x07: // RLCA - RegAF.Word = TableRotShift[0, 0, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // EX AF, AF' - TUS = RegAF.Word; RegAF.Word = RegAltAF.Word; RegAltAF.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // ADD HL, BC - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x0A: // LD A, (BC) - RegAF.High = ReadMemoryWrapper(RegBC.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegBC.Word + 1); - break; - case 0x0B: // DEC BC - --RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x0C: // INC C - RegAF.Low = (byte)(TableInc[++RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // DEC C - RegAF.Low = (byte)(TableDec[--RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // LD C, n - RegBC.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x0F: // RRCA - RegAF.Word = TableRotShift[0, 1, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // DJNZ d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (--RegBC.High != 0) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 13; pendingCycles -= 13; - } - else - { - totalExecutedCycles += 8; pendingCycles -= 8; - } - break; - case 0x11: // LD DE, nn - RegDE.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x12: // LD (DE), A - RegWZ.Low = (byte)((RegDE.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegDE.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x13: // INC DE - ++RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x14: // INC D - RegAF.Low = (byte)(TableInc[++RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // DEC D - RegAF.Low = (byte)(TableDec[--RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // LD D, n - RegDE.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x17: // RLA - RegAF.Word = TableRotShift[0, 2, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // JR d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x19: // ADD HL, DE - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x1A: // LD A, (DE) - RegAF.High = ReadMemoryWrapper(RegDE.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegDE.Word + 1); - break; - case 0x1B: // DEC DE - --RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x1C: // INC E - RegAF.Low = (byte)(TableInc[++RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // DEC E - RegAF.Low = (byte)(TableDec[--RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // LD E, n - RegDE.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x1F: // RRA - RegAF.Word = TableRotShift[0, 3, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // JR NZ, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x21: // LD HL, nn - RegHL.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x22: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x23: // INC HL - ++RegHL.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x24: // INC H - RegAF.Low = (byte)(TableInc[++RegHL.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // DEC H - RegAF.Low = (byte)(TableDec[--RegHL.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // LD H, n - RegHL.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x27: // DAA - RegAF.Word = TableDaa[RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // JR Z, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x29: // ADD HL, HL - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x2A: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x2B: // DEC HL - --RegHL.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x2C: // INC L - RegAF.Low = (byte)(TableInc[++RegHL.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // DEC L - RegAF.Low = (byte)(TableDec[--RegHL.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // LD L, n - RegHL.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x2F: // CPL - RegAF.High ^= 0xFF; RegFlagH = true; RegFlagN = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // JR NC, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x31: // LD SP, nn - RegSP.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x32: // LD (nn), A - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ.Low = (byte)((temp_WZ + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(temp_WZ, RegAF.High); - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 0x33: // INC SP - ++RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x34: // INC (HL) - TB = ReadMemoryWrapper(RegHL.Word); RegAF.Low = (byte)(TableInc[++TB] | (RegAF.Low & 1)); WriteMemoryWrapper(RegHL.Word, TB); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x35: // DEC (HL) - TB = ReadMemoryWrapper(RegHL.Word); RegAF.Low = (byte)(TableDec[--TB] | (RegAF.Low & 1)); WriteMemoryWrapper(RegHL.Word, TB); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x36: // LD (HL), n - WriteMemoryWrapper(RegHL.Word, FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x37: // SCF - RegFlagH = false; RegFlagN = false; RegFlagC = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // JR C, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x39: // ADD HL, SP - RegWZ = (ushort)(RegHL + 1); - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x3A: // LD A, (nn) - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegAF.High = ReadMemoryWrapper(temp_WZ); - totalExecutedCycles += 13; pendingCycles -= 13; - RegWZ.Word = (ushort)(temp_WZ + 1); - break; - case 0x3B: // DEC SP - --RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x3C: // INC A - RegAF.Low = (byte)(TableInc[++RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // DEC A - RegAF.Low = (byte)(TableDec[--RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // LD A, n - RegAF.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x3F: // CCF - RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // LD B, B - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x41: // LD B, C - RegBC.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x42: // LD B, D - RegBC.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x43: // LD B, E - RegBC.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x44: // LD B, H - RegBC.High = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x45: // LD B, L - RegBC.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x46: // LD B, (HL) - RegBC.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x47: // LD B, A - RegBC.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x48: // LD C, B - RegBC.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x49: // LD C, C - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4A: // LD C, D - RegBC.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4B: // LD C, E - RegBC.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4C: // LD C, H - RegBC.Low = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4D: // LD C, L - RegBC.Low = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4E: // LD C, (HL) - RegBC.Low = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x4F: // LD C, A - RegBC.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x50: // LD D, B - RegDE.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x51: // LD D, C - RegDE.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x52: // LD D, D - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x53: // LD D, E - RegDE.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x54: // LD D, H - RegDE.High = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x55: // LD D, L - RegDE.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x56: // LD D, (HL) - RegDE.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x57: // LD D, A - RegDE.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x58: // LD E, B - RegDE.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x59: // LD E, C - RegDE.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5A: // LD E, D - RegDE.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5B: // LD E, E - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5C: // LD E, H - RegDE.Low = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5D: // LD E, L - RegDE.Low = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5E: // LD E, (HL) - RegDE.Low = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x5F: // LD E, A - RegDE.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x60: // LD H, B - RegHL.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x61: // LD H, C - RegHL.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x62: // LD H, D - RegHL.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x63: // LD H, E - RegHL.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x64: // LD H, H - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x65: // LD H, L - RegHL.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x66: // LD H, (HL) - RegHL.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x67: // LD H, A - RegHL.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x68: // LD L, B - RegHL.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x69: // LD L, C - RegHL.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6A: // LD L, D - RegHL.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6B: // LD L, E - RegHL.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6C: // LD L, H - RegHL.Low = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6D: // LD L, L - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x6E: // LD L, (HL) - RegHL.Low = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x6F: // LD L, A - RegHL.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x70: // LD (HL), B - WriteMemoryWrapper(RegHL.Word, RegBC.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x71: // LD (HL), C - WriteMemoryWrapper(RegHL.Word, RegBC.Low); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x72: // LD (HL), D - WriteMemoryWrapper(RegHL.Word, RegDE.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x73: // LD (HL), E - WriteMemoryWrapper(RegHL.Word, RegDE.Low); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x74: // LD (HL), H - WriteMemoryWrapper(RegHL.Word, RegHL.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x75: // LD (HL), L - WriteMemoryWrapper(RegHL.Word, RegHL.Low); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x76: // HALT - Halt(); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x77: // LD (HL), A - RegWZ.Low = (byte)((RegHL.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegHL.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x78: // LD A, B - RegAF.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x79: // LD A, C - RegAF.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7A: // LD A, D - RegAF.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7B: // LD A, E - RegAF.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7C: // LD A, H - RegAF.High = RegHL.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7D: // LD A, L - RegAF.High = RegHL.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7E: // LD A, (HL) - RegAF.High = ReadMemoryWrapper(RegHL.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegHL.Word + 1); - break; - case 0x7F: // LD A, A - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // ADD A, B - RegAF.Word = TableALU[0, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // ADD A, C - RegAF.Word = TableALU[0, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // ADD A, D - RegAF.Word = TableALU[0, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // ADD A, E - RegAF.Word = TableALU[0, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // ADD A, H - RegAF.Word = TableALU[0, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // ADD A, L - RegAF.Word = TableALU[0, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // ADD A, (HL) - RegWZ = (ushort)(RegHL + 1); - RegAF.Word = TableALU[0, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x87: // ADD A, A - RegAF.Word = TableALU[0, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // ADC A, B - RegAF.Word = TableALU[1, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // ADC A, C - RegAF.Word = TableALU[1, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // ADC A, D - RegAF.Word = TableALU[1, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // ADC A, E - RegAF.Word = TableALU[1, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // ADC A, H - RegAF.Word = TableALU[1, RegAF.High, RegHL.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // ADC A, L - RegAF.Word = TableALU[1, RegAF.High, RegHL.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // ADC A, (HL) - RegAF.Word = TableALU[1, RegAF.High, ReadMemoryWrapper(RegHL.Word), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x8F: // ADC A, A - RegAF.Word = TableALU[1, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // SUB B - RegAF.Word = TableALU[2, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // SUB C - RegAF.Word = TableALU[2, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // SUB D - RegAF.Word = TableALU[2, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // SUB E - RegAF.Word = TableALU[2, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // SUB H - RegAF.Word = TableALU[2, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // SUB L - RegAF.Word = TableALU[2, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // SUB (HL) - RegAF.Word = TableALU[2, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x97: // SUB A, A - RegAF.Word = TableALU[2, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // SBC A, B - RegAF.Word = TableALU[3, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // SBC A, C - RegAF.Word = TableALU[3, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // SBC A, D - RegAF.Word = TableALU[3, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // SBC A, E - RegAF.Word = TableALU[3, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // SBC A, H - RegAF.Word = TableALU[3, RegAF.High, RegHL.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // SBC A, L - RegAF.Word = TableALU[3, RegAF.High, RegHL.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // SBC A, (HL) - RegAF.Word = TableALU[3, RegAF.High, ReadMemoryWrapper(RegHL.Word), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x9F: // SBC A, A - RegAF.Word = TableALU[3, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // AND B - RegAF.Word = TableALU[4, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA1: // AND C - RegAF.Word = TableALU[4, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA2: // AND D - RegAF.Word = TableALU[4, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA3: // AND E - RegAF.Word = TableALU[4, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA4: // AND H - RegAF.Word = TableALU[4, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // AND L - RegAF.Word = TableALU[4, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // AND (HL) - RegAF.Word = TableALU[4, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xA7: // AND A - RegAF.Word = TableALU[4, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // XOR B - RegAF.Word = TableALU[5, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA9: // XOR C - RegAF.Word = TableALU[5, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAA: // XOR D - RegAF.Word = TableALU[5, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAB: // XOR E - RegAF.Word = TableALU[5, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAC: // XOR H - RegAF.Word = TableALU[5, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // XOR L - RegAF.Word = TableALU[5, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // XOR (HL) - RegAF.Word = TableALU[5, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xAF: // XOR A - RegAF.Word = TableALU[5, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // OR B - RegAF.Word = TableALU[6, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB1: // OR C - RegAF.Word = TableALU[6, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB2: // OR D - RegAF.Word = TableALU[6, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB3: // OR E - RegAF.Word = TableALU[6, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB4: // OR H - RegAF.Word = TableALU[6, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // OR L - RegAF.Word = TableALU[6, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // OR (HL) - RegAF.Word = TableALU[6, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xB7: // OR A - RegAF.Word = TableALU[6, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // CP B - RegAF.Word = TableALU[7, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB9: // CP C - RegAF.Word = TableALU[7, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBA: // CP D - RegAF.Word = TableALU[7, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBB: // CP E - RegAF.Word = TableALU[7, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBC: // CP H - RegAF.Word = TableALU[7, RegAF.High, RegHL.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // CP L - RegAF.Word = TableALU[7, RegAF.High, RegHL.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // CP (HL) - RegAF.Word = TableALU[7, RegAF.High, ReadMemoryWrapper(RegHL.Word), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xBF: // CP A - RegAF.Word = TableALU[7, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // RET NZ - if (!RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC1: // POP BC - RegBC.Low = ReadMemoryWrapper(RegSP.Word++); RegBC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC2: // JP NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC3: // JP nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - RegPC.Word = TUS; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC4: // CALL NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xC5: // PUSH BC - WriteMemoryWrapper(--RegSP.Word, RegBC.High); WriteMemoryWrapper(--RegSP.Word, RegBC.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC6: // ADD A, n - RegAF.Word = TableALU[0, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xC7: // RST $00 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x00; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC8: // RET Z - if (RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC9: // RET - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCA: // JP Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCB: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // RLC B - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x01: // RLC C - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x02: // RLC D - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x03: // RLC E - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x04: // RLC H - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x05: // RLC L - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x06: // RLC (HL) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x07: // RLC A - TUS = TableRotShift[1, 0, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x08: // RRC B - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x09: // RRC C - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0A: // RRC D - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0B: // RRC E - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0C: // RRC H - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0D: // RRC L - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x0E: // RRC (HL) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x0F: // RRC A - TUS = TableRotShift[1, 1, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x10: // RL B - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x11: // RL C - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x12: // RL D - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x13: // RL E - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x14: // RL H - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x15: // RL L - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x16: // RL (HL) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x17: // RL A - TUS = TableRotShift[1, 2, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x18: // RR B - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x19: // RR C - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1A: // RR D - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1B: // RR E - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1C: // RR H - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1D: // RR L - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x1E: // RR (HL) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x1F: // RR A - TUS = TableRotShift[1, 3, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x20: // SLA B - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x21: // SLA C - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x22: // SLA D - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x23: // SLA E - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x24: // SLA H - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x25: // SLA L - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x26: // SLA (HL) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x27: // SLA A - TUS = TableRotShift[1, 4, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x28: // SRA B - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x29: // SRA C - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2A: // SRA D - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2B: // SRA E - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2C: // SRA H - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2D: // SRA L - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2E: // SRA (HL) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x2F: // SRA A - TUS = TableRotShift[1, 5, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x30: // SL1 B - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x31: // SL1 C - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x32: // SL1 D - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x33: // SL1 E - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x34: // SL1 H - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x35: // SL1 L - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x36: // SL1 (HL) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x37: // SL1 A - TUS = TableRotShift[1, 6, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x38: // SRL B - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegBC.High]; - RegBC.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x39: // SRL C - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegBC.Low]; - RegBC.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3A: // SRL D - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegDE.High]; - RegDE.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3B: // SRL E - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegDE.Low]; - RegDE.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3C: // SRL H - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegHL.High]; - RegHL.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3D: // SRL L - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegHL.Low]; - RegHL.Low = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x3E: // SRL (HL) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper(RegHL.Word)]; - WriteMemoryWrapper(RegHL.Word, (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x3F: // SRL A - TUS = TableRotShift[1, 7, RegAF.Low + 256 * RegAF.High]; - RegAF.High = (byte)(TUS >> 8); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x40: // BIT 0, B - RegFlagZ = (RegBC.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x41: // BIT 0, C - RegFlagZ = (RegBC.Low & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x42: // BIT 0, D - RegFlagZ = (RegDE.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x43: // BIT 0, E - RegFlagZ = (RegDE.Low & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x44: // BIT 0, H - RegFlagZ = (RegHL.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // BIT 0, L - RegFlagZ = (RegHL.Low & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x46: // BIT 0, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x47: // BIT 0, A - RegFlagZ = (RegAF.High & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x48: // BIT 1, B - RegFlagZ = (RegBC.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x49: // BIT 1, C - RegFlagZ = (RegBC.Low & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4A: // BIT 1, D - RegFlagZ = (RegDE.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4B: // BIT 1, E - RegFlagZ = (RegDE.Low & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4C: // BIT 1, H - RegFlagZ = (RegHL.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // BIT 1, L - RegFlagZ = (RegHL.Low & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4E: // BIT 1, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4F: // BIT 1, A - RegFlagZ = (RegAF.High & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x50: // BIT 2, B - RegFlagZ = (RegBC.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x51: // BIT 2, C - RegFlagZ = (RegBC.Low & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x52: // BIT 2, D - RegFlagZ = (RegDE.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x53: // BIT 2, E - RegFlagZ = (RegDE.Low & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x54: // BIT 2, H - RegFlagZ = (RegHL.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // BIT 2, L - RegFlagZ = (RegHL.Low & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x56: // BIT 2, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x57: // BIT 2, A - RegFlagZ = (RegAF.High & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x58: // BIT 3, B - RegFlagZ = (RegBC.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x59: // BIT 3, C - RegFlagZ = (RegBC.Low & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5A: // BIT 3, D - RegFlagZ = (RegDE.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5B: // BIT 3, E - RegFlagZ = (RegDE.Low & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5C: // BIT 3, H - RegFlagZ = (RegHL.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // BIT 3, L - RegFlagZ = (RegHL.Low & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5E: // BIT 3, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5F: // BIT 3, A - RegFlagZ = (RegAF.High & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x60: // BIT 4, B - RegFlagZ = (RegBC.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x61: // BIT 4, C - RegFlagZ = (RegBC.Low & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x62: // BIT 4, D - RegFlagZ = (RegDE.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x63: // BIT 4, E - RegFlagZ = (RegDE.Low & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x64: // BIT 4, H - RegFlagZ = (RegHL.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // BIT 4, L - RegFlagZ = (RegHL.Low & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x66: // BIT 4, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x67: // BIT 4, A - RegFlagZ = (RegAF.High & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x68: // BIT 5, B - RegFlagZ = (RegBC.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x69: // BIT 5, C - RegFlagZ = (RegBC.Low & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6A: // BIT 5, D - RegFlagZ = (RegDE.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6B: // BIT 5, E - RegFlagZ = (RegDE.Low & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6C: // BIT 5, H - RegFlagZ = (RegHL.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // BIT 5, L - RegFlagZ = (RegHL.Low & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6E: // BIT 5, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6F: // BIT 5, A - RegFlagZ = (RegAF.High & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x70: // BIT 6, B - RegFlagZ = (RegBC.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x71: // BIT 6, C - RegFlagZ = (RegBC.Low & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x72: // BIT 6, D - RegFlagZ = (RegDE.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x73: // BIT 6, E - RegFlagZ = (RegDE.Low & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x74: // BIT 6, H - RegFlagZ = (RegHL.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // BIT 6, L - RegFlagZ = (RegHL.Low & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x76: // BIT 6, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x77: // BIT 6, A - RegFlagZ = (RegAF.High & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x78: // BIT 7, B - RegFlagZ = (RegBC.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegBC.High.Bit(3); - RegFlag5 = RegBC.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x79: // BIT 7, C - RegFlagZ = (RegBC.Low & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegBC.Low.Bit(3); - RegFlag5 = RegBC.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7A: // BIT 7, D - RegFlagZ = (RegDE.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegDE.High.Bit(3); - RegFlag5 = RegDE.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7B: // BIT 7, E - RegFlagZ = (RegDE.Low & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegDE.Low.Bit(3); - RegFlag5 = RegDE.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7C: // BIT 7, H - RegFlagZ = (RegHL.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegHL.High.Bit(3); - RegFlag5 = RegHL.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // BIT 7, L - RegFlagZ = (RegHL.Low & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegHL.Low.Bit(3); - RegFlag5 = RegHL.Low.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7E: // BIT 7, (HL) - RegFlagZ = (ReadMemoryWrapper(RegHL.Word) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7F: // BIT 7, A - RegFlagZ = (RegAF.High & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegAF.High.Bit(3); - RegFlag5 = RegAF.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x80: // RES 0, B - RegBC.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x81: // RES 0, C - RegBC.Low &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x82: // RES 0, D - RegDE.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x83: // RES 0, E - RegDE.Low &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x84: // RES 0, H - RegHL.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x85: // RES 0, L - RegHL.Low &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x86: // RES 0, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x01))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x87: // RES 0, A - RegAF.High &= unchecked((byte)~0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x88: // RES 1, B - RegBC.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x89: // RES 1, C - RegBC.Low &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8A: // RES 1, D - RegDE.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8B: // RES 1, E - RegDE.Low &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8C: // RES 1, H - RegHL.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8D: // RES 1, L - RegHL.Low &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8E: // RES 1, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x02))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x8F: // RES 1, A - RegAF.High &= unchecked((byte)~0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x90: // RES 2, B - RegBC.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x91: // RES 2, C - RegBC.Low &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x92: // RES 2, D - RegDE.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x93: // RES 2, E - RegDE.Low &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x94: // RES 2, H - RegHL.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x95: // RES 2, L - RegHL.Low &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x96: // RES 2, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x04))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x97: // RES 2, A - RegAF.High &= unchecked((byte)~0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x98: // RES 3, B - RegBC.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x99: // RES 3, C - RegBC.Low &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9A: // RES 3, D - RegDE.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9B: // RES 3, E - RegDE.Low &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9C: // RES 3, H - RegHL.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9D: // RES 3, L - RegHL.Low &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9E: // RES 3, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x08))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x9F: // RES 3, A - RegAF.High &= unchecked((byte)~0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA0: // RES 4, B - RegBC.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA1: // RES 4, C - RegBC.Low &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA2: // RES 4, D - RegDE.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA3: // RES 4, E - RegDE.Low &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA4: // RES 4, H - RegHL.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA5: // RES 4, L - RegHL.Low &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA6: // RES 4, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x10))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xA7: // RES 4, A - RegAF.High &= unchecked((byte)~0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA8: // RES 5, B - RegBC.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA9: // RES 5, C - RegBC.Low &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAA: // RES 5, D - RegDE.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAB: // RES 5, E - RegDE.Low &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAC: // RES 5, H - RegHL.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAD: // RES 5, L - RegHL.Low &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAE: // RES 5, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x20))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xAF: // RES 5, A - RegAF.High &= unchecked((byte)~0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB0: // RES 6, B - RegBC.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB1: // RES 6, C - RegBC.Low &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB2: // RES 6, D - RegDE.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB3: // RES 6, E - RegDE.Low &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB4: // RES 6, H - RegHL.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB5: // RES 6, L - RegHL.Low &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB6: // RES 6, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x40))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xB7: // RES 6, A - RegAF.High &= unchecked((byte)~0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB8: // RES 7, B - RegBC.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB9: // RES 7, C - RegBC.Low &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBA: // RES 7, D - RegDE.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBB: // RES 7, E - RegDE.Low &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBC: // RES 7, H - RegHL.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBD: // RES 7, L - RegHL.Low &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBE: // RES 7, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) & unchecked((byte)~0x80))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xBF: // RES 7, A - RegAF.High &= unchecked((byte)~0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC0: // SET 0, B - RegBC.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC1: // SET 0, C - RegBC.Low |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC2: // SET 0, D - RegDE.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC3: // SET 0, E - RegDE.Low |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC4: // SET 0, H - RegHL.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC5: // SET 0, L - RegHL.Low |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC6: // SET 0, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x01))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xC7: // SET 0, A - RegAF.High |= unchecked((byte)0x01); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC8: // SET 1, B - RegBC.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xC9: // SET 1, C - RegBC.Low |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCA: // SET 1, D - RegDE.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCB: // SET 1, E - RegDE.Low |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCC: // SET 1, H - RegHL.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCD: // SET 1, L - RegHL.Low |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xCE: // SET 1, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x02))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xCF: // SET 1, A - RegAF.High |= unchecked((byte)0x02); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD0: // SET 2, B - RegBC.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD1: // SET 2, C - RegBC.Low |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD2: // SET 2, D - RegDE.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD3: // SET 2, E - RegDE.Low |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD4: // SET 2, H - RegHL.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD5: // SET 2, L - RegHL.Low |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD6: // SET 2, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x04))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xD7: // SET 2, A - RegAF.High |= unchecked((byte)0x04); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD8: // SET 3, B - RegBC.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xD9: // SET 3, C - RegBC.Low |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDA: // SET 3, D - RegDE.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDB: // SET 3, E - RegDE.Low |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDC: // SET 3, H - RegHL.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDD: // SET 3, L - RegHL.Low |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xDE: // SET 3, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x08))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xDF: // SET 3, A - RegAF.High |= unchecked((byte)0x08); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE0: // SET 4, B - RegBC.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE1: // SET 4, C - RegBC.Low |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE2: // SET 4, D - RegDE.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE3: // SET 4, E - RegDE.Low |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE4: // SET 4, H - RegHL.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE5: // SET 4, L - RegHL.Low |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE6: // SET 4, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x10))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xE7: // SET 4, A - RegAF.High |= unchecked((byte)0x10); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE8: // SET 5, B - RegBC.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xE9: // SET 5, C - RegBC.Low |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEA: // SET 5, D - RegDE.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEB: // SET 5, E - RegDE.Low |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEC: // SET 5, H - RegHL.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xED: // SET 5, L - RegHL.Low |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEE: // SET 5, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x20))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xEF: // SET 5, A - RegAF.High |= unchecked((byte)0x20); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF0: // SET 6, B - RegBC.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF1: // SET 6, C - RegBC.Low |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF2: // SET 6, D - RegDE.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF3: // SET 6, E - RegDE.Low |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF4: // SET 6, H - RegHL.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF5: // SET 6, L - RegHL.Low |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF6: // SET 6, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x40))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xF7: // SET 6, A - RegAF.High |= unchecked((byte)0x40); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF8: // SET 7, B - RegBC.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xF9: // SET 7, C - RegBC.Low |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFA: // SET 7, D - RegDE.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFB: // SET 7, E - RegDE.Low |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFC: // SET 7, H - RegHL.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFD: // SET 7, L - RegHL.Low |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xFE: // SET 7, (HL) - WriteMemoryWrapper(RegHL.Word, (byte)(ReadMemoryWrapper(RegHL.Word) | unchecked((byte)0x80))); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xFF: // SET 7, A - RegAF.High |= unchecked((byte)0x80); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - } - break; - case 0xCC: // CALL Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xCD: // CALL nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - break; - case 0xCE: // ADC A, n - RegAF.Word = TableALU[1, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xCF: // RST $08 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x08; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD0: // RET NC - if (!RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD1: // POP DE - RegDE.Low = ReadMemoryWrapper(RegSP.Word++); RegDE.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD2: // JP NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD3: // OUT n, A - WriteHardware(FetchMemoryWrapper(RegPC.Word++), RegAF.High); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD4: // CALL NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xD5: // PUSH DE - WriteMemoryWrapper(--RegSP.Word, RegDE.High); WriteMemoryWrapper(--RegSP.Word, RegDE.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD6: // SUB n - RegAF.Word = TableALU[2, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xD7: // RST $10 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x10; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD8: // RET C - if (RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD9: // EXX - TUS = RegBC.Word; RegBC.Word = RegAltBC.Word; RegAltBC.Word = TUS; - TUS = RegDE.Word; RegDE.Word = RegAltDE.Word; RegAltDE.Word = TUS; - TUS = RegHL.Word; RegHL.Word = RegAltHL.Word; RegAltHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // JP C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xDB: // IN A, n - RegAF.High = ReadHardware((ushort)FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xDC: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xDD: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // LD BC, nn - RegBC.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x02: // LD (BC), A - RegWZ.Low = (byte)((RegBC.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegBC.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x03: // INC BC - ++RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x04: // INC B - RegAF.Low = (byte)(TableInc[++RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // DEC B - RegAF.Low = (byte)(TableDec[--RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // LD B, n - RegBC.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x07: // RLCA - RegAF.Word = TableRotShift[0, 0, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // EX AF, AF' - TUS = RegAF.Word; RegAF.Word = RegAltAF.Word; RegAltAF.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // ADD IX, BC - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x0A: // LD A, (BC) - RegAF.High = ReadMemoryWrapper(RegBC.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegBC.Word + 1); - break; - case 0x0B: // DEC BC - --RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x0C: // INC C - RegAF.Low = (byte)(TableInc[++RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // DEC C - RegAF.Low = (byte)(TableDec[--RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // LD C, n - RegBC.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x0F: // RRCA - RegAF.Word = TableRotShift[0, 1, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // DJNZ d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (--RegBC.High != 0) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 13; pendingCycles -= 13; - } - else - { - totalExecutedCycles += 8; pendingCycles -= 8; - } - break; - case 0x11: // LD DE, nn - RegDE.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x12: // LD (DE), A - RegWZ.Low = (byte)((RegDE.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegDE.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x13: // INC DE - ++RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x14: // INC D - RegAF.Low = (byte)(TableInc[++RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // DEC D - RegAF.Low = (byte)(TableDec[--RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // LD D, n - RegDE.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x17: // RLA - RegAF.Word = TableRotShift[0, 2, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // JR d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x19: // ADD IX, DE - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x1A: // LD A, (DE) - RegAF.High = ReadMemoryWrapper(RegDE.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegDE.Word + 1); - break; - case 0x1B: // DEC DE - --RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x1C: // INC E - RegAF.Low = (byte)(TableInc[++RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // DEC E - RegAF.Low = (byte)(TableDec[--RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // LD E, n - RegDE.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x1F: // RRA - RegAF.Word = TableRotShift[0, 3, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // JR NZ, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x21: // LD IX, nn - RegIX.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x22: // LD (nn), IX - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegIX.Low); - WriteMemoryWrapper(TUS, RegIX.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x23: // INC IX - ++RegIX.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x24: // INC IXH - RegAF.Low = (byte)(TableInc[++RegIX.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x25: // DEC IXH - RegAF.Low = (byte)(TableDec[--RegIX.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x26: // LD IXH, n - RegIX.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x27: // DAA - RegAF.Word = TableDaa[RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // JR Z, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x29: // ADD IX, IX - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegIX.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x2A: // LD IX, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegIX.Low = ReadMemoryWrapper(TUS++); RegIX.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x2B: // DEC IX - --RegIX.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x2C: // INC IXL - RegAF.Low = (byte)(TableInc[++RegIX.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2D: // DEC IXL - RegAF.Low = (byte)(TableDec[--RegIX.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2E: // LD IXL, n - RegIX.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x2F: // CPL - RegAF.High ^= 0xFF; RegFlagH = true; RegFlagN = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // JR NC, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x31: // LD SP, nn - RegSP.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x32: // LD (nn), A - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ.Low = (byte)((temp_WZ + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(temp_WZ, RegAF.High); - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 0x33: // INC SP - ++RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x34: // INC (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); RegAF.Low = (byte)(TableInc[++TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // DEC (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); RegAF.Low = (byte)(TableDec[--TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // LD (IX+d), n - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x37: // SCF - RegFlagH = false; RegFlagN = false; RegFlagC = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // JR C, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x39: // ADD IX, SP - RegWZ = (ushort)(RegIX + 1); - TI1 = (short)RegIX.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIX.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x3A: // LD A, (nn) - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegAF.High = ReadMemoryWrapper(temp_WZ); - totalExecutedCycles += 13; pendingCycles -= 13; - RegWZ = (ushort)(temp_WZ + 1); - break; - case 0x3B: // DEC SP - --RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x3C: // INC A - RegAF.Low = (byte)(TableInc[++RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // DEC A - RegAF.Low = (byte)(TableDec[--RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // LD A, n - RegAF.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x3F: // CCF - RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // LD B, B - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x41: // LD B, C - RegBC.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x42: // LD B, D - RegBC.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x43: // LD B, E - RegBC.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x44: // LD B, IXH - RegBC.High = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // LD B, IXL - RegBC.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x46: // LD B, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegBC.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x47: // LD B, A - RegBC.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x48: // LD C, B - RegBC.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x49: // LD C, C - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4A: // LD C, D - RegBC.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4B: // LD C, E - RegBC.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4C: // LD C, IXH - RegBC.Low = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // LD C, IXL - RegBC.Low = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4E: // LD C, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegBC.Low = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x4F: // LD C, A - RegBC.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x50: // LD D, B - RegDE.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x51: // LD D, C - RegDE.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x52: // LD D, D - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x53: // LD D, E - RegDE.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x54: // LD D, IXH - RegDE.High = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // LD D, IXL - RegDE.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x56: // LD D, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegDE.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x57: // LD D, A - RegDE.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x58: // LD E, B - RegDE.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x59: // LD E, C - RegDE.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5A: // LD E, D - RegDE.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5B: // LD E, E - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5C: // LD E, IXH - RegDE.Low = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // LD E, IXL - RegDE.Low = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5E: // LD E, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegDE.Low = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x5F: // LD E, A - RegDE.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x60: // LD IXH, B - RegIX.High = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x61: // LD IXH, C - RegIX.High = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x62: // LD IXH, D - RegIX.High = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x63: // LD IXH, E - RegIX.High = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x64: // LD IXH, IXH - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // LD IXH, IXL - RegIX.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x66: // LD H, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegHL.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x67: // LD IXH, A - RegIX.High = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x68: // LD IXL, B - RegIX.Low = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x69: // LD IXL, C - RegIX.Low = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6A: // LD IXL, D - RegIX.Low = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6B: // LD IXL, E - RegIX.Low = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6C: // LD IXL, IXH - RegIX.Low = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // LD IXL, IXL - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6E: // LD L, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegHL.Low = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x6F: // LD IXL, A - RegIX.Low = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x70: // LD (IX+d), B - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x71: // LD (IX+d), C - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x72: // LD (IX+d), D - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x73: // LD (IX+d), E - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x74: // LD (IX+d), H - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x75: // LD (IX+d), L - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x76: // HALT - Halt(); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x77: // LD (IX+d), A - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x78: // LD A, B - RegAF.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x79: // LD A, C - RegAF.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7A: // LD A, D - RegAF.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7B: // LD A, E - RegAF.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7C: // LD A, IXH - RegAF.High = RegIX.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // LD A, IXL - RegAF.High = RegIX.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7E: // LD A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.High = ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x7F: // LD A, A - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // ADD A, B - RegAF.Word = TableALU[0, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // ADD A, C - RegAF.Word = TableALU[0, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // ADD A, D - RegAF.Word = TableALU[0, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // ADD A, E - RegAF.Word = TableALU[0, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // ADD A, IXH - RegAF.Word = TableALU[0, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x85: // ADD A, IXL - RegAF.Word = TableALU[0, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x86: // ADD A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[0, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x87: // ADD A, A - RegAF.Word = TableALU[0, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // ADC A, B - RegAF.Word = TableALU[1, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // ADC A, C - RegAF.Word = TableALU[1, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // ADC A, D - RegAF.Word = TableALU[1, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // ADC A, E - RegAF.Word = TableALU[1, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // ADC A, IXH - RegAF.Word = TableALU[1, RegAF.High, RegIX.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8D: // ADC A, IXL - RegAF.Word = TableALU[1, RegAF.High, RegIX.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8E: // ADC A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[1, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x8F: // ADC A, A - RegAF.Word = TableALU[1, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // SUB B - RegAF.Word = TableALU[2, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // SUB C - RegAF.Word = TableALU[2, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // SUB D - RegAF.Word = TableALU[2, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // SUB E - RegAF.Word = TableALU[2, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // SUB IXH - RegAF.Word = TableALU[2, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x95: // SUB IXL - RegAF.Word = TableALU[2, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x96: // SUB (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[2, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x97: // SUB A, A - RegAF.Word = TableALU[2, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // SBC A, B - RegAF.Word = TableALU[3, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // SBC A, C - RegAF.Word = TableALU[3, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // SBC A, D - RegAF.Word = TableALU[3, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // SBC A, E - RegAF.Word = TableALU[3, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // SBC A, IXH - RegAF.Word = TableALU[3, RegAF.High, RegIX.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9D: // SBC A, IXL - RegAF.Word = TableALU[3, RegAF.High, RegIX.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9E: // SBC A, (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[3, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x9F: // SBC A, A - RegAF.Word = TableALU[3, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // AND B - RegAF.Word = TableALU[4, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA1: // AND C - RegAF.Word = TableALU[4, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA2: // AND D - RegAF.Word = TableALU[4, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA3: // AND E - RegAF.Word = TableALU[4, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA4: // AND IXH - RegAF.Word = TableALU[4, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA5: // AND IXL - RegAF.Word = TableALU[4, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA6: // AND (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[4, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xA7: // AND A - RegAF.Word = TableALU[4, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // XOR B - RegAF.Word = TableALU[5, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA9: // XOR C - RegAF.Word = TableALU[5, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAA: // XOR D - RegAF.Word = TableALU[5, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAB: // XOR E - RegAF.Word = TableALU[5, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAC: // XOR IXH - RegAF.Word = TableALU[5, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAD: // XOR IXL - RegAF.Word = TableALU[5, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAE: // XOR (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[5, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xAF: // XOR A - RegAF.Word = TableALU[5, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // OR B - RegAF.Word = TableALU[6, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB1: // OR C - RegAF.Word = TableALU[6, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB2: // OR D - RegAF.Word = TableALU[6, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB3: // OR E - RegAF.Word = TableALU[6, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB4: // OR IXH - RegAF.Word = TableALU[6, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB5: // OR IXL - RegAF.Word = TableALU[6, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB6: // OR (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[6, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xB7: // OR A - RegAF.Word = TableALU[6, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // CP B - RegAF.Word = TableALU[7, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB9: // CP C - RegAF.Word = TableALU[7, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBA: // CP D - RegAF.Word = TableALU[7, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBB: // CP E - RegAF.Word = TableALU[7, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBC: // CP IXH - RegAF.Word = TableALU[7, RegAF.High, RegIX.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBD: // CP IXL - RegAF.Word = TableALU[7, RegAF.High, RegIX.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBE: // CP (IX+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - RegAF.Word = TableALU[7, RegAF.High, ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xBF: // CP A - RegAF.Word = TableALU[7, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // RET NZ - if (!RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC1: // POP BC - RegBC.Low = ReadMemoryWrapper(RegSP.Word++); RegBC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC2: // JP NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC3: // JP nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - RegPC.Word = TUS; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC4: // CALL NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xC5: // PUSH BC - WriteMemoryWrapper(--RegSP.Word, RegBC.High); WriteMemoryWrapper(--RegSP.Word, RegBC.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC6: // ADD A, n - RegAF.Word = TableALU[0, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xC7: // RST $00 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x00; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC8: // RET Z - if (RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC9: // RET - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCA: // JP Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCB: // (Prefix) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIX.Word + Displacement); - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // RLC (IX+d)→B - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x01: // RLC (IX+d)→C - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x02: // RLC (IX+d)→D - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x03: // RLC (IX+d)→E - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x04: // RLC (IX+d)→H - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x05: // RLC (IX+d)→L - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x06: // RLC (IX+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x07: // RLC (IX+d)→A - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x08: // RRC (IX+d)→B - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x09: // RRC (IX+d)→C - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0A: // RRC (IX+d)→D - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0B: // RRC (IX+d)→E - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0C: // RRC (IX+d)→H - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0D: // RRC (IX+d)→L - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0E: // RRC (IX+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0F: // RRC (IX+d)→A - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x10: // RL (IX+d)→B - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x11: // RL (IX+d)→C - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x12: // RL (IX+d)→D - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x13: // RL (IX+d)→E - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x14: // RL (IX+d)→H - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x15: // RL (IX+d)→L - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x16: // RL (IX+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x17: // RL (IX+d)→A - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x18: // RR (IX+d)→B - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x19: // RR (IX+d)→C - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1A: // RR (IX+d)→D - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1B: // RR (IX+d)→E - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1C: // RR (IX+d)→H - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1D: // RR (IX+d)→L - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1E: // RR (IX+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1F: // RR (IX+d)→A - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x20: // SLA (IX+d)→B - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x21: // SLA (IX+d)→C - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x22: // SLA (IX+d)→D - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x23: // SLA (IX+d)→E - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x24: // SLA (IX+d)→H - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x25: // SLA (IX+d)→L - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x26: // SLA (IX+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x27: // SLA (IX+d)→A - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x28: // SRA (IX+d)→B - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x29: // SRA (IX+d)→C - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2A: // SRA (IX+d)→D - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2B: // SRA (IX+d)→E - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2C: // SRA (IX+d)→H - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2D: // SRA (IX+d)→L - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2E: // SRA (IX+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2F: // SRA (IX+d)→A - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x30: // SL1 (IX+d)→B - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x31: // SL1 (IX+d)→C - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x32: // SL1 (IX+d)→D - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x33: // SL1 (IX+d)→E - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x34: // SL1 (IX+d)→H - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // SL1 (IX+d)→L - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // SL1 (IX+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x37: // SL1 (IX+d)→A - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x38: // SRL (IX+d)→B - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x39: // SRL (IX+d)→C - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegBC.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3A: // SRL (IX+d)→D - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3B: // SRL (IX+d)→E - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegDE.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3C: // SRL (IX+d)→H - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3D: // SRL (IX+d)→L - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegHL.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3E: // SRL (IX+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3F: // SRL (IX+d)→A - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIX.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - RegAF.High = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x40: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x41: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x42: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x43: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x45: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x46: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x47: // BIT 0, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x48: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x49: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4A: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4B: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4D: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4E: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4F: // BIT 1, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x50: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x51: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x52: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x53: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x55: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x56: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x57: // BIT 2, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x58: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x59: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5A: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5B: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5D: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5E: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5F: // BIT 3, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x60: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x61: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x62: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x63: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x64: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x65: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x66: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x67: // BIT 4, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x68: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x69: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6A: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6B: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6C: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6D: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6E: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6F: // BIT 5, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x70: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x71: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x72: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x73: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x75: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x76: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x77: // BIT 6, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x78: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x79: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7A: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7B: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7D: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7E: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7F: // BIT 7, (IX+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x80: // RES 0, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x81: // RES 0, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x82: // RES 0, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x83: // RES 0, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x84: // RES 0, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x85: // RES 0, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x86: // RES 0, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x87: // RES 0, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x88: // RES 1, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x89: // RES 1, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8A: // RES 1, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8B: // RES 1, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8C: // RES 1, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8D: // RES 1, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8E: // RES 1, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8F: // RES 1, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x90: // RES 2, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x91: // RES 2, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x92: // RES 2, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x93: // RES 2, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x94: // RES 2, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x95: // RES 2, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x96: // RES 2, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x97: // RES 2, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x98: // RES 3, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x99: // RES 3, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9A: // RES 3, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9B: // RES 3, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9C: // RES 3, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9D: // RES 3, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9E: // RES 3, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9F: // RES 3, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA0: // RES 4, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA1: // RES 4, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA2: // RES 4, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA3: // RES 4, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA4: // RES 4, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA5: // RES 4, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA6: // RES 4, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA7: // RES 4, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA8: // RES 5, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA9: // RES 5, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAA: // RES 5, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAB: // RES 5, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAC: // RES 5, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAD: // RES 5, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAE: // RES 5, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAF: // RES 5, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB0: // RES 6, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB1: // RES 6, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB2: // RES 6, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB3: // RES 6, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB4: // RES 6, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB5: // RES 6, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB6: // RES 6, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB7: // RES 6, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB8: // RES 7, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB9: // RES 7, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBA: // RES 7, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBB: // RES 7, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBC: // RES 7, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBD: // RES 7, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBE: // RES 7, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBF: // RES 7, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) & unchecked((byte)~0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC0: // SET 0, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC1: // SET 0, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC2: // SET 0, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC3: // SET 0, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC4: // SET 0, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC5: // SET 0, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC6: // SET 0, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC7: // SET 0, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x01)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC8: // SET 1, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC9: // SET 1, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCA: // SET 1, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCB: // SET 1, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCC: // SET 1, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCD: // SET 1, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCE: // SET 1, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCF: // SET 1, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x02)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD0: // SET 2, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD1: // SET 2, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD2: // SET 2, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD3: // SET 2, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD4: // SET 2, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD5: // SET 2, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD6: // SET 2, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD7: // SET 2, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x04)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD8: // SET 3, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD9: // SET 3, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDA: // SET 3, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDB: // SET 3, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDC: // SET 3, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDD: // SET 3, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDE: // SET 3, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDF: // SET 3, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x08)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE0: // SET 4, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE1: // SET 4, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE2: // SET 4, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE3: // SET 4, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // SET 4, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE5: // SET 4, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE6: // SET 4, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE7: // SET 4, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x10)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE8: // SET 5, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE9: // SET 5, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEA: // SET 5, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEB: // SET 5, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEC: // SET 5, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xED: // SET 5, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEE: // SET 5, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEF: // SET 5, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x20)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF0: // SET 6, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF1: // SET 6, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF2: // SET 6, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF3: // SET 6, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF4: // SET 6, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF5: // SET 6, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF6: // SET 6, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF7: // SET 6, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x40)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF8: // SET 7, (IX+d)→B - RegBC.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF9: // SET 7, (IX+d)→C - RegBC.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegBC.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFA: // SET 7, (IX+d)→D - RegDE.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFB: // SET 7, (IX+d)→E - RegDE.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegDE.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFC: // SET 7, (IX+d)→H - RegHL.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFD: // SET 7, (IX+d)→L - RegHL.Low = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegHL.Low); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFE: // SET 7, (IX+d) - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFF: // SET 7, (IX+d)→A - RegAF.High = (byte)(ReadMemoryWrapper((ushort)(RegIX.Word + Displacement)) | unchecked((byte)0x80)); - WriteMemoryWrapper((ushort)(RegIX.Word + Displacement), RegAF.High); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - } - break; - case 0xCC: // CALL Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xCD: // CALL nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - break; - case 0xCE: // ADC A, n - RegAF.Word = TableALU[1, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xCF: // RST $08 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x08; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD0: // RET NC - if (!RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD1: // POP DE - RegDE.Low = ReadMemoryWrapper(RegSP.Word++); RegDE.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD2: // JP NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD3: // OUT n, A - WriteHardware(FetchMemoryWrapper(RegPC.Word++), RegAF.High); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD4: // CALL NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xD5: // PUSH DE - WriteMemoryWrapper(--RegSP.Word, RegDE.High); WriteMemoryWrapper(--RegSP.Word, RegDE.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD6: // SUB n - RegAF.Word = TableALU[2, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xD7: // RST $10 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x10; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD8: // RET C - if (RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD9: // EXX - TUS = RegBC.Word; RegBC.Word = RegAltBC.Word; RegAltBC.Word = TUS; - TUS = RegDE.Word; RegDE.Word = RegAltDE.Word; RegAltDE.Word = TUS; - TUS = RegHL.Word; RegHL.Word = RegAltHL.Word; RegAltHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // JP C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xDB: // IN A, n - RegAF.High = ReadHardware((ushort)FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xDC: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xDD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xDE: // SBC A, n - RegAF.Word = TableALU[3, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xDF: // RST $18 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x18; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE0: // RET PO - if (!RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE1: // POP IX - RegIX.Low = ReadMemoryWrapper(RegSP.Word++); RegIX.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0xE2: // JP PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE3: // EX (SP), IX - TUS = RegSP.Word; TBL = ReadMemoryWrapper(TUS++); TBH = ReadMemoryWrapper(TUS--); - WriteMemoryWrapper(TUS++, RegIX.Low); WriteMemoryWrapper(TUS, RegIX.High); - RegIX.Low = TBL; RegIX.High = TBH; - RegWZ = RegIX; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xE5: // PUSH IX - WriteMemoryWrapper(--RegSP.Word, RegIX.High); WriteMemoryWrapper(--RegSP.Word, RegIX.Low); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xE6: // AND n - RegAF.Word = TableALU[4, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xE7: // RST $20 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x20; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE8: // RET PE - if (RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE9: // JP IX - RegWZ = RegIX; - RegPC.Word = RegIX.Word; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEA: // JP PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xEB: // EX DE, HL - TUS = RegDE.Word; RegDE.Word = RegHL.Word; RegHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // CALL PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xED: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x02: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x03: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x04: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x07: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x11: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x12: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x13: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x14: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x17: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x19: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x21: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x22: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x23: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x24: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x27: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x29: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x31: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x32: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x33: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x34: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x35: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x36: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x37: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x39: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // IN B, C - RegBC.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.High > 127; - RegFlagZ = RegBC.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x41: // OUT C, B - WriteHardware(RegBC.Low, RegBC.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x42: // SBC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegBC.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegBC.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x43: // LD (nn), BC - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegBC.Low); - WriteMemoryWrapper(TUS, RegBC.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x46: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x47: // LD I, A - RegI = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x48: // IN C, C - RegBC.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.Low > 127; - RegFlagZ = RegBC.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x49: // OUT C, C - WriteHardware(RegBC.Low, RegBC.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4A: // ADC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x4B: // LD BC, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegBC.Low = ReadMemoryWrapper(TUS++); RegBC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x4E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4F: // LD R, A - RegR = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x50: // IN D, C - RegDE.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.High > 127; - RegFlagZ = RegDE.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x51: // OUT C, D - WriteHardware(RegBC.Low, RegDE.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x52: // SBC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegDE.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegDE.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x53: // LD (nn), DE - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegDE.Low); - WriteMemoryWrapper(TUS, RegDE.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x56: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x57: // LD A, I - RegAF.High = RegI; - RegFlagS = RegI > 127; - RegFlagZ = RegI == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x58: // IN E, C - RegDE.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.Low > 127; - RegFlagZ = RegDE.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x59: // OUT C, E - WriteHardware(RegBC.Low, RegDE.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5A: // ADC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x5B: // LD DE, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegDE.Low = ReadMemoryWrapper(TUS++); RegDE.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x5E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5F: // LD A, R - RegAF.High = (byte)(RegR & 0x7F); - RegFlagS = (byte)(RegR & 0x7F) > 127; - RegFlagZ = (byte)(RegR & 0x7F) == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x60: // IN H, C - RegHL.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.High > 127; - RegFlagZ = RegHL.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x61: // OUT C, H - WriteHardware(RegBC.Low, RegHL.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x62: // SBC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegHL.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegHL.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x63: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x64: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x66: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x67: // RRD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB2 >> 4) + (TB1 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 & 0x0F)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x68: // IN L, C - RegHL.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.Low > 127; - RegFlagZ = RegHL.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x69: // OUT C, L - WriteHardware(RegBC.Low, RegHL.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6A: // ADC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x6B: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x6C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x6E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6F: // RLD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB1 & 0x0F) + (TB2 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 >> 4)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x70: // IN 0, C - TB = ReadHardware((ushort)RegBC.Low); - RegFlagS = TB > 127; - RegFlagZ = TB == 0; - RegFlagH = false; - RegFlagP = TableParity[TB]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x71: // OUT C, 0 - WriteHardware(RegBC.Low, 0); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x72: // SBC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegSP.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegSP.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x73: // LD (nn), SP - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegSP.Low); - WriteMemoryWrapper(TUS, RegSP.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x76: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x77: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x78: // IN A, C - RegAF.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x79: // OUT C, A - WriteHardware(RegBC.Low, RegAF.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7A: // ADC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x7B: // LD SP, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegSP.Low = ReadMemoryWrapper(TUS++); RegSP.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x7E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x87: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x97: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // LDI - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA1: // CPI - RegWZ = (ushort)(RegWZ + 1); - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA2: // INI - RegWZ = (ushort)(RegBC + 1); - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA3: // OUTI - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // LDD - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA9: // CPD - RegWZ = (ushort)(RegWZ - 1); - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAA: // IND - RegWZ = (ushort)(RegBC - 1); - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAB: // OUTD - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // LDIR - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB1: // CPIR - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB2: // INIR - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB3: // OTIR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // LDDR - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB9: // CPDR - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBA: // INDR - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBB: // OTDR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xED: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - } - break; - case 0xEE: // XOR n - RegAF.Word = TableALU[5, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xEF: // RST $28 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x28; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF0: // RET P - if (!RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF1: // POP AF - RegAF.Low = ReadMemoryWrapper(RegSP.Word++); RegAF.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF2: // JP P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF3: // DI - IFF1 = IFF2 = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // CALL P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xF5: // PUSH AF - WriteMemoryWrapper(--RegSP.Word, RegAF.High); WriteMemoryWrapper(--RegSP.Word, RegAF.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF6: // OR n - RegAF.Word = TableALU[6, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xF7: // RST $30 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x30; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF8: // RET M - if (RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF9: // LD SP, IX - RegSP.Word = RegIX.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFA: // JP M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFB: // EI - EI_pending = 2; - Interruptable = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // CALL M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xFD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xFE: // CP n - RegAF.Word = TableALU[7, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xFF: // RST $38 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - } - break; - case 0xDE: // SBC A, n - RegAF.Word = TableALU[3, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xDF: // RST $18 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x18; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE0: // RET PO - if (!RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE1: // POP HL - RegHL.Low = ReadMemoryWrapper(RegSP.Word++); RegHL.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE2: // JP PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE3: // EX (SP), HL - TUS = RegSP.Word; TBL = ReadMemoryWrapper(TUS++); TBH = ReadMemoryWrapper(TUS--); - WriteMemoryWrapper(TUS++, RegHL.Low); WriteMemoryWrapper(TUS, RegHL.High); - RegHL.Low = TBL; RegHL.High = TBH; - RegWZ = RegHL; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xE4: // CALL PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xE5: // PUSH HL - WriteMemoryWrapper(--RegSP.Word, RegHL.High); WriteMemoryWrapper(--RegSP.Word, RegHL.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE6: // AND n - RegAF.Word = TableALU[4, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xE7: // RST $20 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x20; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE8: // RET PE - if (RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE9: // JP HL - RegWZ = RegHL; - RegPC.Word = RegHL.Word; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // JP PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xEB: // EX DE, HL - TUS = RegDE.Word; RegDE.Word = RegHL.Word; RegHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // CALL PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xED: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x02: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x03: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x04: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x07: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x11: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x12: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x13: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x14: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x17: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x19: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x21: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x22: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x23: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x24: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x27: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x29: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x31: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x32: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x33: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x34: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x35: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x36: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x37: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x39: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // IN B, C - RegBC.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.High > 127; - RegFlagZ = RegBC.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x41: // OUT C, B - WriteHardware(RegBC.Low, RegBC.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x42: // SBC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegBC.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegBC.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x43: // LD (nn), BC - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegBC.Low); - WriteMemoryWrapper(TUS, RegBC.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x46: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x47: // LD I, A - RegI = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x48: // IN C, C - RegBC.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.Low > 127; - RegFlagZ = RegBC.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x49: // OUT C, C - WriteHardware(RegBC.Low, RegBC.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4A: // ADC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x4B: // LD BC, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegBC.Low = ReadMemoryWrapper(TUS++); RegBC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x4E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4F: // LD R, A - RegR = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x50: // IN D, C - RegDE.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.High > 127; - RegFlagZ = RegDE.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x51: // OUT C, D - WriteHardware(RegBC.Low, RegDE.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x52: // SBC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegDE.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegDE.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x53: // LD (nn), DE - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegDE.Low); - WriteMemoryWrapper(TUS, RegDE.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x56: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x57: // LD A, I - RegAF.High = RegI; - RegFlagS = RegI > 127; - RegFlagZ = RegI == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x58: // IN E, C - RegDE.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.Low > 127; - RegFlagZ = RegDE.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x59: // OUT C, E - WriteHardware(RegBC.Low, RegDE.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5A: // ADC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x5B: // LD DE, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegDE.Low = ReadMemoryWrapper(TUS++); RegDE.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x5E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5F: // LD A, R - RegAF.High = (byte)(RegR & 0x7F); - RegFlagS = (byte)(RegR & 0x7F) > 127; - RegFlagZ = (byte)(RegR & 0x7F) == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x60: // IN H, C - RegHL.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.High > 127; - RegFlagZ = RegHL.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x61: // OUT C, H - WriteHardware(RegBC.Low, RegHL.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x62: // SBC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegHL.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegHL.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x63: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x64: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x66: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x67: // RRD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB2 >> 4) + (TB1 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 & 0x0F)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x68: // IN L, C - RegHL.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.Low > 127; - RegFlagZ = RegHL.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x69: // OUT C, L - WriteHardware(RegBC.Low, RegHL.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6A: // ADC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x6B: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x6E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6F: // RLD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB1 & 0x0F) + (TB2 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 >> 4)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x70: // IN 0, C - TB = ReadHardware((ushort)RegBC.Low); - RegFlagS = TB > 127; - RegFlagZ = TB == 0; - RegFlagH = false; - RegFlagP = TableParity[TB]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x71: // OUT C, 0 - WriteHardware(RegBC.Low, 0); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x72: // SBC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegSP.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegSP.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x73: // LD (nn), SP - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegSP.Low); - WriteMemoryWrapper(TUS, RegSP.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x76: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x77: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x78: // IN A, C - RegAF.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x79: // OUT C, A - WriteHardware(RegBC.Low, RegAF.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7A: // ADC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x7B: // LD SP, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegSP.Low = ReadMemoryWrapper(TUS++); RegSP.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x7E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x87: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x97: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // LDI - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA1: // CPI - RegWZ = (ushort)(RegWZ + 1); - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA2: // INI - RegWZ = (ushort)(RegBC + 1); - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA3: // OUTI - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // LDD - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA9: // CPD - RegWZ = (ushort)(RegWZ - 1); - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAA: // IND - RegWZ = (ushort)(RegBC - 1); - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAB: // OUTD - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // LDIR - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB1: // CPIR - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB2: // INIR - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB3: // OTIR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // LDDR - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB9: // CPDR - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBA: // INDR - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBB: // OTDR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xED: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - } - break; - case 0xEE: // XOR n - RegAF.Word = TableALU[5, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xEF: // RST $28 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x28; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF0: // RET P - if (!RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF1: // POP AF - RegAF.Low = ReadMemoryWrapper(RegSP.Word++); RegAF.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF2: // JP P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF3: // DI - IFF1 = IFF2 = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // CALL P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xF5: // PUSH AF - WriteMemoryWrapper(--RegSP.Word, RegAF.High); WriteMemoryWrapper(--RegSP.Word, RegAF.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF6: // OR n - RegAF.Word = TableALU[6, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xF7: // RST $30 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x30; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF8: // RET M - if (RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF9: // LD SP, HL - RegSP.Word = RegHL.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0xFA: // JP M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFB: // EI - EI_pending = 2; - Interruptable = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // CALL M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xFD: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // LD BC, nn - RegBC.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x02: // LD (BC), A - RegWZ.Low = (byte)((RegBC.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegBC.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x03: // INC BC - ++RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x04: // INC B - RegAF.Low = (byte)(TableInc[++RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // DEC B - RegAF.Low = (byte)(TableDec[--RegBC.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // LD B, n - RegBC.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x07: // RLCA - RegAF.Word = TableRotShift[0, 0, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // EX AF, AF' - TUS = RegAF.Word; RegAF.Word = RegAltAF.Word; RegAltAF.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // ADD IY, BC - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x0A: // LD A, (BC) - RegAF.High = ReadMemoryWrapper(RegBC.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegBC.Word + 1); - break; - case 0x0B: // DEC BC - --RegBC.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x0C: // INC C - RegAF.Low = (byte)(TableInc[++RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // DEC C - RegAF.Low = (byte)(TableDec[--RegBC.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // LD C, n - RegBC.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x0F: // RRCA - RegAF.Word = TableRotShift[0, 1, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // DJNZ d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (--RegBC.High != 0) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 13; pendingCycles -= 13; - } - else - { - totalExecutedCycles += 8; pendingCycles -= 8; - } - break; - case 0x11: // LD DE, nn - RegDE.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x12: // LD (DE), A - RegWZ.Low = (byte)((RegDE.Word + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(RegDE.Word, RegAF.High); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x13: // INC DE - ++RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x14: // INC D - RegAF.Low = (byte)(TableInc[++RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // DEC D - RegAF.Low = (byte)(TableDec[--RegDE.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // LD D, n - RegDE.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x17: // RLA - RegAF.Word = TableRotShift[0, 2, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // JR d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x19: // ADD IY, DE - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x1A: // LD A, (DE) - RegAF.High = ReadMemoryWrapper(RegDE.Word); - totalExecutedCycles += 7; pendingCycles -= 7; - RegWZ = (ushort)(RegDE.Word + 1); - break; - case 0x1B: // DEC DE - --RegDE.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x1C: // INC E - RegAF.Low = (byte)(TableInc[++RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // DEC E - RegAF.Low = (byte)(TableDec[--RegDE.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // LD E, n - RegDE.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x1F: // RRA - RegAF.Word = TableRotShift[0, 3, RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // JR NZ, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x21: // LD IY, nn - RegIY.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x22: // LD (nn), IY - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegIY.Low); - WriteMemoryWrapper(TUS, RegIY.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x23: // INC IY - ++RegIY.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x24: // INC IYH - RegAF.Low = (byte)(TableInc[++RegIY.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x25: // DEC IYH - RegAF.Low = (byte)(TableDec[--RegIY.High] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x26: // LD IYH, n - RegIY.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x27: // DAA - RegAF.Word = TableDaa[RegAF.Word]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // JR Z, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagZ) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x29: // ADD IY, IY - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegIY.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x2A: // LD IY, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegIY.Low = ReadMemoryWrapper(TUS++); RegIY.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x2B: // DEC IY - --RegIY.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x2C: // INC IYL - RegAF.Low = (byte)(TableInc[++RegIY.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2D: // DEC IYL - RegAF.Low = (byte)(TableDec[--RegIY.Low] | (RegAF.Low & 1)); - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x2E: // LD IYL, n - RegIY.Low = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0x2F: // CPL - RegAF.High ^= 0xFF; RegFlagH = true; RegFlagN = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // JR NC, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (!RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x31: // LD SP, nn - RegSP.Word = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0x32: // LD (nn), A - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ.Low = (byte)((temp_WZ + 1) & 0xFF); - RegWZ.High = RegAF.High; - WriteMemoryWrapper(temp_WZ, RegAF.High); - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 0x33: // INC SP - ++RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x34: // INC (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); RegAF.Low = (byte)(TableInc[++TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // DEC (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - TB = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); RegAF.Low = (byte)(TableDec[--TB] | (RegAF.Low & 1)); WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), TB); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // LD (IY+d), n - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x37: // SCF - RegFlagH = false; RegFlagN = false; RegFlagC = true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // JR C, d - TSB = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegPC.Word + TSB); - if (RegFlagC) - { - RegPC.Word = (ushort)(RegPC.Word + TSB); - totalExecutedCycles += 12; pendingCycles -= 12; - } - else - { - totalExecutedCycles += 7; pendingCycles -= 7; - } - break; - case 0x39: // ADD IY, SP - RegWZ = (ushort)(RegIY + 1); - TI1 = (short)RegIY.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegIY.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x3A: // LD A, (nn) - temp_WZ = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegAF.High = ReadMemoryWrapper(temp_WZ); - totalExecutedCycles += 13; pendingCycles -= 13; - RegWZ = (ushort)(temp_WZ + 1); - break; - case 0x3B: // DEC SP - --RegSP.Word; - totalExecutedCycles += 6; pendingCycles -= 6; - break; - case 0x3C: // INC A - RegAF.Low = (byte)(TableInc[++RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // DEC A - RegAF.Low = (byte)(TableDec[--RegAF.High] | (RegAF.Low & 1)); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // LD A, n - RegAF.High = FetchMemoryWrapper(RegPC.Word++); - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0x3F: // CCF - RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true; RegFlag3 = (RegAF.High & 0x08) != 0; RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // LD B, B - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x41: // LD B, C - RegBC.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x42: // LD B, D - RegBC.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x43: // LD B, E - RegBC.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x44: // LD B, IYH - RegBC.High = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // LD B, IYL - RegBC.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x46: // LD B, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegBC.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x47: // LD B, A - RegBC.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x48: // LD C, B - RegBC.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x49: // LD C, C - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4A: // LD C, D - RegBC.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4B: // LD C, E - RegBC.Low = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x4C: // LD C, IYH - RegBC.Low = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // LD C, IYL - RegBC.Low = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4E: // LD C, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegBC.Low = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x4F: // LD C, A - RegBC.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x50: // LD D, B - RegDE.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x51: // LD D, C - RegDE.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x52: // LD D, D - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x53: // LD D, E - RegDE.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x54: // LD D, IYH - RegDE.High = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // LD D, IYL - RegDE.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x56: // LD D, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegDE.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x57: // LD D, A - RegDE.High = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x58: // LD E, B - RegDE.Low = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x59: // LD E, C - RegDE.Low = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5A: // LD E, D - RegDE.Low = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5B: // LD E, E - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x5C: // LD E, IYH - RegDE.Low = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // LD E, IYL - RegDE.Low = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5E: // LD E, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegDE.Low = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x5F: // LD E, A - RegDE.Low = RegAF.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x60: // LD IYH, B - RegIY.High = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x61: // LD IYH, C - RegIY.High = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x62: // LD IYH, D - RegIY.High = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x63: // LD IYH, E - RegIY.High = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x64: // LD IYH, IYH - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // LD IYH, IYL - RegIY.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x66: // LD H, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegHL.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x67: // LD IYH, A - RegIY.High = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x68: // LD IYL, B - RegIY.Low = RegBC.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x69: // LD IYL, C - RegIY.Low = RegBC.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6A: // LD IYL, D - RegIY.Low = RegDE.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6B: // LD IYL, E - RegIY.Low = RegDE.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6C: // LD IYL, IYH - RegIY.Low = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // LD IYL, IYL - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6E: // LD L, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegHL.Low = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x6F: // LD IYL, A - RegIY.Low = RegAF.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x70: // LD (IY+d), B - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegBC.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x71: // LD (IY+d), C - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegBC.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x72: // LD (IY+d), D - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegDE.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x73: // LD (IY+d), E - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegDE.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x74: // LD (IY+d), H - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegHL.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x75: // LD (IY+d), L - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegHL.Low); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x76: // HALT - Halt(); - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x77: // LD (IY+d), A - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), RegAF.High); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x78: // LD A, B - RegAF.High = RegBC.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x79: // LD A, C - RegAF.High = RegBC.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7A: // LD A, D - RegAF.High = RegDE.High; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7B: // LD A, E - RegAF.High = RegDE.Low; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x7C: // LD A, IYH - RegAF.High = RegIY.High; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // LD A, IYL - RegAF.High = RegIY.Low; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7E: // LD A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.High = ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x7F: // LD A, A - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // ADD A, B - RegAF.Word = TableALU[0, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // ADD A, C - RegAF.Word = TableALU[0, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // ADD A, D - RegAF.Word = TableALU[0, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // ADD A, E - RegAF.Word = TableALU[0, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // ADD A, IYH - RegAF.Word = TableALU[0, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x85: // ADD A, IYL - RegAF.Word = TableALU[0, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x86: // ADD A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[0, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x87: // ADD A, A - RegAF.Word = TableALU[0, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // ADC A, B - RegAF.Word = TableALU[1, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // ADC A, C - RegAF.Word = TableALU[1, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // ADC A, D - RegAF.Word = TableALU[1, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // ADC A, E - RegAF.Word = TableALU[1, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // ADC A, IYH - RegAF.Word = TableALU[1, RegAF.High, RegIY.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8D: // ADC A, IYL - RegAF.Word = TableALU[1, RegAF.High, RegIY.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x8E: // ADC A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[1, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x8F: // ADC A, A - RegAF.Word = TableALU[1, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // SUB B - RegAF.Word = TableALU[2, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // SUB C - RegAF.Word = TableALU[2, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // SUB D - RegAF.Word = TableALU[2, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // SUB E - RegAF.Word = TableALU[2, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // SUB IYH - RegAF.Word = TableALU[2, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x95: // SUB IYL - RegAF.Word = TableALU[2, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x96: // SUB (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[2, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x97: // SUB A, A - RegAF.Word = TableALU[2, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // SBC A, B - RegAF.Word = TableALU[3, RegAF.High, RegBC.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // SBC A, C - RegAF.Word = TableALU[3, RegAF.High, RegBC.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // SBC A, D - RegAF.Word = TableALU[3, RegAF.High, RegDE.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // SBC A, E - RegAF.Word = TableALU[3, RegAF.High, RegDE.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // SBC A, IYH - RegAF.Word = TableALU[3, RegAF.High, RegIY.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9D: // SBC A, IYL - RegAF.Word = TableALU[3, RegAF.High, RegIY.Low, RegFlagC ? 1 : 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x9E: // SBC A, (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[3, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), RegFlagC ? 1 : 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0x9F: // SBC A, A - RegAF.Word = TableALU[3, RegAF.High, RegAF.High, RegFlagC ? 1 : 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // AND B - RegAF.Word = TableALU[4, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA1: // AND C - RegAF.Word = TableALU[4, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA2: // AND D - RegAF.Word = TableALU[4, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA3: // AND E - RegAF.Word = TableALU[4, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA4: // AND IYH - RegAF.Word = TableALU[4, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA5: // AND IYL - RegAF.Word = TableALU[4, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xA6: // AND (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[4, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xA7: // AND A - RegAF.Word = TableALU[4, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // XOR B - RegAF.Word = TableALU[5, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA9: // XOR C - RegAF.Word = TableALU[5, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAA: // XOR D - RegAF.Word = TableALU[5, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAB: // XOR E - RegAF.Word = TableALU[5, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAC: // XOR IYH - RegAF.Word = TableALU[5, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAD: // XOR IYL - RegAF.Word = TableALU[5, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xAE: // XOR (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[5, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xAF: // XOR A - RegAF.Word = TableALU[5, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // OR B - RegAF.Word = TableALU[6, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB1: // OR C - RegAF.Word = TableALU[6, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB2: // OR D - RegAF.Word = TableALU[6, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB3: // OR E - RegAF.Word = TableALU[6, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB4: // OR IYH - RegAF.Word = TableALU[6, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB5: // OR IYL - RegAF.Word = TableALU[6, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xB6: // OR (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[6, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xB7: // OR A - RegAF.Word = TableALU[6, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // CP B - RegAF.Word = TableALU[7, RegAF.High, RegBC.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB9: // CP C - RegAF.Word = TableALU[7, RegAF.High, RegBC.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBA: // CP D - RegAF.Word = TableALU[7, RegAF.High, RegDE.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBB: // CP E - RegAF.Word = TableALU[7, RegAF.High, RegDE.Low, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBC: // CP IYH - RegAF.Word = TableALU[7, RegAF.High, RegIY.High, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBD: // CP IYL - RegAF.Word = TableALU[7, RegAF.High, RegIY.Low, 0]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xBE: // CP (IY+d) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - RegAF.Word = TableALU[7, RegAF.High, ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)), 0]; - totalExecutedCycles += 19; pendingCycles -= 19; - break; - case 0xBF: // CP A - RegAF.Word = TableALU[7, RegAF.High, RegAF.High, 0]; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // RET NZ - if (!RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC1: // POP BC - RegBC.Low = ReadMemoryWrapper(RegSP.Word++); RegBC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC2: // JP NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC3: // JP nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - RegPC.Word = TUS; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xC4: // CALL NZ, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xC5: // PUSH BC - WriteMemoryWrapper(--RegSP.Word, RegBC.High); WriteMemoryWrapper(--RegSP.Word, RegBC.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC6: // ADD A, n - RegAF.Word = TableALU[0, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xC7: // RST $00 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x00; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xC8: // RET Z - if (RegFlagZ) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xC9: // RET - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCA: // JP Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xCB: // (Prefix) - Displacement = (sbyte)FetchMemoryWrapper(RegPC.Word++); - RegWZ = (ushort)(RegIY.Word + Displacement); - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // RLC (IY+d) - RegWZ = (ushort)(RegIY.Word + Displacement); - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x01: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x02: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x03: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x04: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x05: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x06: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x07: // RLC (IY+d) - TUS = TableRotShift[1, 0, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x08: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x09: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0A: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0B: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0C: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0D: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0E: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x0F: // RRC (IY+d) - TUS = TableRotShift[1, 1, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x10: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x11: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x12: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x13: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x14: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x15: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x16: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x17: // RL (IY+d) - TUS = TableRotShift[1, 2, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x18: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x19: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1A: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1B: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1C: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1D: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1E: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x1F: // RR (IY+d) - TUS = TableRotShift[1, 3, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x20: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x21: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x22: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x23: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x24: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x25: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x26: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x27: // SLA (IY+d) - TUS = TableRotShift[1, 4, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x28: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x29: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2A: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2B: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2C: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2D: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2E: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x2F: // SRA (IY+d) - TUS = TableRotShift[1, 5, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x30: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x31: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x32: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x33: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x34: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x35: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x36: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x37: // SL1 (IY+d) - TUS = TableRotShift[1, 6, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x38: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x39: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3A: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3B: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3C: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3D: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3E: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x3F: // SRL (IY+d) - TUS = TableRotShift[1, 7, RegAF.Low + 256 * ReadMemoryWrapper((ushort)(RegIY.Word + Displacement))]; - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(TUS >> 8)); - RegAF.Low = (byte)TUS; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x40: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x41: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x42: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x43: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x45: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x46: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x47: // BIT 0, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x01) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x48: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x49: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4A: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4B: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4D: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4E: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4F: // BIT 1, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x02) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x50: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x51: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x52: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x53: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x55: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x56: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x57: // BIT 2, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x04) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x58: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x59: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5A: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5B: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5D: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5E: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5F: // BIT 3, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x08) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x60: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x61: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x62: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x63: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x64: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x65: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x66: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x67: // BIT 4, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x10) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x68: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x69: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6A: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6B: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6C: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6D: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6E: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x6F: // BIT 5, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x20) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x70: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x71: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x72: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x73: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x75: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x76: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x77: // BIT 6, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x40) == 0; - RegFlagP = RegFlagZ; - RegFlagS = false; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x78: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x79: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7A: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7B: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7D: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7E: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7F: // BIT 7, (IY+d) - RegFlagZ = (ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & 0x80) == 0; - RegFlagP = RegFlagZ; - RegFlagS = !RegFlagZ; - RegFlag3 = RegWZ.High.Bit(3); - RegFlag5 = RegWZ.High.Bit(5); - RegFlagH = true; - RegFlagN = false; - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x80: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x81: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x82: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x83: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x84: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x85: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x86: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x87: // RES 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x88: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x89: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8A: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8B: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8C: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8D: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8E: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x8F: // RES 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x90: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x91: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x92: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x93: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x94: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x95: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x96: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x97: // RES 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x98: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x99: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9A: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9B: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9C: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9D: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9E: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0x9F: // RES 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA0: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA1: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA2: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA3: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA4: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA5: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA6: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA7: // RES 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA8: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xA9: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAA: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAB: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAC: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAD: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAE: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xAF: // RES 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB0: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB1: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB2: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB3: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB4: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB5: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB6: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB7: // RES 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB8: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xB9: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBA: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBB: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBC: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBD: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBE: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xBF: // RES 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) & unchecked((byte)~0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC0: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC1: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC2: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC3: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC4: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC5: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC6: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC7: // SET 0, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x01))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC8: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xC9: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCA: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCB: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCC: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCD: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCE: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xCF: // SET 1, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x02))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD0: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD1: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD2: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD3: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD4: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD5: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD6: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD7: // SET 2, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x04))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD8: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xD9: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDA: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDB: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDC: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDD: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDE: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xDF: // SET 3, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x08))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE0: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE1: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE2: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE3: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE5: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE6: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE7: // SET 4, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x10))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE8: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE9: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEA: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEB: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEC: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xED: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEE: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xEF: // SET 5, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x20))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF0: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF1: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF2: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF3: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF4: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF5: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF6: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF7: // SET 6, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x40))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF8: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xF9: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFA: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFB: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFC: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFD: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFE: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xFF: // SET 7, (IY+d) - WriteMemoryWrapper((ushort)(RegIY.Word + Displacement), (byte)(ReadMemoryWrapper((ushort)(RegIY.Word + Displacement)) | unchecked((byte)0x80))); - totalExecutedCycles += 23; pendingCycles -= 23; - break; - } - break; - case 0xCC: // CALL Z, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagZ) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xCD: // CALL nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - break; - case 0xCE: // ADC A, n - RegAF.Word = TableALU[1, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xCF: // RST $08 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x08; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD0: // RET NC - if (!RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD1: // POP DE - RegDE.Low = ReadMemoryWrapper(RegSP.Word++); RegDE.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD2: // JP NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xD3: // OUT n, A - WriteHardware(FetchMemoryWrapper(RegPC.Word++), RegAF.High); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD4: // CALL NC, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xD5: // PUSH DE - WriteMemoryWrapper(--RegSP.Word, RegDE.High); WriteMemoryWrapper(--RegSP.Word, RegDE.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD6: // SUB n - RegAF.Word = TableALU[2, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xD7: // RST $10 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x10; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xD8: // RET C - if (RegFlagC) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xD9: // EXX - TUS = RegBC.Word; RegBC.Word = RegAltBC.Word; RegAltBC.Word = TUS; - TUS = RegDE.Word; RegDE.Word = RegAltDE.Word; RegAltDE.Word = TUS; - TUS = RegHL.Word; RegHL.Word = RegAltHL.Word; RegAltHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // JP C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xDB: // IN A, n - RegAF.High = ReadHardware((ushort)FetchMemoryWrapper(RegPC.Word++)); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xDC: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xDD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xDE: // SBC A, n - RegAF.Word = TableALU[3, RegAF.High, FetchMemoryWrapper(RegPC.Word++), RegFlagC ? 1 : 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xDF: // RST $18 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x18; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE0: // RET PO - if (!RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE1: // POP IY - RegIY.Low = ReadMemoryWrapper(RegSP.Word++); RegIY.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0xE2: // JP PO, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xE3: // EX (SP), IY - TUS = RegSP.Word; TBL = ReadMemoryWrapper(TUS++); TBH = ReadMemoryWrapper(TUS--); - WriteMemoryWrapper(TUS++, RegIY.Low); WriteMemoryWrapper(TUS, RegIY.High); - RegIY.Low = TBL; RegIY.High = TBH; - RegWZ = RegIY; - totalExecutedCycles += 23; pendingCycles -= 23; - break; - case 0xE4: // CALL C, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagC) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xE5: // PUSH IY - WriteMemoryWrapper(--RegSP.Word, RegIY.High); WriteMemoryWrapper(--RegSP.Word, RegIY.Low); - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0xE6: // AND n - RegAF.Word = TableALU[4, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xE7: // RST $20 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x20; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xE8: // RET PE - if (RegFlagP) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xE9: // JP IY - RegWZ = RegIY; - RegPC.Word = RegIY.Word; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0xEA: // JP PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xEB: // EX DE, HL - TUS = RegDE.Word; RegDE.Word = RegHL.Word; RegHL.Word = TUS; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // CALL PE, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagP) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xED: // (Prefix) - ++RegR; - switch (FetchMemoryWrapper(RegPC.Word++)) - { - case 0x00: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x01: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x02: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x03: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x04: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x05: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x06: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x07: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x08: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x09: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x0F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x10: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x11: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x12: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x13: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x14: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x15: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x16: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x17: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x18: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x19: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x1F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x20: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x21: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x22: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x23: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x24: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x25: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x26: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x27: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x28: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x29: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x2F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x30: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x31: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x32: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x33: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x34: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x35: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x36: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x37: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x38: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x39: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x3F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x40: // IN B, C - RegBC.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.High > 127; - RegFlagZ = RegBC.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x41: // OUT C, B - WriteHardware(RegBC.Low, RegBC.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x42: // SBC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegBC.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegBC.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x43: // LD (nn), BC - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegBC.Low); - WriteMemoryWrapper(TUS, RegBC.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x44: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x45: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x46: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x47: // LD I, A - RegI = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x48: // IN C, C - RegBC.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegBC.Low > 127; - RegFlagZ = RegBC.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegBC.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x49: // OUT C, C - WriteHardware(RegBC.Low, RegBC.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x4A: // ADC HL, BC - TI1 = (short)RegHL.Word; TI2 = (short)RegBC.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x4B: // LD BC, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegBC.Low = ReadMemoryWrapper(TUS++); RegBC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x4C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x4E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x4F: // LD R, A - RegR = RegAF.High; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x50: // IN D, C - RegDE.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.High > 127; - RegFlagZ = RegDE.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x51: // OUT C, D - WriteHardware(RegBC.Low, RegDE.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x52: // SBC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegDE.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegDE.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x53: // LD (nn), DE - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegDE.Low); - WriteMemoryWrapper(TUS, RegDE.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x54: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x55: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x56: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x57: // LD A, I - RegAF.High = RegI; - RegFlagS = RegI > 127; - RegFlagZ = RegI == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x58: // IN E, C - RegDE.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegDE.Low > 127; - RegFlagZ = RegDE.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegDE.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x59: // OUT C, E - WriteHardware(RegBC.Low, RegDE.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x5A: // ADC HL, DE - TI1 = (short)RegHL.Word; TI2 = (short)RegDE.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x5B: // LD DE, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegDE.Low = ReadMemoryWrapper(TUS++); RegDE.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x5C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x5E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x5F: // LD A, R - RegAF.High = (byte)(RegR & 0x7F); - RegFlagS = (byte)(RegR & 0x7F) > 127; - RegFlagZ = (byte)(RegR & 0x7F) == 0; - RegFlagH = false; - RegFlagN = false; - RegFlagP = IFF2; - totalExecutedCycles += 9; pendingCycles -= 9; - break; - case 0x60: // IN H, C - RegHL.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.High > 127; - RegFlagZ = RegHL.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x61: // OUT C, H - WriteHardware(RegBC.Low, RegHL.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x62: // SBC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegHL.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegHL.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x63: // LD (nn), HL - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegHL.Low); - WriteMemoryWrapper(TUS, RegHL.High); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x64: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x65: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x66: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x67: // RRD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB2 >> 4) + (TB1 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 & 0x0F)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x68: // IN L, C - RegHL.Low = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegHL.Low > 127; - RegFlagZ = RegHL.Low == 0; - RegFlagH = false; - RegFlagP = TableParity[RegHL.Low]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x69: // OUT C, L - WriteHardware(RegBC.Low, RegHL.Low); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x6A: // ADC HL, HL - TI1 = (short)RegHL.Word; TI2 = (short)RegHL.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x6B: // LD HL, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegHL.Low = ReadMemoryWrapper(TUS++); RegHL.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0x6C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x6E: // IM $0 - interruptMode = 0; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x6F: // RLD - RegWZ = (ushort)(RegHL + 1); - TB1 = RegAF.High; TB2 = ReadMemoryWrapper(RegHL.Word); - WriteMemoryWrapper(RegHL.Word, (byte)((TB1 & 0x0F) + (TB2 << 4))); - RegAF.High = (byte)((TB1 & 0xF0) + (TB2 >> 4)); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - RegFlag3 = (RegAF.High & 0x08) != 0; - RegFlag5 = (RegAF.High & 0x20) != 0; - totalExecutedCycles += 18; pendingCycles -= 18; - break; - case 0x70: // IN 0, C - TB = ReadHardware((ushort)RegBC.Low); - RegFlagS = TB > 127; - RegFlagZ = TB == 0; - RegFlagH = false; - RegFlagP = TableParity[TB]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x71: // OUT C, 0 - WriteHardware(RegBC.Low, 0); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x72: // SBC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 - TI2; - if (RegFlagC) { --TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((RegHL.Word ^ RegSP.Word ^ TUS) & 0x1000) != 0; - RegFlagN = true; - RegFlagC = (((int)RegHL.Word - (int)RegSP.Word - (RegFlagC ? 1 : 0)) & 0x10000) != 0; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x73: // LD (nn), SP - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - WriteMemoryWrapper(TUS++, RegSP.Low); - WriteMemoryWrapper(TUS, RegSP.High); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x74: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x75: // RETN - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - IFF1 = IFF2; - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x76: // IM $1 - interruptMode = 1; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x77: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x78: // IN A, C - RegAF.High = ReadHardware((ushort)RegBC.Low); - RegFlagS = RegAF.High > 127; - RegFlagZ = RegAF.High == 0; - RegFlagH = false; - RegFlagP = TableParity[RegAF.High]; - RegFlagN = false; - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x79: // OUT C, A - WriteHardware(RegBC.Low, RegAF.High); - totalExecutedCycles += 12; pendingCycles -= 12; - break; - case 0x7A: // ADC HL, SP - TI1 = (short)RegHL.Word; TI2 = (short)RegSP.Word; TIR = TI1 + TI2; - if (RegFlagC) { ++TIR; ++TI2; } - TUS = (ushort)TIR; - RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF; - RegFlagN = false; - RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF; - RegFlagP = TIR > 32767 || TIR < -32768; - RegFlagS = TUS > 32767; - RegFlagZ = TUS == 0; - RegHL.Word = TUS; - RegFlag3 = (TUS & 0x0800) != 0; - RegFlag5 = (TUS & 0x2000) != 0; - totalExecutedCycles += 15; pendingCycles -= 15; - break; - case 0x7B: // LD SP, (nn) - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = (ushort)(TUS + 1); - RegSP.Low = ReadMemoryWrapper(TUS++); RegSP.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 20; pendingCycles -= 20; - break; - case 0x7C: // NEG - RegAF.Word = TableNeg[RegAF.Word]; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7D: // RETI - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 14; pendingCycles -= 14; - break; - case 0x7E: // IM $2 - interruptMode = 2; - totalExecutedCycles += 8; pendingCycles -= 8; - break; - case 0x7F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x80: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x81: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x82: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x83: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x84: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x85: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x86: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x87: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x88: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x89: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x8F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x90: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x91: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x92: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x93: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x94: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x95: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x96: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x97: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x98: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x99: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9A: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9B: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9C: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9D: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9E: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0x9F: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA0: // LDI - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA1: // CPI - RegWZ = (ushort)(RegWZ + 1); - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA2: // INI - RegWZ = (ushort)(RegBC + 1); - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA3: // OUTI - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xA8: // LDD - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xA9: // CPD - RegWZ = (ushort)(RegWZ - 1); - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAA: // IND - RegWZ = (ushort)(RegBC - 1); - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAB: // OUTD - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - totalExecutedCycles += 16; pendingCycles -= 16; - break; - case 0xAC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xAF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB0: // LDIR - WriteMemoryWrapper(RegDE.Word++, TB1 = ReadMemoryWrapper(RegHL.Word++)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB1: // CPIR - TB1 = ReadMemoryWrapper(RegHL.Word++); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB2: // INIR - WriteMemoryWrapper(RegHL.Word++, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB3: // OTIR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word++)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xB8: // LDDR - WriteMemoryWrapper(RegDE.Word--, TB1 = ReadMemoryWrapper(RegHL.Word--)); - TB1 += RegAF.High; RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - RegFlagH = false; - RegFlagN = false; - if (RegBC.Word != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xB9: // CPDR - TB1 = ReadMemoryWrapper(RegHL.Word--); TB2 = (byte)(RegAF.High - TB1); - RegFlagN = true; - RegFlagH = TableHalfBorrow[RegAF.High, TB1]; - RegFlagZ = TB2 == 0; - RegFlagS = TB2 > 127; - TB1 = (byte)(RegAF.High - TB1 - (RegFlagH ? 1 : 0)); RegFlag5 = (TB1 & 0x02) != 0; RegFlag3 = (TB1 & 0x08) != 0; - --RegBC.Word; - RegFlagP = RegBC.Word != 0; - if (RegBC.Word != 0 && !RegFlagZ) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBA: // INDR - WriteMemoryWrapper(RegHL.Word--, ReadHardware(RegBC.Word)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBB: // OTDR - WriteHardware(RegBC.Word, ReadMemoryWrapper(RegHL.Word--)); - --RegBC.High; - RegFlagZ = RegBC.High == 0; - RegFlagN = true; - if (RegBC.High != 0) - { - RegPC.Word -= 2; - totalExecutedCycles += 21; pendingCycles -= 21; - } - else - { - totalExecutedCycles += 16; pendingCycles -= 16; - } - break; - case 0xBC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xBF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xC9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xCF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xD9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xDF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xE9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xED: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xEF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF0: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF1: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF2: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF3: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF5: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF6: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF7: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF8: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF9: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFA: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFB: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFD: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFE: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFF: // NOP - totalExecutedCycles += 4; pendingCycles -= 4; - break; - } - break; - case 0xEE: // XOR n - RegAF.Word = TableALU[5, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xEF: // RST $28 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x28; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF0: // RET P - if (!RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF1: // POP AF - RegAF.Low = ReadMemoryWrapper(RegSP.Word++); RegAF.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF2: // JP P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xF3: // DI - IFF1 = IFF2 = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xF4: // CALL P, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (!RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xF5: // PUSH AF - WriteMemoryWrapper(--RegSP.Word, RegAF.High); WriteMemoryWrapper(--RegSP.Word, RegAF.Low); - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF6: // OR n - RegAF.Word = TableALU[6, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xF7: // RST $30 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x30; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - case 0xF8: // RET M - if (RegFlagS) - { - RegPC.Low = ReadMemoryWrapper(RegSP.Word++); RegPC.High = ReadMemoryWrapper(RegSP.Word++); - totalExecutedCycles += 11; pendingCycles -= 11; - } - else - { - totalExecutedCycles += 5; pendingCycles -= 5; - } - break; - case 0xF9: // LD SP, IY - RegSP.Word = RegIY.Word; - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFA: // JP M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - RegPC.Word = TUS; - } - totalExecutedCycles += 10; pendingCycles -= 10; - break; - case 0xFB: // EI - EI_pending = 2; - Interruptable = false; - totalExecutedCycles += 4; pendingCycles -= 4; - break; - case 0xFC: // CALL M, nn - TUS = (ushort)(FetchMemoryWrapper(RegPC.Word++) + FetchMemoryWrapper(RegPC.Word++) * 256); - RegWZ = TUS; - if (RegFlagS) - { - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = TUS; - totalExecutedCycles += 17; pendingCycles -= 17; - } - else - { - totalExecutedCycles += 10; pendingCycles -= 10; - } - break; - case 0xFD: // <- - // Invalid sequence. - totalExecutedCycles += 1337; pendingCycles -= 1337; - break; - case 0xFE: // CP n - RegAF.Word = TableALU[7, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xFF: // RST $38 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - } - break; - case 0xFE: // CP n - RegAF.Word = TableALU[7, RegAF.High, FetchMemoryWrapper(RegPC.Word++), 0]; - totalExecutedCycles += 7; pendingCycles -= 7; - break; - case 0xFF: // RST $38 - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 11; pendingCycles -= 11; - break; - } - - } - bool int_triggered = false; - - // Process interrupt requests. - if (nonMaskableInterruptPending) - { - halted = false; - - totalExecutedCycles += 11; pendingCycles -= 11; - nonMaskableInterruptPending = false; - - iff2 = iff1; - iff1 = false; - - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x66; - NMICallback(); - - } - else if (iff1 && interrupt && Interruptable) - { - int_triggered = true; - - Halted = false; - - iff1 = iff2 = false; - - switch (interruptMode) - { - case 0: - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 1: - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Word = 0x38; - totalExecutedCycles += 13; pendingCycles -= 13; - break; - case 2: - TUS = (ushort)(RegI * 256 + 0); - WriteMemoryWrapper(--RegSP.Word, RegPC.High); WriteMemoryWrapper(--RegSP.Word, RegPC.Low); - RegPC.Low = ReadMemoryWrapper(TUS++); RegPC.High = ReadMemoryWrapper(TUS); - totalExecutedCycles += 19; pendingCycles -= 19; - break; - } - IRQCallback(); - } - - //EI (enable interrupts) actually takes effect after the NEXT instruction - if (EI_pending > 0) - { - EI_pending--; - if (EI_pending == 0 && !int_triggered) - { - IFF1 = IFF2 = true; - } - } - - } - } - - // TODO, not super thrilled with the existing Z80 disassembler, lets see if we can find something decent to replace it with - Disassembler Disassembler = new Disassembler(); - - public string TraceHeader - { - get { return "Z80: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; } - } - - public TraceInfo State() - { - ushort tempPC = RegPC.Word; - - return new TraceInfo - { - Disassembly = string.Format( - "{0:X4}: {1:X2} {2}", - RegPC.Word, - FetchMemoryWrapper(RegPC.Word), - Disassembler.Disassemble(() => ReadMemoryWrapper(tempPC++))).PadRight(26), - RegisterInfo = string.Format( - "AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4} Cy:{7} {8}{9}{10}{11}{12}{13}{14}{15}", - RegAF.Word, - RegBC.Word, - RegDE.Word, - RegHL.Word, - RegIX.Word, - RegIY.Word, - RegSP.Word, - TotalExecutedCycles, - RegFlagC ? "C" : "c", - RegFlagN ? "N" : "n", - RegFlagP ? "P" : "p", - RegFlag3 ? "3" : "-", - RegFlagH ? "H" : "h", - RegFlag5 ? "5" : "-", - RegFlagZ ? "Z" : "z", - RegFlagS ? "S" : "s" - ) - }; - } - } -} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Interrupts.cs deleted file mode 100644 index 738f1dad74..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Interrupts.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - private bool iff1; - public bool IFF1 { get { return iff1; } set { iff1 = value; } } - - private bool iff2; - public bool IFF2 { get { return iff2; } set { iff2 = value; } } - - private bool interrupt; - public bool Interrupt { get { return interrupt; } set { interrupt = value; } } - - private bool nonMaskableInterrupt; - public bool NonMaskableInterrupt - { - get { return nonMaskableInterrupt; } - set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; } - } - - private bool nonMaskableInterruptPending; - public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } } - - private int interruptMode; - public int InterruptMode - { - get { return interruptMode; } - set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; } - } - - private bool halted; - public bool Halted { get { return halted; } set { halted = value; } } - - public Action IRQCallback = delegate() { }; - public Action NMICallback = delegate() { }; - - private void ResetInterrupts() - { - IFF1 = false; - IFF2 = false; - Interrupt = false; - NonMaskableInterrupt = false; - NonMaskableInterruptPending = false; - InterruptMode = 1; - Halted = false; - } - - private void Halt() - { - Halted = true; - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Registers.cs deleted file mode 100644 index bd5fe98cbc..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Registers.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System.Runtime.InteropServices; -using System; - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - [StructLayout(LayoutKind.Explicit)] - [Serializable()] - public struct RegisterPair - { - [FieldOffset(0)] - public ushort Word; - - [FieldOffset(0)] - public byte Low; - - [FieldOffset(1)] - public byte High; - - public RegisterPair(ushort value) - { - Word = value; - Low = (byte)(Word); - High = (byte)(Word >> 8); - } - - public static implicit operator ushort(RegisterPair rp) - { - return rp.Word; - } - - public static implicit operator RegisterPair(ushort value) - { - return new RegisterPair(value); - } - } - - private bool RegFlagC - { - get { return (RegAF.Low & 0x01) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x01) | (value ? 0x01 : 0x00)); } - } - - private bool RegFlagN - { - get { return (RegAF.Low & 0x02) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x02) | (value ? 0x02 : 0x00)); } - } - - private bool RegFlagP - { - get { return (RegAF.Low & 0x04) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x04) | (value ? 0x04 : 0x00)); } - } - - private bool RegFlag3 - { - get { return (RegAF.Low & 0x08) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x08) | (value ? 0x08 : 0x00)); } - } - - private bool RegFlagH - { - get { return (RegAF.Low & 0x10) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x10) | (value ? 0x10 : 0x00)); } - } - - private bool RegFlag5 - { - get { return (RegAF.Low & 0x20) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x20) | (value ? 0x20 : 0x00)); } - } - - private bool RegFlagZ - { - get { return (RegAF.Low & 0x40) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x40) | (value ? 0x40 : 0x00)); } - } - - private bool RegFlagS - { - get { return (RegAF.Low & 0x80) != 0; } - set { RegAF.Low = (byte)((RegAF.Low & ~0x80) | (value ? 0x80 : 0x00)); } - } - - private RegisterPair RegAF; - private RegisterPair RegBC; - private RegisterPair RegDE; - private RegisterPair RegHL; - private RegisterPair RegWZ; - - private RegisterPair RegAltAF; // Shadow for A and F - private RegisterPair RegAltBC; // Shadow for B and C - private RegisterPair RegAltDE; // Shadow for D and E - private RegisterPair RegAltHL; // Shadow for H and L - // NOTE: There is no AltWZ register (despite it being shown on various block diagrams) - - private byte RegI; // I (interrupt vector) - private byte RegR; // R (memory refresh) - - private RegisterPair RegIX; // IX (index register x) - private RegisterPair RegIY; // IY (index register y) - - private RegisterPair RegSP; // SP (stack pointer) - private RegisterPair RegPC; // PC (program counter) - - private void ResetRegisters() - { - // Clear main registers - RegAF = 0; RegBC = 0; RegDE = 0; RegHL = 0; RegWZ = 0; - // Clear alternate registers - RegAltAF = 0; RegAltBC = 0; RegAltDE = 0; RegAltHL = 0; - // Clear special purpose registers - RegI = 0; RegR = 0; - RegIX.Word = 0; RegIY.Word = 0; - RegSP.Word = 0; RegPC.Word = 0; - } - - public byte RegisterA - { - get { return RegAF.High; } - set { RegAF.High = value; } - } - - public byte RegisterF - { - get { return RegAF.Low; } - set { RegAF.Low = value; } - } - - public ushort RegisterAF - { - get { return RegAF.Word; } - set { RegAF.Word = value; } - } - - public byte RegisterB - { - get { return RegBC.High; } - set { RegBC.High = value; } - } - - public byte RegisterC - { - get { return RegBC.Low; } - set { RegBC.Low = value; } - } - - public ushort RegisterBC - { - get { return RegBC.Word; } - set { RegBC.Word = value; } - } - - public byte RegisterD - { - get { return RegDE.High; } - set { RegDE.High = value; } - } - - public byte RegisterE - { - get { return RegDE.Low; } - set { RegDE.Low = value; } - } - - public ushort RegisterDE - { - get { return RegDE.Word; } - set { RegDE.Word = value; } - } - - public byte RegisterH - { - get { return RegHL.High; } - set { RegHL.High = value; } - } - - public byte RegisterL - { - get { return RegHL.Low; } - set { RegHL.Low = value; } - } - - public ushort RegisterHL - { - get { return RegHL.Word; } - set { RegHL.Word = value; } - } - - public byte RegisterW - { - get { return RegWZ.High; } - set { RegWZ.High = value; } - } - - public byte RegisterZ - { - get { return RegWZ.Low; } - set { RegWZ.Low = value; } - } - - public ushort RegisterWZ - { - get { return RegWZ.Word; } - set { RegWZ.Word = value; } - } - - public ushort RegisterPC - { - get { return RegPC.Word; } - set { RegPC.Word = value; } - } - - public ushort RegisterSP - { - get { return RegSP.Word; } - set { RegSP.Word = value; } - } - - public ushort RegisterIX - { - get { return RegIX.Word; } - set { RegIX.Word = value; } - } - - public ushort RegisterIY - { - get { return RegIY.Word; } - set { RegIY.Word = value; } - } - - public byte RegisterI - { - get { return RegI; } - set { RegI = value; } - } - - public byte RegisterR - { - get { return RegR; } - set { RegR = value; } - } - - public ushort RegisterShadowAF - { - get { return RegAltAF.Word; } - set { RegAltAF.Word = value; } - } - - public ushort RegisterShadowBC - { - get { return RegAltBC.Word; } - set { RegAltBC.Word = value; } - } - - public ushort RegisterShadowDE - { - get { return RegAltDE.Word; } - set { RegAltDE.Word = value; } - } - - public ushort RegisterShadowHL - { - get { return RegAltHL.Word; } - set { RegAltHL.Word = value; } - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Tables.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Tables.cs deleted file mode 100644 index a50e9a1aeb..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Tables.cs +++ /dev/null @@ -1,331 +0,0 @@ -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public partial class Z80A - { - private void InitialiseTables() - { - InitTableInc(); - InitTableDec(); - InitTableParity(); - InitTableALU(); - InitTableRotShift(); - InitTableHalfBorrow(); - InitTableHalfCarry(); - InitTableNeg(); - InitTableDaa(); - } - - private byte[] TableInc; - private void InitTableInc() - { - TableInc = new byte[256]; - for (int i = 0; i < 256; ++i) - TableInc[i] = FlagByte(false, false, i == 0x80, UndocumentedX(i), (i & 0xF) == 0x0, UndocumentedY(i), i == 0, i > 127); - } - - private byte[] TableDec; - private void InitTableDec() - { - TableDec = new byte[256]; - for (int i = 0; i < 256; ++i) - TableDec[i] = FlagByte(false, true, i == 0x7F, UndocumentedX(i), (i & 0xF) == 0xF, UndocumentedY(i), i == 0, i > 127); - } - - private bool[] TableParity; - private void InitTableParity() - { - TableParity = new bool[256]; - for (int i = 0; i < 256; ++i) - { - int Bits = 0; - for (int j = 0; j < 8; ++j) - { - Bits += (i >> j) & 1; - } - TableParity[i] = (Bits & 1) == 0; - } - } - - private ushort[, , ,] TableALU; - private void InitTableALU() - { - TableALU = new ushort[8, 256, 256, 2]; // Class, OP1, OP2, Carry - - for (int i = 0; i < 8; ++i) - { - for (int op1 = 0; op1 < 256; ++op1) - { - for (int op2 = 0; op2 < 256; ++op2) - { - for (int c = 0; c < 2; ++c) - { - - int ac = (i == 1 || i == 3) ? c : 0; - - bool S = false; - bool Z = false; - bool C = false; - bool H = false; - bool N = false; - bool P = false; - - byte result_b = 0; - int result_si = 0; - int result_ui = 0; - - // Fetch result - switch (i) - { - case 0: - case 1: - result_si = (sbyte)op1 + (sbyte)op2 + ac; - result_ui = op1 + op2 + ac; - break; - case 2: - case 3: - case 7: - result_si = (sbyte)op1 - (sbyte)op2 - ac; - result_ui = op1 - op2 - ac; - break; - case 4: - result_si = op1 & op2; - break; - case 5: - result_si = op1 ^ op2; - break; - case 6: - result_si = op1 | op2; - break; - } - - result_b = (byte)result_si; - - // Parity/Carry - - switch (i) - { - case 0: - case 1: - case 2: - case 3: - case 7: - P = result_si < -128 || result_si > 127; - C = result_ui < 0 || result_ui > 255; - break; - case 4: - case 5: - case 6: - P = TableParity[result_b]; - C = false; - break; - } - - // Subtraction - N = i == 2 || i == 3 || i == 7; - - // Half carry - switch (i) - { - case 0: - case 1: - H = ((op1 & 0xF) + (op2 & 0xF) + (ac & 0xF)) > 0xF; - break; - case 2: - case 3: - case 7: - H = ((op1 & 0xF) - (op2 & 0xF) - (ac & 0xF)) < 0x0; - break; - case 4: - H = true; - break; - case 5: - case 6: - H = false; - break; - } - - // Undocumented - byte UndocumentedFlags = (byte)(result_b & 0x28); - if (i == 7) UndocumentedFlags = (byte)(op2 & 0x28); - - S = result_b > 127; - Z = result_b == 0; - - if (i == 7) result_b = (byte)op1; - - TableALU[i, op1, op2, c] = (ushort)( - result_b * 256 + - ((C ? 0x01 : 0) + (N ? 0x02 : 0) + (P ? 0x04 : 0) + (H ? 0x10 : 0) + (Z ? 0x40 : 0) + (S ? 0x80 : 0)) + - (UndocumentedFlags)); - - } - } - } - } - } - - private bool[,] TableHalfBorrow; - private void InitTableHalfBorrow() - { - TableHalfBorrow = new bool[256, 256]; - for (int i = 0; i < 256; i++) - { - for (int j = 0; j < 256; j++) - { - TableHalfBorrow[i, j] = ((i & 0xF) - (j & 0xF)) < 0; - } - } - } - - private bool[,] TableHalfCarry; - private void InitTableHalfCarry() - { - TableHalfCarry = new bool[256, 256]; - for (int i = 0; i < 256; i++) - { - for (int j = 0; j < 256; j++) - { - TableHalfCarry[i, j] = ((i & 0xF) + (j & 0xF)) > 0xF; - } - } - } - - private ushort[, ,] TableRotShift; - private void InitTableRotShift() - { - TableRotShift = new ushort[2, 8, 65536]; // All, operation, AF - for (int all = 0; all < 2; all++) - { - for (int y = 0; y < 8; ++y) - { - for (int af = 0; af < 65536; af++) - { - byte Old = (byte)(af >> 8); - bool OldCarry = (af & 0x01) != 0; - - ushort newAf = (ushort)(af & ~(0x13)); // Clear HALF-CARRY, SUBTRACT and CARRY flags - - byte New = Old; - if ((y & 1) == 0) - { - if ((Old & 0x80) != 0) ++newAf; - - New <<= 1; - - if ((y & 0x04) == 0) - { - if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x01; - } - else - { - if ((y & 0x02) != 0) New |= 0x01; - } - - } - else - { - - if ((Old & 0x01) != 0) ++newAf; - - New >>= 1; - - if ((y & 0x04) == 0) - { - if (((y & 0x02) == 0) ? ((newAf & 0x01) != 0) : OldCarry) New |= 0x80; - } - else - { - if ((y & 0x02) == 0) New |= (byte)(Old & 0x80); - } - } - - newAf &= 0xFF; - newAf |= (ushort)(New * 256); - - if (all == 1) - { - newAf &= unchecked((ushort)~0xC4); // Clear S, Z, P - if (New > 127) newAf |= 0x80; - if (New == 0) newAf |= 0x40; - if (TableParity[New]) newAf |= 0x04; - } - - TableRotShift[all, y, af] = (ushort)((newAf & ~0x28) | ((newAf >> 8) & 0x28)); - } - } - } - } - - private ushort[] TableNeg; - private void InitTableNeg() - { - TableNeg = new ushort[65536]; - for (int af = 0; af < 65536; af++) - { - ushort raf = 0; - byte b = (byte)(af >> 8); - byte a = (byte)-b; - raf |= (ushort)(a * 256); - raf |= FlagByte(b != 0x00, true, b == 0x80, UndocumentedX(a), TableHalfCarry[a, b], UndocumentedY(a), a == 0, a > 127); - TableNeg[af] = raf; - } - } - - private ushort[] TableDaa; - private void InitTableDaa() - { - TableDaa = new ushort[65536]; - for (int af = 0; af < 65536; ++af) - { - byte a = (byte)(af >> 8); - byte tmp = a; - - if (IsN(af)) - { - if (IsH(af) || ((a & 0x0F) > 0x09)) tmp -= 0x06; - if (IsC(af) || a > 0x99) tmp -= 0x60; - } - else - { - if (IsH(af) || ((a & 0x0F) > 0x09)) tmp += 0x06; - if (IsC(af) || a > 0x99) tmp += 0x60; - } - - TableDaa[af] = (ushort)((tmp * 256) + FlagByte(IsC(af) || a > 0x99, IsN(af), TableParity[tmp], UndocumentedX(tmp), ((a ^ tmp) & 0x10) != 0, UndocumentedY(tmp), tmp == 0, tmp > 127)); - } - } - - private byte FlagByte(bool C, bool N, bool P, bool X, bool H, bool Y, bool Z, bool S) - { - return (byte)( - (C ? 0x01 : 0) + - (N ? 0x02 : 0) + - (P ? 0x04 : 0) + - (X ? 0x08 : 0) + - (H ? 0x10 : 0) + - (Y ? 0x20 : 0) + - (Z ? 0x40 : 0) + - (S ? 0x80 : 0) - ); - } - - private bool UndocumentedX(int value) - { - return (value & 0x08) != 0; - } - - private bool UndocumentedY(int value) - { - return (value & 0x20) != 0; - } - - private bool IsC(int value) { return (value & 0x01) != 0; } - private bool IsN(int value) { return (value & 0x02) != 0; } - private bool IsP(int value) { return (value & 0x04) != 0; } - private bool IsX(int value) { return (value & 0x08) != 0; } - private bool IsH(int value) { return (value & 0x10) != 0; } - private bool IsY(int value) { return (value & 0x20) != 0; } - private bool IsZ(int value) { return (value & 0x40) != 0; } - private bool IsS(int value) { return (value & 0x80) != 0; } - } -} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80/Z80A.cs deleted file mode 100644 index 3f53e2ee23..0000000000 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Z80A.cs +++ /dev/null @@ -1,142 +0,0 @@ -using System; -using System.Globalization; -using System.IO; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - -// This Z80 emulator is a modified version of Ben Ryves 'Brazil' emulator. -// It is MIT licensed. - -// for WZ register details, see: http://www.grimware.org/lib/exe/fetch.php/documentations/devices/z80/z80.memptr.eng.txt - -namespace BizHawk.Emulation.Cores.Components.Z80 -{ - public sealed partial class Z80A - { - public Z80A() - { - InitialiseTables(); - Reset(); - } - - public void Reset() - { - ResetRegisters(); - ResetInterrupts(); - PendingCycles = 0; - ExpectedExecutedCycles = 0; - TotalExecutedCycles = 0; - } - - public void SoftReset() - { - ResetRegisters(); - ResetInterrupts(); - } - - // Memory Access - - public Func FetchMemory; - public Func ReadMemory; - public Action WriteMemory; - - public byte ReadMemoryWrapper(ushort addr) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallReads(addr, "System Bus"); - } - - return ReadMemory(addr); - } - - public byte FetchFirstMemoryWrapper(ushort addr) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallReads(addr, "System Bus"); - } - - if (FetchMemory != null) - { - return FetchMemory(addr, true); - } - - return ReadMemory(addr); - } - - public byte FetchMemoryWrapper(ushort addr) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallReads(addr, "System Bus"); - } - - if (FetchMemory != null) - { - return FetchMemory(addr, false); - } - - return ReadMemory(addr); - } - - public void WriteMemoryWrapper(ushort addr, byte value) - { - if (MemoryCallbacks != null) - { - MemoryCallbacks.CallWrites(addr, "System Bus"); - } - - WriteMemory(addr, value); - } - - public IMemoryCallbackSystem MemoryCallbacks { get; set; } - - // Utility function, not used by core - public ushort ReadWord(ushort addr) - { - ushort value = ReadMemory(addr++); - value |= (ushort)(ReadMemory(addr) << 8); - return value; - } - - // Hardware I/O Port Access - - public Func ReadHardware; - public Action WriteHardware; - - // State Save/Load - - public void SyncState(Serializer ser) - { - ser.BeginSection("Z80"); - ser.Sync("AF", ref RegAF.Word); - ser.Sync("BC", ref RegBC.Word); - ser.Sync("DE", ref RegDE.Word); - ser.Sync("HL", ref RegHL.Word); - ser.Sync("WZ", ref RegWZ.Word); - ser.Sync("ShadowAF", ref RegAltAF.Word); - ser.Sync("ShadowBC", ref RegAltBC.Word); - ser.Sync("ShadowDE", ref RegAltDE.Word); - ser.Sync("ShadowHL", ref RegAltHL.Word); - ser.Sync("I", ref RegI); - ser.Sync("R", ref RegR); - ser.Sync("IX", ref RegIX.Word); - ser.Sync("IY", ref RegIY.Word); - ser.Sync("SP", ref RegSP.Word); - ser.Sync("PC", ref RegPC.Word); - ser.Sync("IRQ", ref interrupt); - ser.Sync("NMI", ref nonMaskableInterrupt); - ser.Sync("NMIPending", ref nonMaskableInterruptPending); - ser.Sync("IM", ref interruptMode); - ser.Sync("IFF1", ref iff1); - ser.Sync("IFF2", ref iff2); - ser.Sync("Halted", ref halted); - ser.Sync("ExecutedCycles", ref totalExecutedCycles); - ser.Sync("PendingCycles", ref pendingCycles); - ser.Sync("EI_pending", ref EI_pending); - ser.EndSection(); - } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs new file mode 100644 index 0000000000..c70e4aa503 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Execute.cs @@ -0,0 +1,1468 @@ +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + private int totalExecutedCycles; + public int TotalExecutedCycles { get { return totalExecutedCycles; } set { totalExecutedCycles = value; } } + + private int EI_pending; + + public const ushort CBpre = 0; + public const ushort EXTDpre = 1; + public const ushort IXpre = 2; + public const ushort IYpre = 3; + public const ushort IXCBpre = 4; + public const ushort IYCBpre = 5; + public const ushort IXYprefetch = 6; + + // variables for executing instructions + public int instr_pntr = 0; + public ushort[] cur_instr; + public int opcode; + public bool NO_prefix, CB_prefix, IX_prefix, EXTD_prefix, IY_prefix, IXCB_prefix, IYCB_prefix; + public bool IXCB_prefetch, IYCB_prefetch; // value is fetched before opcode + public bool halted; + public ushort PF; + + public void FetchInstruction(byte opcode) + { + if (NO_prefix) + { + switch (opcode) + { + case 0x00: NOP_(); break; // NOP + case 0x01: LD_IND_16(C, B, PCl, PCh); break; // LD BC, nn + case 0x02: LD_8_IND(C, B, A); break; // LD (BC), A + case 0x03: INC_16(C, B); break; // INC BC + case 0x04: INT_OP(INC8, B); break; // INC B + case 0x05: INT_OP(DEC8, B); break; // DEC B + case 0x06: LD_IND_8_INC(B, PCl, PCh); break; // LD B, n + case 0x07: INT_OP(RLC, Aim); break; // RLCA + case 0x08: EXCH_(); break; // EXCH AF, AF' + case 0x09: ADD_16(L, H, C, B); break; // ADD HL, BC + case 0x0A: REG_OP_IND(TR, A, C, B); break; // LD A, (BC) + case 0x0B: DEC_16(C, B); break; // DEC BC + case 0x0C: INT_OP(INC8, C); break; // INC C + case 0x0D: INT_OP(DEC8, C); break; // DEC C + case 0x0E: LD_IND_8_INC(C, PCl, PCh); break; // LD C, n + case 0x0F: INT_OP(RRC, Aim); break; // RRCA + case 0x10: DJNZ_(); break; // DJNZ B + case 0x11: LD_IND_16(E, D, PCl, PCh); break; // LD DE, nn + case 0x12: LD_8_IND(E, D, A); break; // LD (DE), A + case 0x13: INC_16(E, D); break; // INC DE + case 0x14: INT_OP(INC8, D); break; // INC D + case 0x15: INT_OP(DEC8, D); break; // DEC D + case 0x16: LD_IND_8_INC(D, PCl, PCh); break; // LD D, n + case 0x17: INT_OP(RL, Aim); break; // RLA + case 0x18: JR_COND(true); break; // JR, r8 + case 0x19: ADD_16(L, H, E, D); break; // ADD HL, DE + case 0x1A: REG_OP_IND(TR, A, E, D); break; // LD A, (DE) + case 0x1B: DEC_16(E, D); break; // DEC DE + case 0x1C: INT_OP(INC8, E); break; // INC E + case 0x1D: INT_OP(DEC8, E); break; // DEC E + case 0x1E: LD_IND_8_INC(E, PCl, PCh); break; // LD E, n + case 0x1F: INT_OP(RR, Aim); break; // RRA + case 0x20: JR_COND(!FlagZ); break; // JR NZ, r8 + case 0x21: LD_IND_16(L, H, PCl, PCh); break; // LD HL, nn + case 0x22: LD_16_IND_nn(L, H); break; // LD (nn), HL + case 0x23: INC_16(L, H); break; // INC HL + case 0x24: INT_OP(INC8, H); break; // INC H + case 0x25: INT_OP(DEC8, H); break; // DEC H + case 0x26: LD_IND_8_INC(H, PCl, PCh); break; // LD H, n + case 0x27: INT_OP(DA, A); break; // DAA + case 0x28: JR_COND(FlagZ); break; // JR Z, r8 + case 0x29: ADD_16(L, H, L, H); break; // ADD HL, HL + case 0x2A: LD_IND_16_nn(L, H); break; // LD HL, (nn) + case 0x2B: DEC_16(L, H); break; // DEC HL + case 0x2C: INT_OP(INC8, L); break; // INC L + case 0x2D: INT_OP(DEC8, L); break; // DEC L + case 0x2E: LD_IND_8_INC(L, PCl, PCh); break; // LD L, n + case 0x2F: INT_OP(CPL, A); break; // CPL + case 0x30: JR_COND(!FlagC); break; // JR NC, r8 + case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn + case 0x32: LD_8_IND_nn(A); break; // LD (nn), A + case 0x33: INC_16(SPl, SPh); break; // INC SP + case 0x34: INC_8_IND(L, H); break; // INC (HL) + case 0x35: DEC_8_IND(L, H); break; // DEC (HL) + case 0x36: LD_8_IND_IND(L, H, PCl, PCh); break; // LD (HL), n + case 0x37: INT_OP(SCF, A); break; // SCF + case 0x38: JR_COND(FlagC); break; // JR C, r8 + case 0x39: ADD_16(L, H, SPl, SPh); break; // ADD HL, SP + case 0x3A: LD_IND_8_nn(A); break; // LD A, (nn) + case 0x3B: DEC_16(SPl, SPh); break; // DEC SP + case 0x3C: INT_OP(INC8, A); break; // INC A + case 0x3D: INT_OP(DEC8, A); break; // DEC A + case 0x3E: LD_IND_8_INC(A, PCl, PCh); break; // LD A, n + case 0x3F: INT_OP(CCF, A); break; // CCF + case 0x40: REG_OP(TR, B, B); break; // LD B, B + case 0x41: REG_OP(TR, B, C); break; // LD B, C + case 0x42: REG_OP(TR, B, D); break; // LD B, D + case 0x43: REG_OP(TR, B, E); break; // LD B, E + case 0x44: REG_OP(TR, B, H); break; // LD B, H + case 0x45: REG_OP(TR, B, L); break; // LD B, L + case 0x46: REG_OP_IND(TR, B, L, H); break; // LD B, (HL) + case 0x47: REG_OP(TR, B, A); break; // LD B, A + case 0x48: REG_OP(TR, C, B); break; // LD C, B + case 0x49: REG_OP(TR, C, C); break; // LD C, C + case 0x4A: REG_OP(TR, C, D); break; // LD C, D + case 0x4B: REG_OP(TR, C, E); break; // LD C, E + case 0x4C: REG_OP(TR, C, H); break; // LD C, H + case 0x4D: REG_OP(TR, C, L); break; // LD C, L + case 0x4E: REG_OP_IND(TR, C, L, H); break; // LD C, (HL) + case 0x4F: REG_OP(TR, C, A); break; // LD C, A + case 0x50: REG_OP(TR, D, B); break; // LD D, B + case 0x51: REG_OP(TR, D, C); break; // LD D, C + case 0x52: REG_OP(TR, D, D); break; // LD D, D + case 0x53: REG_OP(TR, D, E); break; // LD D, E + case 0x54: REG_OP(TR, D, H); break; // LD D, H + case 0x55: REG_OP(TR, D, L); break; // LD D, L + case 0x56: REG_OP_IND(TR, D, L, H); break; // LD D, (HL) + case 0x57: REG_OP(TR, D, A); break; // LD D, A + case 0x58: REG_OP(TR, E, B); break; // LD E, B + case 0x59: REG_OP(TR, E, C); break; // LD E, C + case 0x5A: REG_OP(TR, E, D); break; // LD E, D + case 0x5B: REG_OP(TR, E, E); break; // LD E, E + case 0x5C: REG_OP(TR, E, H); break; // LD E, H + case 0x5D: REG_OP(TR, E, L); break; // LD E, L + case 0x5E: REG_OP_IND(TR, E, L, H); break; // LD E, (HL) + case 0x5F: REG_OP(TR, E, A); break; // LD E, A + case 0x60: REG_OP(TR, H, B); break; // LD H, B + case 0x61: REG_OP(TR, H, C); break; // LD H, C + case 0x62: REG_OP(TR, H, D); break; // LD H, D + case 0x63: REG_OP(TR, H, E); break; // LD H, E + case 0x64: REG_OP(TR, H, H); break; // LD H, H + case 0x65: REG_OP(TR, H, L); break; // LD H, L + case 0x66: REG_OP_IND(TR, H, L, H); break; // LD H, (HL) + case 0x67: REG_OP(TR, H, A); break; // LD H, A + case 0x68: REG_OP(TR, L, B); break; // LD L, B + case 0x69: REG_OP(TR, L, C); break; // LD L, C + case 0x6A: REG_OP(TR, L, D); break; // LD L, D + case 0x6B: REG_OP(TR, L, E); break; // LD L, E + case 0x6C: REG_OP(TR, L, H); break; // LD L, H + case 0x6D: REG_OP(TR, L, L); break; // LD L, L + case 0x6E: REG_OP_IND(TR, L, L, H); break; // LD L, (HL) + case 0x6F: REG_OP(TR, L, A); break; // LD L, A + case 0x70: LD_8_IND(L, H, B); break; // LD (HL), B + case 0x71: LD_8_IND(L, H, C); break; // LD (HL), C + case 0x72: LD_8_IND(L, H, D); break; // LD (HL), D + case 0x73: LD_8_IND(L, H, E); break; // LD (HL), E + case 0x74: LD_8_IND(L, H, H); break; // LD (HL), H + case 0x75: LD_8_IND(L, H, L); break; // LD (HL), L + case 0x76: HALT_(); break; // HALT + case 0x77: LD_8_IND(L, H, A); break; // LD (HL), A + case 0x78: REG_OP(TR, A, B); break; // LD A, B + case 0x79: REG_OP(TR, A, C); break; // LD A, C + case 0x7A: REG_OP(TR, A, D); break; // LD A, D + case 0x7B: REG_OP(TR, A, E); break; // LD A, E + case 0x7C: REG_OP(TR, A, H); break; // LD A, H + case 0x7D: REG_OP(TR, A, L); break; // LD A, L + case 0x7E: REG_OP_IND(TR, A, L, H); break; // LD A, (HL) + case 0x7F: REG_OP(TR, A, A); break; // LD A, A + case 0x80: REG_OP(ADD8, A, B); break; // ADD A, B + case 0x81: REG_OP(ADD8, A, C); break; // ADD A, C + case 0x82: REG_OP(ADD8, A, D); break; // ADD A, D + case 0x83: REG_OP(ADD8, A, E); break; // ADD A, E + case 0x84: REG_OP(ADD8, A, H); break; // ADD A, H + case 0x85: REG_OP(ADD8, A, L); break; // ADD A, L + case 0x86: REG_OP_IND(ADD8, A, L, H); break; // ADD A, (HL) + case 0x87: REG_OP(ADD8, A, A); break; // ADD A, A + case 0x88: REG_OP(ADC8, A, B); break; // ADC A, B + case 0x89: REG_OP(ADC8, A, C); break; // ADC A, C + case 0x8A: REG_OP(ADC8, A, D); break; // ADC A, D + case 0x8B: REG_OP(ADC8, A, E); break; // ADC A, E + case 0x8C: REG_OP(ADC8, A, H); break; // ADC A, H + case 0x8D: REG_OP(ADC8, A, L); break; // ADC A, L + case 0x8E: REG_OP_IND(ADC8, A, L, H); break; // ADC A, (HL) + case 0x8F: REG_OP(ADC8, A, A); break; // ADC A, A + case 0x90: REG_OP(SUB8, A, B); break; // SUB A, B + case 0x91: REG_OP(SUB8, A, C); break; // SUB A, C + case 0x92: REG_OP(SUB8, A, D); break; // SUB A, D + case 0x93: REG_OP(SUB8, A, E); break; // SUB A, E + case 0x94: REG_OP(SUB8, A, H); break; // SUB A, H + case 0x95: REG_OP(SUB8, A, L); break; // SUB A, L + case 0x96: REG_OP_IND(SUB8, A, L, H); break; // SUB A, (HL) + case 0x97: REG_OP(SUB8, A, A); break; // SUB A, A + case 0x98: REG_OP(SBC8, A, B); break; // SBC A, B + case 0x99: REG_OP(SBC8, A, C); break; // SBC A, C + case 0x9A: REG_OP(SBC8, A, D); break; // SBC A, D + case 0x9B: REG_OP(SBC8, A, E); break; // SBC A, E + case 0x9C: REG_OP(SBC8, A, H); break; // SBC A, H + case 0x9D: REG_OP(SBC8, A, L); break; // SBC A, L + case 0x9E: REG_OP_IND(SBC8, A, L, H); break; // SBC A, (HL) + case 0x9F: REG_OP(SBC8, A, A); break; // SBC A, A + case 0xA0: REG_OP(AND8, A, B); break; // AND A, B + case 0xA1: REG_OP(AND8, A, C); break; // AND A, C + case 0xA2: REG_OP(AND8, A, D); break; // AND A, D + case 0xA3: REG_OP(AND8, A, E); break; // AND A, E + case 0xA4: REG_OP(AND8, A, H); break; // AND A, H + case 0xA5: REG_OP(AND8, A, L); break; // AND A, L + case 0xA6: REG_OP_IND(AND8, A, L, H); break; // AND A, (HL) + case 0xA7: REG_OP(AND8, A, A); break; // AND A, A + case 0xA8: REG_OP(XOR8, A, B); break; // XOR A, B + case 0xA9: REG_OP(XOR8, A, C); break; // XOR A, C + case 0xAA: REG_OP(XOR8, A, D); break; // XOR A, D + case 0xAB: REG_OP(XOR8, A, E); break; // XOR A, E + case 0xAC: REG_OP(XOR8, A, H); break; // XOR A, H + case 0xAD: REG_OP(XOR8, A, L); break; // XOR A, L + case 0xAE: REG_OP_IND(XOR8, A, L, H); break; // XOR A, (HL) + case 0xAF: REG_OP(XOR8, A, A); break; // XOR A, A + case 0xB0: REG_OP(OR8, A, B); break; // OR A, B + case 0xB1: REG_OP(OR8, A, C); break; // OR A, C + case 0xB2: REG_OP(OR8, A, D); break; // OR A, D + case 0xB3: REG_OP(OR8, A, E); break; // OR A, E + case 0xB4: REG_OP(OR8, A, H); break; // OR A, H + case 0xB5: REG_OP(OR8, A, L); break; // OR A, L + case 0xB6: REG_OP_IND(OR8, A, L, H); break; // OR A, (HL) + case 0xB7: REG_OP(OR8, A, A); break; // OR A, A + case 0xB8: REG_OP(CP8, A, B); break; // CP A, B + case 0xB9: REG_OP(CP8, A, C); break; // CP A, C + case 0xBA: REG_OP(CP8, A, D); break; // CP A, D + case 0xBB: REG_OP(CP8, A, E); break; // CP A, E + case 0xBC: REG_OP(CP8, A, H); break; // CP A, H + case 0xBD: REG_OP(CP8, A, L); break; // CP A, L + case 0xBE: REG_OP_IND(CP8, A, L, H); break; // CP A, (HL) + case 0xBF: REG_OP(CP8, A, A); break; // CP A, A + case 0xC0: RET_COND(!FlagZ); break; // Ret NZ + case 0xC1: POP_(C, B); break; // POP BC + case 0xC2: JP_COND(!FlagZ); break; // JP NZ + case 0xC3: JP_COND(true); break; // JP + case 0xC4: CALL_COND(!FlagZ); break; // CALL NZ + case 0xC5: PUSH_(C, B); break; // PUSH BC + case 0xC6: REG_OP_IND_INC(ADD8, A, PCl, PCh); break; // ADD A, n + case 0xC7: RST_(0); break; // RST 0 + case 0xC8: RET_COND(FlagZ); break; // RET Z + case 0xC9: RET_(); break; // RET + case 0xCA: JP_COND(FlagZ); break; // JP Z + case 0xCB: PREFIX_(CBpre); break; // PREFIX CB + case 0xCC: CALL_COND(FlagZ); break; // CALL Z + case 0xCD: CALL_COND(true); break; // CALL + case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n + case 0xCF: RST_(0x08); break; // RST 0x08 + case 0xD0: RET_COND(!FlagC); break; // Ret NC + case 0xD1: POP_(E, D); break; // POP DE + case 0xD2: JP_COND(!FlagC); break; // JP NC + case 0xD3: OUT_(); break; // OUT A + case 0xD4: CALL_COND(!FlagC); break; // CALL NC + case 0xD5: PUSH_(E, D); break; // PUSH DE + case 0xD6: REG_OP_IND_INC(SUB8, A, PCl, PCh); break; // SUB A, n + case 0xD7: RST_(0x10); break; // RST 0x10 + case 0xD8: RET_COND(FlagC); break; // RET C + case 0xD9: EXX_(); break; // EXX + case 0xDA: JP_COND(FlagC); break; // JP C + case 0xDB: IN_(); break; // IN A + case 0xDC: CALL_COND(FlagC); break; // CALL C + case 0xDD: PREFIX_(IXpre); break; // PREFIX IX + case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n + case 0xDF: RST_(0x18); break; // RST 0x18 + case 0xE0: RET_COND(!FlagP); break; // RET Po + case 0xE1: POP_(L, H); break; // POP HL + case 0xE2: JP_COND(!FlagP); break; // JP Po + case 0xE3: EXCH_16_IND_(SPl, SPh, L, H); break; // ex (SP), HL + case 0xE4: CALL_COND(!FlagP); break; // CALL Po + case 0xE5: PUSH_(L, H); break; // PUSH HL + case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n + case 0xE7: RST_(0x20); break; // RST 0x20 + case 0xE8: RET_COND(FlagP); break; // RET Pe + case 0xE9: JP_16(L, H); break; // JP (HL) + case 0xEA: JP_COND(FlagP); break; // JP Pe + case 0xEB: EXCH_16_(E,D, L, H); break; // ex DE, HL + case 0xEC: CALL_COND(FlagP); break; // CALL Pe + case 0xED: PREFIX_(EXTDpre); break; // PREFIX EXTD + case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n + case 0xEF: RST_(0x28); break; // RST 0x28 + case 0xF0: RET_COND(!FlagS); break; // RET p + case 0xF1: POP_(F, A); break; // POP AF + case 0xF2: JP_COND(!FlagS); break; // JP p + case 0xF3: DI_(); break; // DI + case 0xF4: CALL_COND(!FlagS); break; // CALL p + case 0xF5: PUSH_(F, A); break; // PUSH AF + case 0xF6: REG_OP_IND_INC(OR8, A, PCl, PCh); break; // OR A, n + case 0xF7: RST_(0x30); break; // RST 0x30 + case 0xF8: RET_COND(FlagS); break; // RET M + case 0xF9: LD_SP_16(L, H); break; // LD SP, HL + case 0xFA: JP_COND(FlagS); break; // JP M + case 0xFB: EI_(); break; // EI + case 0xFC: CALL_COND(FlagS); break; // CALL M + case 0xFD: PREFIX_(IYpre); break; // PREFIX IY + case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // CP A, n + case 0xFF: RST_(0x38); break; // RST 0x38 + } + } + else if (CB_prefix) + { + CB_prefix = false; + NO_prefix = true; + switch (opcode) + { + case 0x00: INT_OP(RLC, B); break; // RLC B + case 0x01: INT_OP(RLC, C); break; // RLC C + case 0x02: INT_OP(RLC, D); break; // RLC D + case 0x03: INT_OP(RLC, E); break; // RLC E + case 0x04: INT_OP(RLC, H); break; // RLC H + case 0x05: INT_OP(RLC, L); break; // RLC L + case 0x06: INT_OP_IND(RLC, L, H); break; // RLC (HL) + case 0x07: INT_OP(RLC, A); break; // RLC A + case 0x08: INT_OP(RRC, B); break; // RRC B + case 0x09: INT_OP(RRC, C); break; // RRC C + case 0x0A: INT_OP(RRC, D); break; // RRC D + case 0x0B: INT_OP(RRC, E); break; // RRC E + case 0x0C: INT_OP(RRC, H); break; // RRC H + case 0x0D: INT_OP(RRC, L); break; // RRC L + case 0x0E: INT_OP_IND(RRC, L, H); break; // RRC (HL) + case 0x0F: INT_OP(RRC, A); break; // RRC A + case 0x10: INT_OP(RL, B); break; // RL B + case 0x11: INT_OP(RL, C); break; // RL C + case 0x12: INT_OP(RL, D); break; // RL D + case 0x13: INT_OP(RL, E); break; // RL E + case 0x14: INT_OP(RL, H); break; // RL H + case 0x15: INT_OP(RL, L); break; // RL L + case 0x16: INT_OP_IND(RL, L, H); break; // RL (HL) + case 0x17: INT_OP(RL, A); break; // RL A + case 0x18: INT_OP(RR, B); break; // RR B + case 0x19: INT_OP(RR, C); break; // RR C + case 0x1A: INT_OP(RR, D); break; // RR D + case 0x1B: INT_OP(RR, E); break; // RR E + case 0x1C: INT_OP(RR, H); break; // RR H + case 0x1D: INT_OP(RR, L); break; // RR L + case 0x1E: INT_OP_IND(RR, L, H); break; // RR (HL) + case 0x1F: INT_OP(RR, A); break; // RR A + case 0x20: INT_OP(SLA, B); break; // SLA B + case 0x21: INT_OP(SLA, C); break; // SLA C + case 0x22: INT_OP(SLA, D); break; // SLA D + case 0x23: INT_OP(SLA, E); break; // SLA E + case 0x24: INT_OP(SLA, H); break; // SLA H + case 0x25: INT_OP(SLA, L); break; // SLA L + case 0x26: INT_OP_IND(SLA, L, H); break; // SLA (HL) + case 0x27: INT_OP(SLA, A); break; // SLA A + case 0x28: INT_OP(SRA, B); break; // SRA B + case 0x29: INT_OP(SRA, C); break; // SRA C + case 0x2A: INT_OP(SRA, D); break; // SRA D + case 0x2B: INT_OP(SRA, E); break; // SRA E + case 0x2C: INT_OP(SRA, H); break; // SRA H + case 0x2D: INT_OP(SRA, L); break; // SRA L + case 0x2E: INT_OP_IND(SRA, L, H); break; // SRA (HL) + case 0x2F: INT_OP(SRA, A); break; // SRA A + case 0x30: INT_OP(SLL, B); break; // SLL B + case 0x31: INT_OP(SLL, C); break; // SLL C + case 0x32: INT_OP(SLL, D); break; // SLL D + case 0x33: INT_OP(SLL, E); break; // SLL E + case 0x34: INT_OP(SLL, H); break; // SLL H + case 0x35: INT_OP(SLL, L); break; // SLL L + case 0x36: INT_OP_IND(SLL, L, H); break; // SLL (HL) + case 0x37: INT_OP(SLL, A); break; // SLL A + case 0x38: INT_OP(SRL, B); break; // SRL B + case 0x39: INT_OP(SRL, C); break; // SRL C + case 0x3A: INT_OP(SRL, D); break; // SRL D + case 0x3B: INT_OP(SRL, E); break; // SRL E + case 0x3C: INT_OP(SRL, H); break; // SRL H + case 0x3D: INT_OP(SRL, L); break; // SRL L + case 0x3E: INT_OP_IND(SRL, L, H); break; // SRL (HL) + case 0x3F: INT_OP(SRL, A); break; // SRL A + case 0x40: BIT_OP(BIT, 0, B); break; // BIT 0, B + case 0x41: BIT_OP(BIT, 0, C); break; // BIT 0, C + case 0x42: BIT_OP(BIT, 0, D); break; // BIT 0, D + case 0x43: BIT_OP(BIT, 0, E); break; // BIT 0, E + case 0x44: BIT_OP(BIT, 0, H); break; // BIT 0, H + case 0x45: BIT_OP(BIT, 0, L); break; // BIT 0, L + case 0x46: BIT_TE_IND(BIT, 0, L, H); break; // BIT 0, (HL) + case 0x47: BIT_OP(BIT, 0, A); break; // BIT 0, A + case 0x48: BIT_OP(BIT, 1, B); break; // BIT 1, B + case 0x49: BIT_OP(BIT, 1, C); break; // BIT 1, C + case 0x4A: BIT_OP(BIT, 1, D); break; // BIT 1, D + case 0x4B: BIT_OP(BIT, 1, E); break; // BIT 1, E + case 0x4C: BIT_OP(BIT, 1, H); break; // BIT 1, H + case 0x4D: BIT_OP(BIT, 1, L); break; // BIT 1, L + case 0x4E: BIT_TE_IND(BIT, 1, L, H); break; // BIT 1, (HL) + case 0x4F: BIT_OP(BIT, 1, A); break; // BIT 1, A + case 0x50: BIT_OP(BIT, 2, B); break; // BIT 2, B + case 0x51: BIT_OP(BIT, 2, C); break; // BIT 2, C + case 0x52: BIT_OP(BIT, 2, D); break; // BIT 2, D + case 0x53: BIT_OP(BIT, 2, E); break; // BIT 2, E + case 0x54: BIT_OP(BIT, 2, H); break; // BIT 2, H + case 0x55: BIT_OP(BIT, 2, L); break; // BIT 2, L + case 0x56: BIT_TE_IND(BIT, 2, L, H); break; // BIT 2, (HL) + case 0x57: BIT_OP(BIT, 2, A); break; // BIT 2, A + case 0x58: BIT_OP(BIT, 3, B); break; // BIT 3, B + case 0x59: BIT_OP(BIT, 3, C); break; // BIT 3, C + case 0x5A: BIT_OP(BIT, 3, D); break; // BIT 3, D + case 0x5B: BIT_OP(BIT, 3, E); break; // BIT 3, E + case 0x5C: BIT_OP(BIT, 3, H); break; // BIT 3, H + case 0x5D: BIT_OP(BIT, 3, L); break; // BIT 3, L + case 0x5E: BIT_TE_IND(BIT, 3, L, H); break; // BIT 3, (HL) + case 0x5F: BIT_OP(BIT, 3, A); break; // BIT 3, A + case 0x60: BIT_OP(BIT, 4, B); break; // BIT 4, B + case 0x61: BIT_OP(BIT, 4, C); break; // BIT 4, C + case 0x62: BIT_OP(BIT, 4, D); break; // BIT 4, D + case 0x63: BIT_OP(BIT, 4, E); break; // BIT 4, E + case 0x64: BIT_OP(BIT, 4, H); break; // BIT 4, H + case 0x65: BIT_OP(BIT, 4, L); break; // BIT 4, L + case 0x66: BIT_TE_IND(BIT, 4, L, H); break; // BIT 4, (HL) + case 0x67: BIT_OP(BIT, 4, A); break; // BIT 4, A + case 0x68: BIT_OP(BIT, 5, B); break; // BIT 5, B + case 0x69: BIT_OP(BIT, 5, C); break; // BIT 5, C + case 0x6A: BIT_OP(BIT, 5, D); break; // BIT 5, D + case 0x6B: BIT_OP(BIT, 5, E); break; // BIT 5, E + case 0x6C: BIT_OP(BIT, 5, H); break; // BIT 5, H + case 0x6D: BIT_OP(BIT, 5, L); break; // BIT 5, L + case 0x6E: BIT_TE_IND(BIT, 5, L, H); break; // BIT 5, (HL) + case 0x6F: BIT_OP(BIT, 5, A); break; // BIT 5, A + case 0x70: BIT_OP(BIT, 6, B); break; // BIT 6, B + case 0x71: BIT_OP(BIT, 6, C); break; // BIT 6, C + case 0x72: BIT_OP(BIT, 6, D); break; // BIT 6, D + case 0x73: BIT_OP(BIT, 6, E); break; // BIT 6, E + case 0x74: BIT_OP(BIT, 6, H); break; // BIT 6, H + case 0x75: BIT_OP(BIT, 6, L); break; // BIT 6, L + case 0x76: BIT_TE_IND(BIT, 6, L, H); break; // BIT 6, (HL) + case 0x77: BIT_OP(BIT, 6, A); break; // BIT 6, A + case 0x78: BIT_OP(BIT, 7, B); break; // BIT 7, B + case 0x79: BIT_OP(BIT, 7, C); break; // BIT 7, C + case 0x7A: BIT_OP(BIT, 7, D); break; // BIT 7, D + case 0x7B: BIT_OP(BIT, 7, E); break; // BIT 7, E + case 0x7C: BIT_OP(BIT, 7, H); break; // BIT 7, H + case 0x7D: BIT_OP(BIT, 7, L); break; // BIT 7, L + case 0x7E: BIT_TE_IND(BIT, 7, L, H); break; // BIT 7, (HL) + case 0x7F: BIT_OP(BIT, 7, A); break; // BIT 7, A + case 0x80: BIT_OP(RES, 0, B); break; // RES 0, B + case 0x81: BIT_OP(RES, 0, C); break; // RES 0, C + case 0x82: BIT_OP(RES, 0, D); break; // RES 0, D + case 0x83: BIT_OP(RES, 0, E); break; // RES 0, E + case 0x84: BIT_OP(RES, 0, H); break; // RES 0, H + case 0x85: BIT_OP(RES, 0, L); break; // RES 0, L + case 0x86: BIT_OP_IND(RES, 0, L, H); break; // RES 0, (HL) + case 0x87: BIT_OP(RES, 0, A); break; // RES 0, A + case 0x88: BIT_OP(RES, 1, B); break; // RES 1, B + case 0x89: BIT_OP(RES, 1, C); break; // RES 1, C + case 0x8A: BIT_OP(RES, 1, D); break; // RES 1, D + case 0x8B: BIT_OP(RES, 1, E); break; // RES 1, E + case 0x8C: BIT_OP(RES, 1, H); break; // RES 1, H + case 0x8D: BIT_OP(RES, 1, L); break; // RES 1, L + case 0x8E: BIT_OP_IND(RES, 1, L, H); break; // RES 1, (HL) + case 0x8F: BIT_OP(RES, 1, A); break; // RES 1, A + case 0x90: BIT_OP(RES, 2, B); break; // RES 2, B + case 0x91: BIT_OP(RES, 2, C); break; // RES 2, C + case 0x92: BIT_OP(RES, 2, D); break; // RES 2, D + case 0x93: BIT_OP(RES, 2, E); break; // RES 2, E + case 0x94: BIT_OP(RES, 2, H); break; // RES 2, H + case 0x95: BIT_OP(RES, 2, L); break; // RES 2, L + case 0x96: BIT_OP_IND(RES, 2, L, H); break; // RES 2, (HL) + case 0x97: BIT_OP(RES, 2, A); break; // RES 2, A + case 0x98: BIT_OP(RES, 3, B); break; // RES 3, B + case 0x99: BIT_OP(RES, 3, C); break; // RES 3, C + case 0x9A: BIT_OP(RES, 3, D); break; // RES 3, D + case 0x9B: BIT_OP(RES, 3, E); break; // RES 3, E + case 0x9C: BIT_OP(RES, 3, H); break; // RES 3, H + case 0x9D: BIT_OP(RES, 3, L); break; // RES 3, L + case 0x9E: BIT_OP_IND(RES, 3, L, H); break; // RES 3, (HL) + case 0x9F: BIT_OP(RES, 3, A); break; // RES 3, A + case 0xA0: BIT_OP(RES, 4, B); break; // RES 4, B + case 0xA1: BIT_OP(RES, 4, C); break; // RES 4, C + case 0xA2: BIT_OP(RES, 4, D); break; // RES 4, D + case 0xA3: BIT_OP(RES, 4, E); break; // RES 4, E + case 0xA4: BIT_OP(RES, 4, H); break; // RES 4, H + case 0xA5: BIT_OP(RES, 4, L); break; // RES 4, L + case 0xA6: BIT_OP_IND(RES, 4, L, H); break; // RES 4, (HL) + case 0xA7: BIT_OP(RES, 4, A); break; // RES 4, A + case 0xA8: BIT_OP(RES, 5, B); break; // RES 5, B + case 0xA9: BIT_OP(RES, 5, C); break; // RES 5, C + case 0xAA: BIT_OP(RES, 5, D); break; // RES 5, D + case 0xAB: BIT_OP(RES, 5, E); break; // RES 5, E + case 0xAC: BIT_OP(RES, 5, H); break; // RES 5, H + case 0xAD: BIT_OP(RES, 5, L); break; // RES 5, L + case 0xAE: BIT_OP_IND(RES, 5, L, H); break; // RES 5, (HL) + case 0xAF: BIT_OP(RES, 5, A); break; // RES 5, A + case 0xB0: BIT_OP(RES, 6, B); break; // RES 6, B + case 0xB1: BIT_OP(RES, 6, C); break; // RES 6, C + case 0xB2: BIT_OP(RES, 6, D); break; // RES 6, D + case 0xB3: BIT_OP(RES, 6, E); break; // RES 6, E + case 0xB4: BIT_OP(RES, 6, H); break; // RES 6, H + case 0xB5: BIT_OP(RES, 6, L); break; // RES 6, L + case 0xB6: BIT_OP_IND(RES, 6, L, H); break; // RES 6, (HL) + case 0xB7: BIT_OP(RES, 6, A); break; // RES 6, A + case 0xB8: BIT_OP(RES, 7, B); break; // RES 7, B + case 0xB9: BIT_OP(RES, 7, C); break; // RES 7, C + case 0xBA: BIT_OP(RES, 7, D); break; // RES 7, D + case 0xBB: BIT_OP(RES, 7, E); break; // RES 7, E + case 0xBC: BIT_OP(RES, 7, H); break; // RES 7, H + case 0xBD: BIT_OP(RES, 7, L); break; // RES 7, L + case 0xBE: BIT_OP_IND(RES, 7, L, H); break; // RES 7, (HL) + case 0xBF: BIT_OP(RES, 7, A); break; // RES 7, A + case 0xC0: BIT_OP(SET, 0, B); break; // SET 0, B + case 0xC1: BIT_OP(SET, 0, C); break; // SET 0, C + case 0xC2: BIT_OP(SET, 0, D); break; // SET 0, D + case 0xC3: BIT_OP(SET, 0, E); break; // SET 0, E + case 0xC4: BIT_OP(SET, 0, H); break; // SET 0, H + case 0xC5: BIT_OP(SET, 0, L); break; // SET 0, L + case 0xC6: BIT_OP_IND(SET, 0, L, H); break; // SET 0, (HL) + case 0xC7: BIT_OP(SET, 0, A); break; // SET 0, A + case 0xC8: BIT_OP(SET, 1, B); break; // SET 1, B + case 0xC9: BIT_OP(SET, 1, C); break; // SET 1, C + case 0xCA: BIT_OP(SET, 1, D); break; // SET 1, D + case 0xCB: BIT_OP(SET, 1, E); break; // SET 1, E + case 0xCC: BIT_OP(SET, 1, H); break; // SET 1, H + case 0xCD: BIT_OP(SET, 1, L); break; // SET 1, L + case 0xCE: BIT_OP_IND(SET, 1, L, H); break; // SET 1, (HL) + case 0xCF: BIT_OP(SET, 1, A); break; // SET 1, A + case 0xD0: BIT_OP(SET, 2, B); break; // SET 2, B + case 0xD1: BIT_OP(SET, 2, C); break; // SET 2, C + case 0xD2: BIT_OP(SET, 2, D); break; // SET 2, D + case 0xD3: BIT_OP(SET, 2, E); break; // SET 2, E + case 0xD4: BIT_OP(SET, 2, H); break; // SET 2, H + case 0xD5: BIT_OP(SET, 2, L); break; // SET 2, L + case 0xD6: BIT_OP_IND(SET, 2, L, H); break; // SET 2, (HL) + case 0xD7: BIT_OP(SET, 2, A); break; // SET 2, A + case 0xD8: BIT_OP(SET, 3, B); break; // SET 3, B + case 0xD9: BIT_OP(SET, 3, C); break; // SET 3, C + case 0xDA: BIT_OP(SET, 3, D); break; // SET 3, D + case 0xDB: BIT_OP(SET, 3, E); break; // SET 3, E + case 0xDC: BIT_OP(SET, 3, H); break; // SET 3, H + case 0xDD: BIT_OP(SET, 3, L); break; // SET 3, L + case 0xDE: BIT_OP_IND(SET, 3, L, H); break; // SET 3, (HL) + case 0xDF: BIT_OP(SET, 3, A); break; // SET 3, A + case 0xE0: BIT_OP(SET, 4, B); break; // SET 4, B + case 0xE1: BIT_OP(SET, 4, C); break; // SET 4, C + case 0xE2: BIT_OP(SET, 4, D); break; // SET 4, D + case 0xE3: BIT_OP(SET, 4, E); break; // SET 4, E + case 0xE4: BIT_OP(SET, 4, H); break; // SET 4, H + case 0xE5: BIT_OP(SET, 4, L); break; // SET 4, L + case 0xE6: BIT_OP_IND(SET, 4, L, H); break; // SET 4, (HL) + case 0xE7: BIT_OP(SET, 4, A); break; // SET 4, A + case 0xE8: BIT_OP(SET, 5, B); break; // SET 5, B + case 0xE9: BIT_OP(SET, 5, C); break; // SET 5, C + case 0xEA: BIT_OP(SET, 5, D); break; // SET 5, D + case 0xEB: BIT_OP(SET, 5, E); break; // SET 5, E + case 0xEC: BIT_OP(SET, 5, H); break; // SET 5, H + case 0xED: BIT_OP(SET, 5, L); break; // SET 5, L + case 0xEE: BIT_OP_IND(SET, 5, L, H); break; // SET 5, (HL) + case 0xEF: BIT_OP(SET, 5, A); break; // SET 5, A + case 0xF0: BIT_OP(SET, 6, B); break; // SET 6, B + case 0xF1: BIT_OP(SET, 6, C); break; // SET 6, C + case 0xF2: BIT_OP(SET, 6, D); break; // SET 6, D + case 0xF3: BIT_OP(SET, 6, E); break; // SET 6, E + case 0xF4: BIT_OP(SET, 6, H); break; // SET 6, H + case 0xF5: BIT_OP(SET, 6, L); break; // SET 6, L + case 0xF6: BIT_OP_IND(SET, 6, L, H); break; // SET 6, (HL) + case 0xF7: BIT_OP(SET, 6, A); break; // SET 6, A + case 0xF8: BIT_OP(SET, 7, B); break; // SET 7, B + case 0xF9: BIT_OP(SET, 7, C); break; // SET 7, C + case 0xFA: BIT_OP(SET, 7, D); break; // SET 7, D + case 0xFB: BIT_OP(SET, 7, E); break; // SET 7, E + case 0xFC: BIT_OP(SET, 7, H); break; // SET 7, H + case 0xFD: BIT_OP(SET, 7, L); break; // SET 7, L + case 0xFE: BIT_OP_IND(SET, 7, L, H); break; // SET 7, (HL) + case 0xFF: BIT_OP(SET, 7, A); break; // SET 7, A + } + } + else if (EXTD_prefix) + { + // NOTE: Much of EXTD is empty + EXTD_prefix = false; + NO_prefix = true; + + switch (opcode) + { + case 0x40: IN_REG_(B, C); break; // IN B, (C) + case 0x41: OUT_REG_(C, B); break; // OUT (C), B + case 0x42: REG_OP_16_(SBC16, L, H, C, B); break; // SBC HL, BC + case 0x43: LD_16_IND_nn(C, B); break; // LD (nn), BC + case 0x44: INT_OP(NEG, A); break; // NEG + case 0x45: RETN_(); break; // RETN + case 0x46: INT_MODE_(0); break; // IM $0 + case 0x47: REG_OP_IR(TR, I, A); break; // LD I, A + case 0x48: IN_REG_(C, C); break; // IN C, (C) + case 0x49: OUT_REG_(C, C); break; // OUT (C), C + case 0x4A: REG_OP_16_(ADC16, L, H, C, B); break; // ADC HL, BC + case 0x4B: LD_IND_16_nn(C, B); break; // LD BC, (nn) + case 0x4C: INT_OP(NEG, A); break; // NEG + case 0x4D: RETI_(); break; // RETI + case 0x4E: INT_MODE_(0); break; // IM $0 + case 0x4F: REG_OP_IR(TR, R, A); break; // LD R, A + case 0x50: IN_REG_(D, C); break; // IN D, (C) + case 0x51: OUT_REG_(C, D); break; // OUT (C), D + case 0x52: REG_OP_16_(SBC16, L, H, E, D); break; // SBC HL, DE + case 0x53: LD_16_IND_nn(E, D); break; // LD (nn), DE + case 0x54: INT_OP(NEG, A); break; // NEG + case 0x55: RETN_(); break; // RETN + case 0x56: INT_MODE_(1); break; // IM $1 + case 0x57: REG_OP_IR(TR, A, I); break; // LD A, I + case 0x58: IN_REG_(E, C); break; // IN E, (C) + case 0x59: OUT_REG_(C, E); break; // OUT (C), E + case 0x5A: REG_OP_16_(ADC16, L, H, E, D); break; // ADC HL, DE + case 0x5B: LD_IND_16_nn(E, D); break; // LD DE, (nn) + case 0x5C: INT_OP(NEG, A); break; // NEG + case 0x5D: RETN_(); break; // RETI + case 0x5E: INT_MODE_(2); break; // IM $0 + case 0x5F: REG_OP_IR(TR, A, R); break; // LD A, R + case 0x60: IN_REG_(H, C); break; // IN H, (C) + case 0x61: OUT_REG_(C, H); break; // OUT (C), H + case 0x62: REG_OP_16_(SBC16, L, H, L, H); break; // SBC HL, HL + case 0x63: LD_16_IND_nn(L, H); break; // LD (nn), HL + case 0x64: INT_OP(NEG, A); break; // NEG + case 0x65: RETN_(); break; // RETN + case 0x66: INT_MODE_(0); break; // IM $0 + case 0x67: RRD_(); break; // RRD + case 0x68: IN_REG_(L, C); break; // IN L, (C) + case 0x69: OUT_REG_(C, L); break; // OUT (C), L + case 0x6A: REG_OP_16_(ADC16, L, H, L, H); break; // ADC HL, HL + case 0x6B: LD_IND_16_nn(L, H); break; // LD HL, (nn) + case 0x6C: INT_OP(NEG, A); break; // NEG + case 0x6D: RETN_(); break; // RETI + case 0x6E: INT_MODE_(0); break; // IM $0 + case 0x6F: RLD_(); break; // LD R, A + case 0x70: IN_REG_(ALU, C); break; // IN 0, (C) + case 0x71: OUT_REG_(C, ZERO); break; // OUT (C), 0 + case 0x72: REG_OP_16_(SBC16, L, H, SPl, SPh); break; // SBC HL, SP + case 0x73: LD_16_IND_nn(SPl, SPh); break; // LD (nn), SP + case 0x74: INT_OP(NEG, A); break; // NEG + case 0x75: RETN_(); break; // RETN + case 0x76: INT_MODE_(1); break; // IM $1 + case 0x77: NOP_(); break; // NOP + case 0x78: IN_REG_(A, C); break; // IN A, (C) + case 0x79: OUT_REG_(C, A); break; // OUT (C), A + case 0x7A: REG_OP_16_(ADC16, L, H, SPl, SPh); break; // ADC HL, SP + case 0x7B: LD_IND_16_nn(SPl, SPh); break; // LD SP, (nn) + case 0x7C: INT_OP(NEG, A); break; // NEG + case 0x7D: RETN_(); break; // RETI + case 0x7E: INT_MODE_(2); break; // IM $2 + case 0x7F: NOP_(); break; // NOP + case 0xA0: LD_OP_R(INC16, 0); break; // LDI + case 0xA1: CP_OP_R(INC16, 0); break; // CPI + case 0xA2: IN_OP_R(INC16, 0); break; // INI + case 0xA3: OUT_OP_R(INC16, 0); break; // OUTI + case 0xA8: LD_OP_R(DEC16, 0); break; // LDD + case 0xA9: CP_OP_R(DEC16, 0); break; // CPD + case 0xAA: IN_OP_R(DEC16, 0); break; // IND + case 0xAB: OUT_OP_R(DEC16, 0); break; // OUTD + case 0xB0: LD_OP_R(INC16, 1); break; // LDIR + case 0xB1: CP_OP_R(INC16, 1); break; // CPIR + case 0xB2: IN_OP_R(INC16, 1); break; // INIR + case 0xB3: OUT_OP_R(INC16, 1); break; // OTIR + case 0xB8: LD_OP_R(DEC16, 1); break; // LDDR + case 0xB9: CP_OP_R(DEC16, 1); break; // CPDR + case 0xBA: IN_OP_R(DEC16, 1); break; // INDR + case 0xBB: OUT_OP_R(DEC16, 1); break; // OTDR + default: NOP_(); break; // NOP + + } + } + else if (IX_prefix) + { + IX_prefix = false; + NO_prefix = true; + + switch (opcode) + { + case 0x00: NOP_(); break; // NOP + case 0x01: LD_IND_16(C, B, PCl, PCh); break; // LD BC, nn + case 0x02: LD_8_IND(C, B, A); break; // LD (BC), A + case 0x03: INC_16(C, B); break; // INC BC + case 0x04: INT_OP(INC8, B); break; // INC B + case 0x05: INT_OP(DEC8, B); break; // DEC B + case 0x06: LD_IND_8_INC(B, PCl, PCh); break; // LD B, n + case 0x07: INT_OP(RLC, Aim); break; // RLCA + case 0x08: EXCH_(); break; // EXCH AF, AF' + case 0x09: ADD_16(Ixl, Ixh, C, B); break; // ADD Ix, BC + case 0x0A: REG_OP_IND(TR, A, C, B); break; // LD A, (BC) + case 0x0B: DEC_16(C, B); break; // DEC BC + case 0x0C: INT_OP(INC8, C); break; // INC C + case 0x0D: INT_OP(DEC8, C); break; // DEC C + case 0x0E: LD_IND_8_INC(C, PCl, PCh); break; // LD C, n + case 0x0F: INT_OP(RRC, Aim); break; // RRCA + case 0x10: DJNZ_(); break; // DJNZ B + case 0x11: LD_IND_16(E, D, PCl, PCh); break; // LD DE, nn + case 0x12: LD_8_IND(E, D, A); break; // LD (DE), A + case 0x13: INC_16(E, D); break; // INC DE + case 0x14: INT_OP(INC8, D); break; // INC D + case 0x15: INT_OP(DEC8, D); break; // DEC D + case 0x16: LD_IND_8_INC(D, PCl, PCh); break; // LD D, n + case 0x17: INT_OP(RL, Aim); break; // RLA + case 0x18: JR_COND(true); break; // JR, r8 + case 0x19: ADD_16(Ixl, Ixh, E, D); break; // ADD Ix, DE + case 0x1A: REG_OP_IND(TR, A, E, D); break; // LD A, (DE) + case 0x1B: DEC_16(E, D); break; // DEC DE + case 0x1C: INT_OP(INC8, E); break; // INC E + case 0x1D: INT_OP(DEC8, E); break; // DEC E + case 0x1E: LD_IND_8_INC(E, PCl, PCh); break; // LD E, n + case 0x1F: INT_OP(RR, Aim); break; // RRA + case 0x20: JR_COND(!FlagZ); break; // JR NZ, r8 + case 0x21: LD_IND_16(Ixl, Ixh, PCl, PCh); break; // LD Ix, nn + case 0x22: LD_16_IND_nn(Ixl, Ixh); break; // LD (nn), Ix + case 0x23: INC_16(Ixl, Ixh); break; // INC Ix + case 0x24: INT_OP(INC8, Ixh); break; // INC Ixh + case 0x25: INT_OP(DEC8, Ixh); break; // DEC Ixh + case 0x26: LD_IND_8_INC(Ixh, PCl, PCh); break; // LD Ixh, n + case 0x27: INT_OP(DA, A); break; // DAA + case 0x28: JR_COND(FlagZ); break; // JR Z, r8 + case 0x29: ADD_16(Ixl, Ixh, Ixl, Ixh); break; // ADD Ix, Ix + case 0x2A: LD_IND_16_nn(Ixl, Ixh); break; // LD Ix, (nn) + case 0x2B: DEC_16(Ixl, Ixh); break; // DEC Ix + case 0x2C: INT_OP(INC8, Ixl); break; // INC Ixl + case 0x2D: INT_OP(DEC8, Ixl); break; // DEC Ixl + case 0x2E: LD_IND_8_INC(Ixl, PCl, PCh); break; // LD Ixl, n + case 0x2F: INT_OP(CPL, A); break; // CPL + case 0x30: JR_COND(!FlagC); break; // JR NC, r8 + case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn + case 0x32: LD_8_IND_nn(A); break; // LD (nn), A + case 0x33: INC_16(SPl, SPh); break; // INC SP + case 0x34: I_OP_n(INC8, Ixl, Ixh); break; // INC (Ix + n) + case 0x35: I_OP_n(DEC8, Ixl, Ixh); break; // DEC (Ix + n) + case 0x36: I_OP_n_n(Ixl, Ixh); break; // LD (Ix + n), n + case 0x37: INT_OP(SCF, A); break; // SCF + case 0x38: JR_COND(FlagC); break; // JR C, r8 + case 0x39: ADD_16(Ixl, Ixh, SPl, SPh); break; // ADD Ix, SP + case 0x3A: LD_IND_8_nn(A); break; // LD A, (nn) + case 0x3B: DEC_16(SPl, SPh); break; // DEC SP + case 0x3C: INT_OP(INC8, A); break; // INC A + case 0x3D: INT_OP(DEC8, A); break; // DEC A + case 0x3E: LD_IND_8_INC(A, PCl, PCh); break; // LD A, n + case 0x3F: INT_OP(CCF, A); break; // CCF + case 0x40: REG_OP(TR, B, B); break; // LD B, B + case 0x41: REG_OP(TR, B, C); break; // LD B, C + case 0x42: REG_OP(TR, B, D); break; // LD B, D + case 0x43: REG_OP(TR, B, E); break; // LD B, E + case 0x44: REG_OP(TR, B, Ixh); break; // LD B, Ixh + case 0x45: REG_OP(TR, B, Ixl); break; // LD B, Ixl + case 0x46: I_REG_OP_IND_n(TR, B, Ixl, Ixh); break; // LD B, (Ix + n) + case 0x47: REG_OP(TR, B, A); break; // LD B, A + case 0x48: REG_OP(TR, C, B); break; // LD C, B + case 0x49: REG_OP(TR, C, C); break; // LD C, C + case 0x4A: REG_OP(TR, C, D); break; // LD C, D + case 0x4B: REG_OP(TR, C, E); break; // LD C, E + case 0x4C: REG_OP(TR, C, Ixh); break; // LD C, Ixh + case 0x4D: REG_OP(TR, C, Ixl); break; // LD C, Ixl + case 0x4E: I_REG_OP_IND_n(TR, C, Ixl, Ixh); break; // LD C, (Ix + n) + case 0x4F: REG_OP(TR, C, A); break; // LD C, A + case 0x50: REG_OP(TR, D, B); break; // LD D, B + case 0x51: REG_OP(TR, D, C); break; // LD D, C + case 0x52: REG_OP(TR, D, D); break; // LD D, D + case 0x53: REG_OP(TR, D, E); break; // LD D, E + case 0x54: REG_OP(TR, D, Ixh); break; // LD D, Ixh + case 0x55: REG_OP(TR, D, Ixl); break; // LD D, Ixl + case 0x56: I_REG_OP_IND_n(TR, D, Ixl, Ixh); break; // LD D, (Ix + n) + case 0x57: REG_OP(TR, D, A); break; // LD D, A + case 0x58: REG_OP(TR, E, B); break; // LD E, B + case 0x59: REG_OP(TR, E, C); break; // LD E, C + case 0x5A: REG_OP(TR, E, D); break; // LD E, D + case 0x5B: REG_OP(TR, E, E); break; // LD E, E + case 0x5C: REG_OP(TR, E, Ixh); break; // LD E, Ixh + case 0x5D: REG_OP(TR, E, Ixl); break; // LD E, Ixl + case 0x5E: I_REG_OP_IND_n(TR, E, Ixl, Ixh); break; // LD E, (Ix + n) + case 0x5F: REG_OP(TR, E, A); break; // LD E, A + case 0x60: REG_OP(TR, Ixh, B); break; // LD Ixh, B + case 0x61: REG_OP(TR, Ixh, C); break; // LD Ixh, C + case 0x62: REG_OP(TR, Ixh, D); break; // LD Ixh, D + case 0x63: REG_OP(TR, Ixh, E); break; // LD Ixh, E + case 0x64: REG_OP(TR, Ixh, Ixh); break; // LD Ixh, Ixh + case 0x65: REG_OP(TR, Ixh, Ixl); break; // LD Ixh, Ixl + case 0x66: I_REG_OP_IND_n(TR, H, Ixl, Ixh); break; // LD H, (Ix + n) + case 0x67: REG_OP(TR, Ixh, A); break; // LD Ixh, A + case 0x68: REG_OP(TR, Ixl, B); break; // LD Ixl, B + case 0x69: REG_OP(TR, Ixl, C); break; // LD Ixl, C + case 0x6A: REG_OP(TR, Ixl, D); break; // LD Ixl, D + case 0x6B: REG_OP(TR, Ixl, E); break; // LD Ixl, E + case 0x6C: REG_OP(TR, Ixl, Ixh); break; // LD Ixl, Ixh + case 0x6D: REG_OP(TR, Ixl, Ixl); break; // LD Ixl, Ixl + case 0x6E: I_REG_OP_IND_n(TR, L, Ixl, Ixh); break; // LD L, (Ix + n) + case 0x6F: REG_OP(TR, Ixl, A); break; // LD Ixl, A + case 0x70: I_LD_8_IND_n(Ixl, Ixh, B); break; // LD (Ix + n), B + case 0x71: I_LD_8_IND_n(Ixl, Ixh, C); break; // LD (Ix + n), C + case 0x72: I_LD_8_IND_n(Ixl, Ixh, D); break; // LD (Ix + n), D + case 0x73: I_LD_8_IND_n(Ixl, Ixh, E); break; // LD (Ix + n), E + case 0x74: I_LD_8_IND_n(Ixl, Ixh, H); break; // LD (Ix + n), H + case 0x75: I_LD_8_IND_n(Ixl, Ixh, L); break; // LD (Ix + n), L + case 0x76: HALT_(); break; // HALT + case 0x77: I_LD_8_IND_n(Ixl, Ixh, A); break; // LD (Ix + n), A + case 0x78: REG_OP(TR, A, B); break; // LD A, B + case 0x79: REG_OP(TR, A, C); break; // LD A, C + case 0x7A: REG_OP(TR, A, D); break; // LD A, D + case 0x7B: REG_OP(TR, A, E); break; // LD A, E + case 0x7C: REG_OP(TR, A, Ixh); break; // LD A, Ixh + case 0x7D: REG_OP(TR, A, Ixl); break; // LD A, Ixl + case 0x7E: I_REG_OP_IND_n(TR, A, Ixl, Ixh); break; // LD A, (Ix + n) + case 0x7F: REG_OP(TR, A, A); break; // LD A, A + case 0x80: REG_OP(ADD8, A, B); break; // ADD A, B + case 0x81: REG_OP(ADD8, A, C); break; // ADD A, C + case 0x82: REG_OP(ADD8, A, D); break; // ADD A, D + case 0x83: REG_OP(ADD8, A, E); break; // ADD A, E + case 0x84: REG_OP(ADD8, A, Ixh); break; // ADD A, Ixh + case 0x85: REG_OP(ADD8, A, Ixl); break; // ADD A, Ixl + case 0x86: I_REG_OP_IND_n(ADD8, A, Ixl, Ixh); break; // ADD A, (Ix + n) + case 0x87: REG_OP(ADD8, A, A); break; // ADD A, A + case 0x88: REG_OP(ADC8, A, B); break; // ADC A, B + case 0x89: REG_OP(ADC8, A, C); break; // ADC A, C + case 0x8A: REG_OP(ADC8, A, D); break; // ADC A, D + case 0x8B: REG_OP(ADC8, A, E); break; // ADC A, E + case 0x8C: REG_OP(ADC8, A, Ixh); break; // ADC A, Ixh + case 0x8D: REG_OP(ADC8, A, Ixl); break; // ADC A, Ixl + case 0x8E: I_REG_OP_IND_n(ADC8, A, Ixl, Ixh); break; // ADC A, (Ix + n) + case 0x8F: REG_OP(ADC8, A, A); break; // ADC A, A + case 0x90: REG_OP(SUB8, A, B); break; // SUB A, B + case 0x91: REG_OP(SUB8, A, C); break; // SUB A, C + case 0x92: REG_OP(SUB8, A, D); break; // SUB A, D + case 0x93: REG_OP(SUB8, A, E); break; // SUB A, E + case 0x94: REG_OP(SUB8, A, Ixh); break; // SUB A, Ixh + case 0x95: REG_OP(SUB8, A, Ixl); break; // SUB A, Ixl + case 0x96: I_REG_OP_IND_n(SUB8, A, Ixl, Ixh); break; // SUB A, (Ix + n) + case 0x97: REG_OP(SUB8, A, A); break; // SUB A, A + case 0x98: REG_OP(SBC8, A, B); break; // SBC A, B + case 0x99: REG_OP(SBC8, A, C); break; // SBC A, C + case 0x9A: REG_OP(SBC8, A, D); break; // SBC A, D + case 0x9B: REG_OP(SBC8, A, E); break; // SBC A, E + case 0x9C: REG_OP(SBC8, A, Ixh); break; // SBC A, Ixh + case 0x9D: REG_OP(SBC8, A, Ixl); break; // SBC A, Ixl + case 0x9E: I_REG_OP_IND_n(SBC8, A, Ixl, Ixh); break; // SBC A, (Ix + n) + case 0x9F: REG_OP(SBC8, A, A); break; // SBC A, A + case 0xA0: REG_OP(AND8, A, B); break; // AND A, B + case 0xA1: REG_OP(AND8, A, C); break; // AND A, C + case 0xA2: REG_OP(AND8, A, D); break; // AND A, D + case 0xA3: REG_OP(AND8, A, E); break; // AND A, E + case 0xA4: REG_OP(AND8, A, Ixh); break; // AND A, Ixh + case 0xA5: REG_OP(AND8, A, Ixl); break; // AND A, Ixl + case 0xA6: I_REG_OP_IND_n(AND8, A, Ixl, Ixh); break; // AND A, (Ix + n) + case 0xA7: REG_OP(AND8, A, A); break; // AND A, A + case 0xA8: REG_OP(XOR8, A, B); break; // XOR A, B + case 0xA9: REG_OP(XOR8, A, C); break; // XOR A, C + case 0xAA: REG_OP(XOR8, A, D); break; // XOR A, D + case 0xAB: REG_OP(XOR8, A, E); break; // XOR A, E + case 0xAC: REG_OP(XOR8, A, Ixh); break; // XOR A, Ixh + case 0xAD: REG_OP(XOR8, A, Ixl); break; // XOR A, Ixl + case 0xAE: I_REG_OP_IND_n(XOR8, A, Ixl, Ixh); break; // XOR A, (Ix + n) + case 0xAF: REG_OP(XOR8, A, A); break; // XOR A, A + case 0xB0: REG_OP(OR8, A, B); break; // OR A, B + case 0xB1: REG_OP(OR8, A, C); break; // OR A, C + case 0xB2: REG_OP(OR8, A, D); break; // OR A, D + case 0xB3: REG_OP(OR8, A, E); break; // OR A, E + case 0xB4: REG_OP(OR8, A, Ixh); break; // OR A, Ixh + case 0xB5: REG_OP(OR8, A, Ixl); break; // OR A, Ixl + case 0xB6: I_REG_OP_IND_n(OR8, A, Ixl, Ixh); break; // OR A, (Ix + n) + case 0xB7: REG_OP(OR8, A, A); break; // OR A, A + case 0xB8: REG_OP(CP8, A, B); break; // CP A, B + case 0xB9: REG_OP(CP8, A, C); break; // CP A, C + case 0xBA: REG_OP(CP8, A, D); break; // CP A, D + case 0xBB: REG_OP(CP8, A, E); break; // CP A, E + case 0xBC: REG_OP(CP8, A, Ixh); break; // CP A, Ixh + case 0xBD: REG_OP(CP8, A, Ixl); break; // CP A, Ixl + case 0xBE: I_REG_OP_IND_n(CP8, A, Ixl, Ixh); break; // CP A, (Ix + n) + case 0xBF: REG_OP(CP8, A, A); break; // CP A, A + case 0xC0: RET_COND(!FlagZ); break; // Ret NZ + case 0xC1: POP_(C, B); break; // POP BC + case 0xC2: JP_COND(!FlagZ); break; // JP NZ + case 0xC3: JP_COND(true); break; // JP + case 0xC4: CALL_COND(!FlagZ); break; // CALL NZ + case 0xC5: PUSH_(C, B); break; // PUSH BC + case 0xC6: REG_OP_IND_INC(ADD8, A, PCl, PCh); break; // ADD A, n + case 0xC7: RST_(0); break; // RST 0 + case 0xC8: RET_COND(FlagZ); break; // RET Z + case 0xC9: RET_(); break; // RET + case 0xCA: JP_COND(FlagZ); break; // JP Z + case 0xCB: PREFIX_(IXCBpre); break; // PREFIX IXCB + case 0xCC: CALL_COND(FlagZ); break; // CALL Z + case 0xCD: CALL_COND(true); break; // CALL + case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n + case 0xCF: RST_(0x08); break; // RST 0x08 + case 0xD0: RET_COND(!FlagC); break; // Ret NC + case 0xD1: POP_(E, D); break; // POP DE + case 0xD2: JP_COND(!FlagC); break; // JP NC + case 0xD3: OUT_(); break; // OUT A + case 0xD4: CALL_COND(!FlagC); break; // CALL NC + case 0xD5: PUSH_(E, D); break; // PUSH DE + case 0xD6: REG_OP_IND_INC(SUB8, A, PCl, PCh); break; // SUB A, n + case 0xD7: RST_(0x10); break; // RST 0x10 + case 0xD8: RET_COND(FlagC); break; // RET C + case 0xD9: EXX_(); break; // EXX + case 0xDA: JP_COND(FlagC); break; // JP C + case 0xDB: IN_(); break; // IN A + case 0xDC: CALL_COND(FlagC); break; // CALL C + case 0xDD: PREFIX_(IXpre); break; // IX Prefix + case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n + case 0xDF: RST_(0x18); break; // RST 0x18 + case 0xE0: RET_COND(!FlagP); break; // RET Po + case 0xE1: POP_(Ixl, Ixh); break; // POP Ix + case 0xE2: JP_COND(!FlagP); break; // JP Po + case 0xE3: EXCH_16_IND_(SPl, SPh, Ixl, Ixh); break; // ex (SP), Ix + case 0xE4: CALL_COND(!FlagP); break; // CALL Po + case 0xE5: PUSH_(Ixl, Ixh); break; // PUSH Ix + case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n + case 0xE7: RST_(0x20); break; // RST 0x20 + case 0xE8: RET_COND(FlagP); break; // RET Pe + case 0xE9: JP_16(Ixl, Ixh); break; // JP (Ix) + case 0xEA: JP_COND(FlagP); break; // JP Pe + case 0xEB: EXCH_16_(E, D, L, H); break; // ex DE, HL + case 0xEC: CALL_COND(FlagP); break; // CALL Pe + case 0xED: PREFIX_(EXTDpre); break; // EXTD Prefix + case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n + case 0xEF: RST_(0x28); break; // RST 0x28 + case 0xF0: RET_COND(!FlagS); break; // RET p + case 0xF1: POP_(F, A); break; // POP AF + case 0xF2: JP_COND(!FlagS); break; // JP p + case 0xF3: DI_(); break; // DI + case 0xF4: CALL_COND(!FlagS); break; // CALL p + case 0xF5: PUSH_(F, A); break; // PUSH AF + case 0xF6: REG_OP_IND_INC(OR8, A, PCl, PCh); break; // OR A, n + case 0xF7: RST_(0x30); break; // RST 0x30 + case 0xF8: RET_COND(FlagS); break; // RET M + case 0xF9: LD_SP_16(Ixl, Ixh); break; // LD SP, Ix + case 0xFA: JP_COND(FlagS); break; // JP M + case 0xFB: EI_(); break; // EI + case 0xFC: CALL_COND(FlagS); break; // CALL M + case 0xFD: PREFIX_(IYpre); break; // IY Prefix + case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // CP A, n + case 0xFF: RST_(0x38); break; // RST $38 + } + } + else if (IY_prefix) + { + IY_prefix = false; + NO_prefix = true; + + switch (opcode) + { + case 0x00: NOP_(); break; // NOP + case 0x01: LD_IND_16(C, B, PCl, PCh); break; // LD BC, nn + case 0x02: LD_8_IND(C, B, A); break; // LD (BC), A + case 0x03: INC_16(C, B); break; // INC BC + case 0x04: INT_OP(INC8, B); break; // INC B + case 0x05: INT_OP(DEC8, B); break; // DEC B + case 0x06: LD_IND_8_INC(B, PCl, PCh); break; // LD B, n + case 0x07: INT_OP(RLC, Aim); break; // RLCA + case 0x08: EXCH_(); break; // EXCH AF, AF' + case 0x09: ADD_16(Iyl, Iyh, C, B); break; // ADD Iy, BC + case 0x0A: REG_OP_IND(TR, A, C, B); break; // LD A, (BC) + case 0x0B: DEC_16(C, B); break; // DEC BC + case 0x0C: INT_OP(INC8, C); break; // INC C + case 0x0D: INT_OP(DEC8, C); break; // DEC C + case 0x0E: LD_IND_8_INC(C, PCl, PCh); break; // LD C, n + case 0x0F: INT_OP(RRC, Aim); break; // RRCA + case 0x10: DJNZ_(); break; // DJNZ B + case 0x11: LD_IND_16(E, D, PCl, PCh); break; // LD DE, nn + case 0x12: LD_8_IND(E, D, A); break; // LD (DE), A + case 0x13: INC_16(E, D); break; // INC DE + case 0x14: INT_OP(INC8, D); break; // INC D + case 0x15: INT_OP(DEC8, D); break; // DEC D + case 0x16: LD_IND_8_INC(D, PCl, PCh); break; // LD D, n + case 0x17: INT_OP(RL, Aim); break; // RLA + case 0x18: JR_COND(true); break; // JR, r8 + case 0x19: ADD_16(Iyl, Iyh, E, D); break; // ADD Iy, DE + case 0x1A: REG_OP_IND(TR, A, E, D); break; // LD A, (DE) + case 0x1B: DEC_16(E, D); break; // DEC DE + case 0x1C: INT_OP(INC8, E); break; // INC E + case 0x1D: INT_OP(DEC8, E); break; // DEC E + case 0x1E: LD_IND_8_INC(E, PCl, PCh); break; // LD E, n + case 0x1F: INT_OP(RR, Aim); break; // RRA + case 0x20: JR_COND(!FlagZ); break; // JR NZ, r8 + case 0x21: LD_IND_16(Iyl, Iyh, PCl, PCh); break; // LD Iy, nn + case 0x22: LD_16_IND_nn(Iyl, Iyh); break; // LD (nn), Iy + case 0x23: INC_16(Iyl, Iyh); break; // INC Iy + case 0x24: INT_OP(INC8, Iyh); break; // INC Iyh + case 0x25: INT_OP(DEC8, Iyh); break; // DEC Iyh + case 0x26: LD_IND_8_INC(Iyh, PCl, PCh); break; // LD Iyh, n + case 0x27: INT_OP(DA, A); break; // DAA + case 0x28: JR_COND(FlagZ); break; // JR Z, r8 + case 0x29: ADD_16(Iyl, Iyh, Iyl, Iyh); break; // ADD Iy, Iy + case 0x2A: LD_IND_16_nn(Iyl, Iyh); break; // LD Iy, (nn) + case 0x2B: DEC_16(Iyl, Iyh); break; // DEC Iy + case 0x2C: INT_OP(INC8, Iyl); break; // INC Iyl + case 0x2D: INT_OP(DEC8, Iyl); break; // DEC Iyl + case 0x2E: LD_IND_8_INC(Iyl, PCl, PCh); break; // LD Iyl, n + case 0x2F: INT_OP(CPL, A); break; // CPL + case 0x30: JR_COND(!FlagC); break; // JR NC, r8 + case 0x31: LD_IND_16(SPl, SPh, PCl, PCh); break; // LD SP, nn + case 0x32: LD_8_IND_nn(A); break; // LD (nn), A + case 0x33: INC_16(SPl, SPh); break; // INC SP + case 0x34: I_OP_n(INC8, Iyl, Iyh); break; // INC (Iy + n) + case 0x35: I_OP_n(DEC8, Iyl, Iyh); break; // DEC (Iy + n) + case 0x36: I_OP_n_n(Iyl, Iyh); break; // LD (Iy + n), n + case 0x37: INT_OP(SCF, A); break; // SCF + case 0x38: JR_COND(FlagC); break; // JR C, r8 + case 0x39: ADD_16(Iyl, Iyh, SPl, SPh); break; // ADD Iy, SP + case 0x3A: LD_IND_8_nn(A); break; // LD A, (nn) + case 0x3B: DEC_16(SPl, SPh); break; // DEC SP + case 0x3C: INT_OP(INC8, A); break; // INC A + case 0x3D: INT_OP(DEC8, A); break; // DEC A + case 0x3E: LD_IND_8_INC(A, PCl, PCh); break; // LD A, n + case 0x3F: INT_OP(CCF, A); break; // CCF + case 0x40: REG_OP(TR, B, B); break; // LD B, B + case 0x41: REG_OP(TR, B, C); break; // LD B, C + case 0x42: REG_OP(TR, B, D); break; // LD B, D + case 0x43: REG_OP(TR, B, E); break; // LD B, E + case 0x44: REG_OP(TR, B, Iyh); break; // LD B, Iyh + case 0x45: REG_OP(TR, B, Iyl); break; // LD B, Iyl + case 0x46: I_REG_OP_IND_n(TR, B, Iyl, Iyh); break; // LD B, (Iy + n) + case 0x47: REG_OP(TR, B, A); break; // LD B, A + case 0x48: REG_OP(TR, C, B); break; // LD C, B + case 0x49: REG_OP(TR, C, C); break; // LD C, C + case 0x4A: REG_OP(TR, C, D); break; // LD C, D + case 0x4B: REG_OP(TR, C, E); break; // LD C, E + case 0x4C: REG_OP(TR, C, Iyh); break; // LD C, Iyh + case 0x4D: REG_OP(TR, C, Iyl); break; // LD C, Iyl + case 0x4E: I_REG_OP_IND_n(TR, C, Iyl, Iyh); break; // LD C, (Iy + n) + case 0x4F: REG_OP(TR, C, A); break; // LD C, A + case 0x50: REG_OP(TR, D, B); break; // LD D, B + case 0x51: REG_OP(TR, D, C); break; // LD D, C + case 0x52: REG_OP(TR, D, D); break; // LD D, D + case 0x53: REG_OP(TR, D, E); break; // LD D, E + case 0x54: REG_OP(TR, D, Iyh); break; // LD D, Iyh + case 0x55: REG_OP(TR, D, Iyl); break; // LD D, Iyl + case 0x56: I_REG_OP_IND_n(TR, D, Iyl, Iyh); break; // LD D, (Iy + n) + case 0x57: REG_OP(TR, D, A); break; // LD D, A + case 0x58: REG_OP(TR, E, B); break; // LD E, B + case 0x59: REG_OP(TR, E, C); break; // LD E, C + case 0x5A: REG_OP(TR, E, D); break; // LD E, D + case 0x5B: REG_OP(TR, E, E); break; // LD E, E + case 0x5C: REG_OP(TR, E, Iyh); break; // LD E, Iyh + case 0x5D: REG_OP(TR, E, Iyl); break; // LD E, Iyl + case 0x5E: I_REG_OP_IND_n(TR, E, Iyl, Iyh); break; // LD E, (Iy + n) + case 0x5F: REG_OP(TR, E, A); break; // LD E, A + case 0x60: REG_OP(TR, Iyh, B); break; // LD Iyh, B + case 0x61: REG_OP(TR, Iyh, C); break; // LD Iyh, C + case 0x62: REG_OP(TR, Iyh, D); break; // LD Iyh, D + case 0x63: REG_OP(TR, Iyh, E); break; // LD Iyh, E + case 0x64: REG_OP(TR, Iyh, Iyh); break; // LD Iyh, Iyh + case 0x65: REG_OP(TR, Iyh, Iyl); break; // LD Iyh, Iyl + case 0x66: I_REG_OP_IND_n(TR, H, Iyl, Iyh); break; // LD H, (Iy + n) + case 0x67: REG_OP(TR, Iyh, A); break; // LD Iyh, A + case 0x68: REG_OP(TR, Iyl, B); break; // LD Iyl, B + case 0x69: REG_OP(TR, Iyl, C); break; // LD Iyl, C + case 0x6A: REG_OP(TR, Iyl, D); break; // LD Iyl, D + case 0x6B: REG_OP(TR, Iyl, E); break; // LD Iyl, E + case 0x6C: REG_OP(TR, Iyl, Iyh); break; // LD Iyl, Iyh + case 0x6D: REG_OP(TR, Iyl, Iyl); break; // LD Iyl, Iyl + case 0x6E: I_REG_OP_IND_n(TR, L, Iyl, Iyh); break; // LD L, (Iy + n) + case 0x6F: REG_OP(TR, Iyl, A); break; // LD Iyl, A + case 0x70: I_LD_8_IND_n(Iyl, Iyh, B); break; // LD (Iy + n), B + case 0x71: I_LD_8_IND_n(Iyl, Iyh, C); break; // LD (Iy + n), C + case 0x72: I_LD_8_IND_n(Iyl, Iyh, D); break; // LD (Iy + n), D + case 0x73: I_LD_8_IND_n(Iyl, Iyh, E); break; // LD (Iy + n), E + case 0x74: I_LD_8_IND_n(Iyl, Iyh, H); break; // LD (Iy + n), H + case 0x75: I_LD_8_IND_n(Iyl, Iyh, L); break; // LD (Iy + n), L + case 0x76: HALT_(); break; // HALT + case 0x77: I_LD_8_IND_n(Iyl, Iyh, A); break; // LD (Iy + n), A + case 0x78: REG_OP(TR, A, B); break; // LD A, B + case 0x79: REG_OP(TR, A, C); break; // LD A, C + case 0x7A: REG_OP(TR, A, D); break; // LD A, D + case 0x7B: REG_OP(TR, A, E); break; // LD A, E + case 0x7C: REG_OP(TR, A, Iyh); break; // LD A, Iyh + case 0x7D: REG_OP(TR, A, Iyl); break; // LD A, Iyl + case 0x7E: I_REG_OP_IND_n(TR, A, Iyl, Iyh); break; // LD A, (Iy + n) + case 0x7F: REG_OP(TR, A, A); break; // LD A, A + case 0x80: REG_OP(ADD8, A, B); break; // ADD A, B + case 0x81: REG_OP(ADD8, A, C); break; // ADD A, C + case 0x82: REG_OP(ADD8, A, D); break; // ADD A, D + case 0x83: REG_OP(ADD8, A, E); break; // ADD A, E + case 0x84: REG_OP(ADD8, A, Iyh); break; // ADD A, Iyh + case 0x85: REG_OP(ADD8, A, Iyl); break; // ADD A, Iyl + case 0x86: I_REG_OP_IND_n(ADD8, A, Iyl, Iyh); break; // ADD A, (Iy + n) + case 0x87: REG_OP(ADD8, A, A); break; // ADD A, A + case 0x88: REG_OP(ADC8, A, B); break; // ADC A, B + case 0x89: REG_OP(ADC8, A, C); break; // ADC A, C + case 0x8A: REG_OP(ADC8, A, D); break; // ADC A, D + case 0x8B: REG_OP(ADC8, A, E); break; // ADC A, E + case 0x8C: REG_OP(ADC8, A, Iyh); break; // ADC A, Iyh + case 0x8D: REG_OP(ADC8, A, Iyl); break; // ADC A, Iyl + case 0x8E: I_REG_OP_IND_n(ADC8, A, Iyl, Iyh); break; // ADC A, (Iy + n) + case 0x8F: REG_OP(ADC8, A, A); break; // ADC A, A + case 0x90: REG_OP(SUB8, A, B); break; // SUB A, B + case 0x91: REG_OP(SUB8, A, C); break; // SUB A, C + case 0x92: REG_OP(SUB8, A, D); break; // SUB A, D + case 0x93: REG_OP(SUB8, A, E); break; // SUB A, E + case 0x94: REG_OP(SUB8, A, Iyh); break; // SUB A, Iyh + case 0x95: REG_OP(SUB8, A, Iyl); break; // SUB A, Iyl + case 0x96: I_REG_OP_IND_n(SUB8, A, Iyl, Iyh); break; // SUB A, (Iy + n) + case 0x97: REG_OP(SUB8, A, A); break; // SUB A, A + case 0x98: REG_OP(SBC8, A, B); break; // SBC A, B + case 0x99: REG_OP(SBC8, A, C); break; // SBC A, C + case 0x9A: REG_OP(SBC8, A, D); break; // SBC A, D + case 0x9B: REG_OP(SBC8, A, E); break; // SBC A, E + case 0x9C: REG_OP(SBC8, A, Iyh); break; // SBC A, Iyh + case 0x9D: REG_OP(SBC8, A, Iyl); break; // SBC A, Iyl + case 0x9E: I_REG_OP_IND_n(SBC8, A, Iyl, Iyh); break; // SBC A, (Iy + n) + case 0x9F: REG_OP(SBC8, A, A); break; // SBC A, A + case 0xA0: REG_OP(AND8, A, B); break; // AND A, B + case 0xA1: REG_OP(AND8, A, C); break; // AND A, C + case 0xA2: REG_OP(AND8, A, D); break; // AND A, D + case 0xA3: REG_OP(AND8, A, E); break; // AND A, E + case 0xA4: REG_OP(AND8, A, Iyh); break; // AND A, Iyh + case 0xA5: REG_OP(AND8, A, Iyl); break; // AND A, Iyl + case 0xA6: I_REG_OP_IND_n(AND8, A, Iyl, Iyh); break; // AND A, (Iy + n) + case 0xA7: REG_OP(AND8, A, A); break; // AND A, A + case 0xA8: REG_OP(XOR8, A, B); break; // XOR A, B + case 0xA9: REG_OP(XOR8, A, C); break; // XOR A, C + case 0xAA: REG_OP(XOR8, A, D); break; // XOR A, D + case 0xAB: REG_OP(XOR8, A, E); break; // XOR A, E + case 0xAC: REG_OP(XOR8, A, Iyh); break; // XOR A, Iyh + case 0xAD: REG_OP(XOR8, A, Iyl); break; // XOR A, Iyl + case 0xAE: I_REG_OP_IND_n(XOR8, A, Iyl, Iyh); break; // XOR A, (Iy + n) + case 0xAF: REG_OP(XOR8, A, A); break; // XOR A, A + case 0xB0: REG_OP(OR8, A, B); break; // OR A, B + case 0xB1: REG_OP(OR8, A, C); break; // OR A, C + case 0xB2: REG_OP(OR8, A, D); break; // OR A, D + case 0xB3: REG_OP(OR8, A, E); break; // OR A, E + case 0xB4: REG_OP(OR8, A, Iyh); break; // OR A, Iyh + case 0xB5: REG_OP(OR8, A, Iyl); break; // OR A, Iyl + case 0xB6: I_REG_OP_IND_n(OR8, A, Iyl, Iyh); break; // OR A, (Iy + n) + case 0xB7: REG_OP(OR8, A, A); break; // OR A, A + case 0xB8: REG_OP(CP8, A, B); break; // CP A, B + case 0xB9: REG_OP(CP8, A, C); break; // CP A, C + case 0xBA: REG_OP(CP8, A, D); break; // CP A, D + case 0xBB: REG_OP(CP8, A, E); break; // CP A, E + case 0xBC: REG_OP(CP8, A, Iyh); break; // CP A, Iyh + case 0xBD: REG_OP(CP8, A, Iyl); break; // CP A, Iyl + case 0xBE: I_REG_OP_IND_n(CP8, A, Iyl, Iyh); break; // CP A, (Iy + n) + case 0xBF: REG_OP(CP8, A, A); break; // CP A, A + case 0xC0: RET_COND(!FlagZ); break; // Ret NZ + case 0xC1: POP_(C, B); break; // POP BC + case 0xC2: JP_COND(!FlagZ); break; // JP NZ + case 0xC3: JP_COND(true); break; // JP + case 0xC4: CALL_COND(!FlagZ); break; // CALL NZ + case 0xC5: PUSH_(C, B); break; // PUSH BC + case 0xC6: REG_OP_IND_INC(ADD8, A, PCl, PCh); break; // ADD A, n + case 0xC7: RST_(0); break; // RST 0 + case 0xC8: RET_COND(FlagZ); break; // RET Z + case 0xC9: RET_(); break; // RET + case 0xCA: JP_COND(FlagZ); break; // JP Z + case 0xCB: PREFIX_(IYCBpre); break; // PREFIy IyCB + case 0xCC: CALL_COND(FlagZ); break; // CALL Z + case 0xCD: CALL_COND(true); break; // CALL + case 0xCE: REG_OP_IND_INC(ADC8, A, PCl, PCh); break; // ADC A, n + case 0xCF: RST_(0x08); break; // RST 0x08 + case 0xD0: RET_COND(!FlagC); break; // Ret NC + case 0xD1: POP_(E, D); break; // POP DE + case 0xD2: JP_COND(!FlagC); break; // JP NC + case 0xD3: OUT_(); break; // OUT A + case 0xD4: CALL_COND(!FlagC); break; // CALL NC + case 0xD5: PUSH_(E, D); break; // PUSH DE + case 0xD6: REG_OP_IND_INC(SUB8, A, PCl, PCh); break; // SUB A, n + case 0xD7: RST_(0x10); break; // RST 0x10 + case 0xD8: RET_COND(FlagC); break; // RET C + case 0xD9: EXX_(); break; // EXX + case 0xDA: JP_COND(FlagC); break; // JP C + case 0xDB: IN_(); break; // IN A + case 0xDC: CALL_COND(FlagC); break; // CALL C + case 0xDD: PREFIX_(IXpre); break; // IX Prefix + case 0xDE: REG_OP_IND_INC(SBC8, A, PCl, PCh); break; // SBC A, n + case 0xDF: RST_(0x18); break; // RST 0x18 + case 0xE0: RET_COND(!FlagP); break; // RET Po + case 0xE1: POP_(Iyl, Iyh); break; // POP Iy + case 0xE2: JP_COND(!FlagP); break; // JP Po + case 0xE3: EXCH_16_IND_(SPl, SPh, Iyl, Iyh); break; // ex (SP), Iy + case 0xE4: CALL_COND(!FlagP); break; // CALL Po + case 0xE5: PUSH_(Iyl, Iyh); break; // PUSH Iy + case 0xE6: REG_OP_IND_INC(AND8, A, PCl, PCh); break; // AND A, n + case 0xE7: RST_(0x20); break; // RST 0x20 + case 0xE8: RET_COND(FlagP); break; // RET Pe + case 0xE9: JP_16(Iyl, Iyh); break; // JP (Iy) + case 0xEA: JP_COND(FlagP); break; // JP Pe + case 0xEB: EXCH_16_(E, D, L, H); break; // ex DE, HL + case 0xEC: CALL_COND(FlagP); break; // CALL Pe + case 0xED: PREFIX_(EXTDpre); break; // EXTD Prefix + case 0xEE: REG_OP_IND_INC(XOR8, A, PCl, PCh); break; // XOR A, n + case 0xEF: RST_(0x28); break; // RST 0x28 + case 0xF0: RET_COND(!FlagS); break; // RET p + case 0xF1: POP_(F, A); break; // POP AF + case 0xF2: JP_COND(!FlagS); break; // JP p + case 0xF3: DI_(); break; // DI + case 0xF4: CALL_COND(!FlagS); break; // CALL p + case 0xF5: PUSH_(F, A); break; // PUSH AF + case 0xF6: REG_OP_IND_INC(OR8, A, PCl, PCh); break; // OR A, n + case 0xF7: RST_(0x30); break; // RST 0x30 + case 0xF8: RET_COND(FlagS); break; // RET M + case 0xF9: LD_SP_16(Iyl, Iyh); break; // LD SP, Iy + case 0xFA: JP_COND(FlagS); break; // JP M + case 0xFB: EI_(); break; // EI + case 0xFC: CALL_COND(FlagS); break; // CALL M + case 0xFD: PREFIX_(IYpre); break; // IY Prefix + case 0xFE: REG_OP_IND_INC(CP8, A, PCl, PCh); break; // CP A, n + case 0xFF: RST_(0x38); break; // RST $38 + } + } + else if (IXCB_prefix || IYCB_prefix) + { + // the first byte fetched is the prefetch value to use with the instruction + // we pick Ix or Iy here, the indexed value is stored in WZ + // In this way, we don't need to pass them as an argument to the I_Funcs. + if (IXCB_prefetch) + { + IXCB_prefetch = false; + PF = opcode; + Regs[ALU] = PF; + PREFETCH_(Ixl, Ixh); + return; + } + + if (IYCB_prefetch) + { + IYCB_prefetch = false; + PF = opcode; + Regs[ALU] = PF; + PREFETCH_(Iyl, Iyh); + return; + } + + IXCB_prefix = false; + IYCB_prefix = false; + NO_prefix = true; + + switch (opcode) + { + case 0x00: I_INT_OP(RLC, B); break; // RLC (I* + n) -> B + case 0x01: I_INT_OP(RLC, C); break; // RLC (I* + n) -> C + case 0x02: I_INT_OP(RLC, D); break; // RLC (I* + n) -> D + case 0x03: I_INT_OP(RLC, E); break; // RLC (I* + n) -> E + case 0x04: I_INT_OP(RLC, H); break; // RLC (I* + n) -> H + case 0x05: I_INT_OP(RLC, L); break; // RLC (I* + n) -> L + case 0x06: I_INT_OP(RLC, ALU); break; // RLC (I* + n) + case 0x07: I_INT_OP(RLC, A); break; // RLC (I* + n) -> A + case 0x08: I_INT_OP(RRC, B); break; // RRC (I* + n) -> B + case 0x09: I_INT_OP(RRC, C); break; // RRC (I* + n) -> C + case 0x0A: I_INT_OP(RRC, D); break; // RRC (I* + n) -> D + case 0x0B: I_INT_OP(RRC, E); break; // RRC (I* + n) -> E + case 0x0C: I_INT_OP(RRC, H); break; // RRC (I* + n) -> H + case 0x0D: I_INT_OP(RRC, L); break; // RRC (I* + n) -> L + case 0x0E: I_INT_OP(RRC, ALU); break; // RRC (I* + n) + case 0x0F: I_INT_OP(RRC, A); break; // RRC (I* + n) -> A + case 0x10: I_INT_OP(RL, B); break; // RL (I* + n) -> B + case 0x11: I_INT_OP(RL, C); break; // RL (I* + n) -> C + case 0x12: I_INT_OP(RL, D); break; // RL (I* + n) -> D + case 0x13: I_INT_OP(RL, E); break; // RL (I* + n) -> E + case 0x14: I_INT_OP(RL, H); break; // RL (I* + n) -> H + case 0x15: I_INT_OP(RL, L); break; // RL (I* + n) -> L + case 0x16: I_INT_OP(RL, ALU); break; // RL (I* + n) + case 0x17: I_INT_OP(RL, A); break; // RL (I* + n) -> A + case 0x18: I_INT_OP(RR, B); break; // RR (I* + n) -> B + case 0x19: I_INT_OP(RR, C); break; // RR (I* + n) -> C + case 0x1A: I_INT_OP(RR, D); break; // RR (I* + n) -> D + case 0x1B: I_INT_OP(RR, E); break; // RR (I* + n) -> E + case 0x1C: I_INT_OP(RR, H); break; // RR (I* + n) -> H + case 0x1D: I_INT_OP(RR, L); break; // RR (I* + n) -> L + case 0x1E: I_INT_OP(RR, ALU); break; // RR (I* + n) + case 0x1F: I_INT_OP(RR, A); break; // RR (I* + n) -> A + case 0x20: I_INT_OP(SLA, B); break; // SLA (I* + n) -> B + case 0x21: I_INT_OP(SLA, C); break; // SLA (I* + n) -> C + case 0x22: I_INT_OP(SLA, D); break; // SLA (I* + n) -> D + case 0x23: I_INT_OP(SLA, E); break; // SLA (I* + n) -> E + case 0x24: I_INT_OP(SLA, H); break; // SLA (I* + n) -> H + case 0x25: I_INT_OP(SLA, L); break; // SLA (I* + n) -> L + case 0x26: I_INT_OP(SLA, ALU); break; // SLA (I* + n) + case 0x27: I_INT_OP(SLA, A); break; // SLA (I* + n) -> A + case 0x28: I_INT_OP(SRA, B); break; // SRA (I* + n) -> B + case 0x29: I_INT_OP(SRA, C); break; // SRA (I* + n) -> C + case 0x2A: I_INT_OP(SRA, D); break; // SRA (I* + n) -> D + case 0x2B: I_INT_OP(SRA, E); break; // SRA (I* + n) -> E + case 0x2C: I_INT_OP(SRA, H); break; // SRA (I* + n) -> H + case 0x2D: I_INT_OP(SRA, L); break; // SRA (I* + n) -> L + case 0x2E: I_INT_OP(SRA, ALU); break; // SRA (I* + n) + case 0x2F: I_INT_OP(SRA, A); break; // SRA (I* + n) -> A + case 0x30: I_INT_OP(SLL, B); break; // SLL (I* + n) -> B + case 0x31: I_INT_OP(SLL, C); break; // SLL (I* + n) -> C + case 0x32: I_INT_OP(SLL, D); break; // SLL (I* + n) -> D + case 0x33: I_INT_OP(SLL, E); break; // SLL (I* + n) -> E + case 0x34: I_INT_OP(SLL, H); break; // SLL (I* + n) -> H + case 0x35: I_INT_OP(SLL, L); break; // SLL (I* + n) -> L + case 0x36: I_INT_OP(SLL, ALU); break; // SLL (I* + n) + case 0x37: I_INT_OP(SLL, A); break; // SLL (I* + n) -> A + case 0x38: I_INT_OP(SRL, B); break; // SRL (I* + n) -> B + case 0x39: I_INT_OP(SRL, C); break; // SRL (I* + n) -> C + case 0x3A: I_INT_OP(SRL, D); break; // SRL (I* + n) -> D + case 0x3B: I_INT_OP(SRL, E); break; // SRL (I* + n) -> E + case 0x3C: I_INT_OP(SRL, H); break; // SRL (I* + n) -> H + case 0x3D: I_INT_OP(SRL, L); break; // SRL (I* + n) -> L + case 0x3E: I_INT_OP(SRL, ALU); break; // SRL (I* + n) + case 0x3F: I_INT_OP(SRL, A); break; // SRL (I* + n) -> A + case 0x40: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x41: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x42: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x43: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x44: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x45: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x46: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x47: I_BIT_TE(0); break; // BIT 0, (I* + n) + case 0x48: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x49: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4A: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4B: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4C: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4D: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4E: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x4F: I_BIT_TE(1); break; // BIT 1, (I* + n) + case 0x50: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x51: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x52: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x53: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x54: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x55: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x56: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x57: I_BIT_TE(2); break; // BIT 2, (I* + n) + case 0x58: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x59: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5A: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5B: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5C: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5D: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5E: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x5F: I_BIT_TE(3); break; // BIT 3, (I* + n) + case 0x60: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x61: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x62: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x63: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x64: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x65: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x66: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x67: I_BIT_TE(4); break; // BIT 4, (I* + n) + case 0x68: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x69: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6A: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6B: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6C: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6D: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6E: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x6F: I_BIT_TE(5); break; // BIT 5, (I* + n) + case 0x70: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x71: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x72: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x73: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x74: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x75: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x76: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x77: I_BIT_TE(6); break; // BIT 6, (I* + n) + case 0x78: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x79: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7A: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7B: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7C: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7D: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7E: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x7F: I_BIT_TE(7); break; // BIT 7, (I* + n) + case 0x80: I_BIT_OP(RES, 0, B); break; // RES 0, (I* + n) -> B + case 0x81: I_BIT_OP(RES, 0, C); break; // RES 0, (I* + n) -> C + case 0x82: I_BIT_OP(RES, 0, D); break; // RES 0, (I* + n) -> D + case 0x83: I_BIT_OP(RES, 0, E); break; // RES 0, (I* + n) -> E + case 0x84: I_BIT_OP(RES, 0, H); break; // RES 0, (I* + n) -> H + case 0x85: I_BIT_OP(RES, 0, L); break; // RES 0, (I* + n) -> L + case 0x86: I_BIT_OP(RES, 0, ALU); break; // RES 0, (I* + n) + case 0x87: I_BIT_OP(RES, 0, A); break; // RES 0, (I* + n) -> A + case 0x88: I_BIT_OP(RES, 1, B); break; // RES 1, (I* + n) -> B + case 0x89: I_BIT_OP(RES, 1, C); break; // RES 1, (I* + n) -> C + case 0x8A: I_BIT_OP(RES, 1, D); break; // RES 1, (I* + n) -> D + case 0x8B: I_BIT_OP(RES, 1, E); break; // RES 1, (I* + n) -> E + case 0x8C: I_BIT_OP(RES, 1, H); break; // RES 1, (I* + n) -> H + case 0x8D: I_BIT_OP(RES, 1, L); break; // RES 1, (I* + n) -> L + case 0x8E: I_BIT_OP(RES, 1, ALU); break; // RES 1, (I* + n) + case 0x8F: I_BIT_OP(RES, 1, A); break; // RES 1, (I* + n) -> A + case 0x90: I_BIT_OP(RES, 2, B); break; // RES 2, (I* + n) -> B + case 0x91: I_BIT_OP(RES, 2, C); break; // RES 2, (I* + n) -> C + case 0x92: I_BIT_OP(RES, 2, D); break; // RES 2, (I* + n) -> D + case 0x93: I_BIT_OP(RES, 2, E); break; // RES 2, (I* + n) -> E + case 0x94: I_BIT_OP(RES, 2, H); break; // RES 2, (I* + n) -> H + case 0x95: I_BIT_OP(RES, 2, L); break; // RES 2, (I* + n) -> L + case 0x96: I_BIT_OP(RES, 2, ALU); break; // RES 2, (I* + n) + case 0x97: I_BIT_OP(RES, 2, A); break; // RES 2, (I* + n) -> A + case 0x98: I_BIT_OP(RES, 3, B); break; // RES 3, (I* + n) -> B + case 0x99: I_BIT_OP(RES, 3, C); break; // RES 3, (I* + n) -> C + case 0x9A: I_BIT_OP(RES, 3, D); break; // RES 3, (I* + n) -> D + case 0x9B: I_BIT_OP(RES, 3, E); break; // RES 3, (I* + n) -> E + case 0x9C: I_BIT_OP(RES, 3, H); break; // RES 3, (I* + n) -> H + case 0x9D: I_BIT_OP(RES, 3, L); break; // RES 3, (I* + n) -> L + case 0x9E: I_BIT_OP(RES, 3, ALU); break; // RES 3, (I* + n) + case 0x9F: I_BIT_OP(RES, 3, A); break; // RES 3, (I* + n) -> A + case 0xA0: I_BIT_OP(RES, 4, B); break; // RES 4, (I* + n) -> B + case 0xA1: I_BIT_OP(RES, 4, C); break; // RES 4, (I* + n) -> C + case 0xA2: I_BIT_OP(RES, 4, D); break; // RES 4, (I* + n) -> D + case 0xA3: I_BIT_OP(RES, 4, E); break; // RES 4, (I* + n) -> E + case 0xA4: I_BIT_OP(RES, 4, H); break; // RES 4, (I* + n) -> H + case 0xA5: I_BIT_OP(RES, 4, L); break; // RES 4, (I* + n) -> L + case 0xA6: I_BIT_OP(RES, 4, ALU); break; // RES 4, (I* + n) + case 0xA7: I_BIT_OP(RES, 4, A); break; // RES 4, (I* + n) -> A + case 0xA8: I_BIT_OP(RES, 5, B); break; // RES 5, (I* + n) -> B + case 0xA9: I_BIT_OP(RES, 5, C); break; // RES 5, (I* + n) -> C + case 0xAA: I_BIT_OP(RES, 5, D); break; // RES 5, (I* + n) -> D + case 0xAB: I_BIT_OP(RES, 5, E); break; // RES 5, (I* + n) -> E + case 0xAC: I_BIT_OP(RES, 5, H); break; // RES 5, (I* + n) -> H + case 0xAD: I_BIT_OP(RES, 5, L); break; // RES 5, (I* + n) -> L + case 0xAE: I_BIT_OP(RES, 5, ALU); break; // RES 5, (I* + n) + case 0xAF: I_BIT_OP(RES, 5, A); break; // RES 5, (I* + n) -> A + case 0xB0: I_BIT_OP(RES, 6, B); break; // RES 6, (I* + n) -> B + case 0xB1: I_BIT_OP(RES, 6, C); break; // RES 6, (I* + n) -> C + case 0xB2: I_BIT_OP(RES, 6, D); break; // RES 6, (I* + n) -> D + case 0xB3: I_BIT_OP(RES, 6, E); break; // RES 6, (I* + n) -> E + case 0xB4: I_BIT_OP(RES, 6, H); break; // RES 6, (I* + n) -> H + case 0xB5: I_BIT_OP(RES, 6, L); break; // RES 6, (I* + n) -> L + case 0xB6: I_BIT_OP(RES, 6, ALU); break; // RES 6, (I* + n) + case 0xB7: I_BIT_OP(RES, 6, A); break; // RES 6, (I* + n) -> A + case 0xB8: I_BIT_OP(RES, 7, B); break; // RES 7, (I* + n) -> B + case 0xB9: I_BIT_OP(RES, 7, C); break; // RES 7, (I* + n) -> C + case 0xBA: I_BIT_OP(RES, 7, D); break; // RES 7, (I* + n) -> D + case 0xBB: I_BIT_OP(RES, 7, E); break; // RES 7, (I* + n) -> E + case 0xBC: I_BIT_OP(RES, 7, H); break; // RES 7, (I* + n) -> H + case 0xBD: I_BIT_OP(RES, 7, L); break; // RES 7, (I* + n) -> L + case 0xBE: I_BIT_OP(RES, 7, ALU); break; // RES 7, (I* + n) + case 0xBF: I_BIT_OP(RES, 7, A); break; // RES 7, (I* + n) -> A + case 0xC0: I_BIT_OP(SET, 0, B); break; // SET 0, (I* + n) -> B + case 0xC1: I_BIT_OP(SET, 0, C); break; // SET 0, (I* + n) -> C + case 0xC2: I_BIT_OP(SET, 0, D); break; // SET 0, (I* + n) -> D + case 0xC3: I_BIT_OP(SET, 0, E); break; // SET 0, (I* + n) -> E + case 0xC4: I_BIT_OP(SET, 0, H); break; // SET 0, (I* + n) -> H + case 0xC5: I_BIT_OP(SET, 0, L); break; // SET 0, (I* + n) -> L + case 0xC6: I_BIT_OP(SET, 0, ALU); break; // SET 0, (I* + n) + case 0xC7: I_BIT_OP(SET, 0, A); break; // SET 0, (I* + n) -> A + case 0xC8: I_BIT_OP(SET, 1, B); break; // SET 1, (I* + n) -> B + case 0xC9: I_BIT_OP(SET, 1, C); break; // SET 1, (I* + n) -> C + case 0xCA: I_BIT_OP(SET, 1, D); break; // SET 1, (I* + n) -> D + case 0xCB: I_BIT_OP(SET, 1, E); break; // SET 1, (I* + n) -> E + case 0xCC: I_BIT_OP(SET, 1, H); break; // SET 1, (I* + n) -> H + case 0xCD: I_BIT_OP(SET, 1, L); break; // SET 1, (I* + n) -> L + case 0xCE: I_BIT_OP(SET, 1, ALU); break; // SET 1, (I* + n) + case 0xCF: I_BIT_OP(SET, 1, A); break; // SET 1, (I* + n) -> A + case 0xD0: I_BIT_OP(SET, 2, B); break; // SET 2, (I* + n) -> B + case 0xD1: I_BIT_OP(SET, 2, C); break; // SET 2, (I* + n) -> C + case 0xD2: I_BIT_OP(SET, 2, D); break; // SET 2, (I* + n) -> D + case 0xD3: I_BIT_OP(SET, 2, E); break; // SET 2, (I* + n) -> E + case 0xD4: I_BIT_OP(SET, 2, H); break; // SET 2, (I* + n) -> H + case 0xD5: I_BIT_OP(SET, 2, L); break; // SET 2, (I* + n) -> L + case 0xD6: I_BIT_OP(SET, 2, ALU); break; // SET 2, (I* + n) + case 0xD7: I_BIT_OP(SET, 2, A); break; // SET 2, (I* + n) -> A + case 0xD8: I_BIT_OP(SET, 3, B); break; // SET 3, (I* + n) -> B + case 0xD9: I_BIT_OP(SET, 3, C); break; // SET 3, (I* + n) -> C + case 0xDA: I_BIT_OP(SET, 3, D); break; // SET 3, (I* + n) -> D + case 0xDB: I_BIT_OP(SET, 3, E); break; // SET 3, (I* + n) -> E + case 0xDC: I_BIT_OP(SET, 3, H); break; // SET 3, (I* + n) -> H + case 0xDD: I_BIT_OP(SET, 3, L); break; // SET 3, (I* + n) -> L + case 0xDE: I_BIT_OP(SET, 3, ALU); break; // SET 3, (I* + n) + case 0xDF: I_BIT_OP(SET, 3, A); break; // SET 3, (I* + n) -> A + case 0xE0: I_BIT_OP(SET, 4, B); break; // SET 4, (I* + n) -> B + case 0xE1: I_BIT_OP(SET, 4, C); break; // SET 4, (I* + n) -> C + case 0xE2: I_BIT_OP(SET, 4, D); break; // SET 4, (I* + n) -> D + case 0xE3: I_BIT_OP(SET, 4, E); break; // SET 4, (I* + n) -> E + case 0xE4: I_BIT_OP(SET, 4, H); break; // SET 4, (I* + n) -> H + case 0xE5: I_BIT_OP(SET, 4, L); break; // SET 4, (I* + n) -> L + case 0xE6: I_BIT_OP(SET, 4, ALU); break; // SET 4, (I* + n) + case 0xE7: I_BIT_OP(SET, 4, A); break; // SET 4, (I* + n) -> A + case 0xE8: I_BIT_OP(SET, 5, B); break; // SET 5, (I* + n) -> B + case 0xE9: I_BIT_OP(SET, 5, C); break; // SET 5, (I* + n) -> C + case 0xEA: I_BIT_OP(SET, 5, D); break; // SET 5, (I* + n) -> D + case 0xEB: I_BIT_OP(SET, 5, E); break; // SET 5, (I* + n) -> E + case 0xEC: I_BIT_OP(SET, 5, H); break; // SET 5, (I* + n) -> H + case 0xED: I_BIT_OP(SET, 5, L); break; // SET 5, (I* + n) -> L + case 0xEE: I_BIT_OP(SET, 5, ALU); break; // SET 5, (I* + n) + case 0xEF: I_BIT_OP(SET, 5, A); break; // SET 5, (I* + n) -> A + case 0xF0: I_BIT_OP(SET, 6, B); break; // SET 6, (I* + n) -> B + case 0xF1: I_BIT_OP(SET, 6, C); break; // SET 6, (I* + n) -> C + case 0xF2: I_BIT_OP(SET, 6, D); break; // SET 6, (I* + n) -> D + case 0xF3: I_BIT_OP(SET, 6, E); break; // SET 6, (I* + n) -> E + case 0xF4: I_BIT_OP(SET, 6, H); break; // SET 6, (I* + n) -> H + case 0xF5: I_BIT_OP(SET, 6, L); break; // SET 6, (I* + n) -> L + case 0xF6: I_BIT_OP(SET, 6, ALU); break; // SET 6, (I* + n) + case 0xF7: I_BIT_OP(SET, 6, A); break; // SET 6, (I* + n) -> A + case 0xF8: I_BIT_OP(SET, 7, B); break; // SET 7, (I* + n) -> B + case 0xF9: I_BIT_OP(SET, 7, C); break; // SET 7, (I* + n) -> C + case 0xFA: I_BIT_OP(SET, 7, D); break; // SET 7, (I* + n) -> D + case 0xFB: I_BIT_OP(SET, 7, E); break; // SET 7, (I* + n) -> E + case 0xFC: I_BIT_OP(SET, 7, H); break; // SET 7, (I* + n) -> H + case 0xFD: I_BIT_OP(SET, 7, L); break; // SET 7, (I* + n) -> L + case 0xFE: I_BIT_OP(SET, 7, ALU); break; // SET 7, (I* + n) + case 0xFF: I_BIT_OP(SET, 7, A); break; // SET 7, (I* + n) -> A + } + } + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs new file mode 100644 index 0000000000..8dc1cd24ce --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Interrupts.cs @@ -0,0 +1,123 @@ +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + private bool iff1; + public bool IFF1 { get { return iff1; } set { iff1 = value; } } + + private bool iff2; + public bool IFF2 { get { return iff2; } set { iff2 = value; } } + + private bool nonMaskableInterrupt; + public bool NonMaskableInterrupt + { + get { return nonMaskableInterrupt; } + set { if (value && !nonMaskableInterrupt) NonMaskableInterruptPending = true; nonMaskableInterrupt = value; } + } + + private bool nonMaskableInterruptPending; + public bool NonMaskableInterruptPending { get { return nonMaskableInterruptPending; } set { nonMaskableInterruptPending = value; } } + + private int interruptMode; + public int InterruptMode + { + get { return interruptMode; } + set { if (value < 0 || value > 2) throw new ArgumentOutOfRangeException(); interruptMode = value; } + } + + public Action IRQCallback = delegate () { }; + public Action NMICallback = delegate () { }; + + private void NMI_() + { + cur_instr = new ushort[] + {IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCh, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + ASGN, PCl, 0x66, + ASGN, PCh, 0, + IDLE, + OP }; + } + + // Mode 0 interrupts only take effect if a CALL or RST is on the data bus + // Otherwise operation just continues as normal + // For now assume a NOP is on the data bus, in which case no stack operations occur + + //NOTE: TODO: When a CALL is present on the data bus, adjust WZ accordingly + private void INTERRUPT_0(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + OP }; + } + + // Just jump to $0038 + private void INTERRUPT_1() + { + cur_instr = new ushort[] + {DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, PCh, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, PCl, + IDLE, + ASGN, PCl, 0x38, + IDLE, + ASGN, PCh, 0, + IDLE, + OP }; + } + + // Interrupt mode 2 uses the I vector combined with a byte on the data bus + // Again for now we assume only a 0 on the data bus and jump to (0xI00) + private void INTERRUPT_2(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCh, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + ASGN, PCl, 0, + TR, PCh, I, + IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + TR16, PCl, PCh, Z, W, + OP }; + } + + private static ushort[] INT_vectors = new ushort[] {0x40, 0x48, 0x50, 0x58, 0x60}; + + private void ResetInterrupts() + { + IFF1 = false; + IFF2 = false; + NonMaskableInterrupt = false; + NonMaskableInterruptPending = false; + FlagI = false; + InterruptMode = 1; + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80/Disassembler.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs similarity index 89% rename from BizHawk.Emulation.Cores/CPUs/Z80/Disassembler.cs rename to BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs index d5b9c2c4e1..6ac1a76444 100644 --- a/BizHawk.Emulation.Cores/CPUs/Z80/Disassembler.cs +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/NewDisassembler.cs @@ -1,114 +1,27 @@ -//http://www.zophar.net/fileuploads/2/10819kouzv/z80undoc.html - -//TODO: ex. (IX+00h) could be turned into (IX) - -//usage: -//VgMuseum.Z80.Disassembler disasm = new Disassembler(); -//ushort pc = RegPC.Word; -//string str = disasm.Disassemble(() => ReadMemory(pc++)); -//Console.WriteLine(str); - -//please note that however much youre tempted to, timings can't be put in a table here because they depend on how the instruction executes at runtime - -using System; +using System; using System.Collections.Generic; using BizHawk.Emulation.Common; -namespace BizHawk.Emulation.Cores.Components.Z80 +namespace BizHawk.Emulation.Cores.Components.Z80A { - public class Disassembler : IDisassemblable + public sealed partial class Z80A : IDisassemblable { - readonly static sbyte[,] opcodeSizes = new sbyte[7, 256]; - - public static void GenerateOpcodeSizes() - { - Disassembler disasm = new Disassembler(); - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[0, i] = (sbyte)pc; - } - - opcodeSizes[0, 0xCB] = -1; - opcodeSizes[0, 0xED] = -2; - opcodeSizes[0, 0xDD] = -3; - opcodeSizes[0, 0xFD] = -4; - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xCB, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[1, i] = (sbyte)pc; - } - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xED, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[2, i] = (sbyte)pc; - } - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xDD, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[3, i] = (sbyte)pc; - } - - opcodeSizes[3, 0xCB] = -5; - opcodeSizes[3, 0xED] = -2; - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xFD, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[4, i] = (sbyte)pc; - } - - opcodeSizes[3, 0xCB] = -6; - opcodeSizes[3, 0xED] = -2; - - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xDD, 0xCB, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[5, i] = (sbyte)pc; - } - - for (int i = 0; i < 256; i++) - { - int pc = 0; - byte[] opcode = { 0xFD, 0xCB, (byte)i, 0, 0, 0 }; - disasm.Disassemble(() => opcode[pc++]); - opcodeSizes[6, i] = (sbyte)pc; - } - } - - static string Result(string format, Func read) + static string Result(string format, Func read, ref ushort addr) { //d immediately succeeds the opcode //n immediate succeeds the opcode and the displacement (if present) //nn immediately succeeds the opcode and the displacement (if present) if (format.IndexOf("nn") != -1) { - byte B = read(); - byte C = read(); + byte B = read(addr++); + byte C = read(addr++); format = format.Replace("nn", string.Format("{0:X4}h", B + C * 256)); } if (format.IndexOf("n") != -1) { - byte B = read(); + byte B = read(addr++); format = format.Replace("n", string.Format("{0:X2}h", B)); } @@ -116,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Components.Z80 if (format.IndexOf("d") != -1) { - byte B = read(); + byte B = read(addr++); bool neg = ((B & 0x80) != 0); char sign = neg ? '-' : '+'; int val = neg ? 256 - B : B; @@ -480,46 +393,49 @@ namespace BizHawk.Emulation.Cores.Components.Z80 "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", "NOP", //0x100 }; - string DisassembleInternal(Func read) + public string Disassemble(ushort addr, Func read, out ushort size) { - byte A = read(); + ushort start_addr = addr; + ushort extra_inc = 0; + byte A = read(addr++); string format; switch (A) { case 0xCB: - A = read(); + A = read(addr++); format = mnemonicsCB[A]; break; case 0xDD: - A = read(); + A = read(addr++); switch (A) { - case 0xCB: format = mnemonicsDDCB[A]; break; + case 0xCB: format = mnemonicsDDCB[read((ushort)(addr + 1))]; extra_inc = 1; break; case 0xED: format = mnemonicsED[A]; break; default: format = mnemonicsDD[A]; break; } break; case 0xED: - A = read(); + A = read(addr++); format = mnemonicsED[A]; break; case 0xFD: - A = read(); + A = read(addr++); switch (A) { - case 0xCB: format = mnemonicsFDCB[A]; break; + case 0xCB: format = mnemonicsFDCB[read((ushort)(addr + 1))]; extra_inc = 1; break; case 0xED: format = mnemonicsED[A]; break; default: format = mnemonicsFD[A]; break; } break; default: format = mnemonics[A]; break; } - return format; - } + + string temp = Result(format, read, ref addr); - public string Disassemble(Func read) - { - return Result(DisassembleInternal(read), read); + addr += extra_inc; + + size = (ushort)(addr - start_addr); + return temp; } #region IDisassemblable @@ -543,7 +459,8 @@ namespace BizHawk.Emulation.Cores.Components.Z80 public string Disassemble(MemoryDomain m, uint addr, out int length) { int loc = (int)addr; - string ret = Disassemble(() => m.PeekByte(loc++)); + ushort unused = 0; + string ret = Disassemble((ushort) addr, a => m.PeekByte(a), out unused); length = loc - (int)addr; return ret; } diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs new file mode 100644 index 0000000000..cfaf517ec7 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Operations.cs @@ -0,0 +1,742 @@ +using BizHawk.Common.NumberExtensions; +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + public void Read_Func(ushort dest, ushort src_l, ushort src_h) + { + Regs[dest] = ReadMemory((ushort)(Regs[src_l] | (Regs[src_h]) << 8)); + } + + public void I_Read_Func(ushort dest, ushort src_l, ushort src_h, ushort inc) + { + Regs[dest] = ReadMemory((ushort)((Regs[src_l] | (Regs[src_h] << 8)) + inc)); + } + + public void Write_Func(ushort dest_l, ushort dest_h, ushort src) + { + WriteMemory((ushort)(Regs[dest_l] | (Regs[dest_h] << 8)), (byte)Regs[src]); + } + + public void I_Write_Func(ushort dest_l, ushort dest_h, ushort inc, ushort src) + { + WriteMemory((ushort)((Regs[dest_l] | (Regs[dest_h] << 8)) + inc), (byte)Regs[src]); + } + + public void OUT_Func(ushort dest, ushort src) + { + WriteHardware(Regs[dest], (byte)(Regs[src])); + } + + public void IN_Func(ushort dest, ushort src) + { + Regs[dest] = ReadHardware(Regs[src]); + } + + public void TR_Func(ushort dest, ushort src) + { + Regs[dest] = Regs[src]; + } + + public void TR16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + Regs[dest_l] = Regs[src_l]; + Regs[dest_h] = Regs[src_h]; + } + + public void ADD16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + int temp = Reg16_d + Reg16_s; + + FlagC = temp.Bit(16); + FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF)) > 0xFFF; + FlagN = false; + Flag3 = (temp & 0x0800) != 0; + Flag5 = (temp & 0x2000) != 0; + + Regs[dest_l] = (ushort)(temp & 0xFF); + Regs[dest_h] = (ushort)((temp & 0xFF00) >> 8); + } + + public void ADD8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d += Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = false; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void SUB8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = true; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void BIT_Func(ushort bit, ushort src) + { + FlagZ = !Regs[src].Bit(bit); + FlagP = FlagZ; // special case + FlagH = true; + FlagN = false; + FlagS = ((bit == 7) && Regs[src].Bit(bit)); + Flag5 = Regs[src].Bit(5); + Flag3 = Regs[src].Bit(3); + } + + // When doing I* + n bit tests, flags 3 and 5 come from I* + n + // This cooresponds to the high byte of WZ + // This is the same for the (HL) bit tests, except that WZ were not assigned to before the test occurs + public void I_BIT_Func(ushort bit, ushort src) + { + FlagZ = !Regs[src].Bit(bit); + FlagP = FlagZ; // special case + FlagH = true; + FlagN = false; + FlagS = ((bit == 7) && Regs[src].Bit(bit)); + Flag5 = Regs[W].Bit(5); + Flag3 = Regs[W].Bit(3); + } + + public void SET_Func(ushort bit, ushort src) + { + Regs[src] |= (ushort)(1 << bit); + } + + public void RES_Func(ushort bit, ushort src) + { + Regs[src] &= (ushort)(0xFF - (1 << bit)); + } + + public void ASGN_Func(ushort src, ushort val) + { + Regs[src] = val; + } + + public void SLL_Func(ushort src) + { + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | 0x1); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void SLA_Func(ushort src) + { + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)((Regs[src] << 1) & 0xFF); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void SRA_Func(ushort src) + { + FlagC = Regs[src].Bit(0); + + ushort temp = (ushort)(Regs[src] & 0x80); // MSB doesn't change in this operation + + Regs[src] = (ushort)((Regs[src] >> 1) | temp); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void SRL_Func(ushort src) + { + FlagC = Regs[src].Bit(0) ? true : false; + + Regs[src] = (ushort)(Regs[src] >> 1); + + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void CPL_Func(ushort src) + { + Regs[src] = (ushort)((~Regs[src]) & 0xFF); + + FlagH = true; + FlagN = true; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void CCF_Func(ushort src) + { + FlagH = FlagC; + FlagC = !FlagC; + FlagN = false; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void SCF_Func(ushort src) + { + FlagC = true; + FlagH = false; + FlagN = false; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void AND8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] & Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagC = false; + FlagH = true; + FlagN = false; + Flag3 = (Regs[dest] & 0x08) != 0; + Flag5 = (Regs[dest] & 0x20) != 0; + FlagS = Regs[dest] > 127; + FlagP = TableParity[Regs[dest]]; + } + + public void OR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)(Regs[dest] | Regs[src]); + + FlagZ = Regs[dest] == 0; + FlagC = false; + FlagH = false; + FlagN = false; + Flag3 = (Regs[dest] & 0x08) != 0; + Flag5 = (Regs[dest] & 0x20) != 0; + FlagS = Regs[dest] > 127; + FlagP = TableParity[Regs[dest]]; + } + + public void XOR8_Func(ushort dest, ushort src) + { + Regs[dest] = (ushort)((Regs[dest] ^ Regs[src])); + + FlagZ = Regs[dest] == 0; + FlagC = false; + FlagH = false; + FlagN = false; + Flag3 = (Regs[dest] & 0x08) != 0; + Flag5 = (Regs[dest] & 0x20) != 0; + FlagS = Regs[dest] > 127; + FlagP = TableParity[Regs[dest]]; + } + + public void CP8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + Reg16_d -= Regs[src]; + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= (Regs[src] & 0xF); + + FlagH = Reg16_d.Bit(4); + FlagN = true; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + } + + public void RRC_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)((FlagC ? 0x80 : 0) | (Regs[src] >> 1)); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void RR_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + ushort c = (ushort)(FlagC ? 0x80 : 0); + + FlagC = Regs[src].Bit(0); + + Regs[src] = (ushort)(c | (Regs[src] >> 1)); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void RLC_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + ushort c = (ushort)(Regs[src].Bit(7) ? 1 : 0); + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void RL_Func(ushort src) + { + bool imm = src == Aim; + if (imm) { src = A; } + + ushort c = (ushort)(FlagC ? 1 : 0); + FlagC = Regs[src].Bit(7); + + Regs[src] = (ushort)(((Regs[src] << 1) & 0xFF) | c); + + if (!imm) + { + FlagS = Regs[src].Bit(7); + FlagZ = Regs[src] == 0; + FlagP = TableParity[Regs[src]]; + } + + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + FlagH = false; + FlagN = false; + } + + public void INC8_Func(ushort src) + { + int Reg16_d = Regs[src]; + Reg16_d += 1; + + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[src] & 0xF; + Reg16_d += 1; + + FlagH = Reg16_d.Bit(4); + FlagN = false; + + Regs[src] = ans; + + FlagS = Regs[src].Bit(7); + FlagP = Regs[src] == 0x80; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void DEC8_Func(ushort src) + { + int Reg16_d = Regs[src]; + Reg16_d -= 1; + + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[src] & 0xF; + Reg16_d -= 1; + + FlagH = Reg16_d.Bit(4); + FlagN = true; + + Regs[src] = ans; + + FlagS = Regs[src].Bit(7); + FlagP = Regs[src] == 0x7F; + Flag3 = (Regs[src] & 0x08) != 0; + Flag5 = (Regs[src] & 0x20) != 0; + } + + public void INC16_Func(ushort src_l, ushort src_h) + { + int Reg16_d = Regs[src_l] | (Regs[src_h] << 8); + + Reg16_d += 1; + + Regs[src_l] = (ushort)(Reg16_d & 0xFF); + Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8); + } + + public void DEC16_Func(ushort src_l, ushort src_h) + { + int Reg16_d = Regs[src_l] | (Regs[src_h] << 8); + + Reg16_d -= 1; + + Regs[src_l] = (ushort)(Reg16_d & 0xFF); + Regs[src_h] = (ushort)((Reg16_d & 0xFF00) >> 8); + } + + public void ADC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d += (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d += ((Regs[src] & 0xF) + c); + + FlagH = Reg16_d.Bit(4); + FlagN = false; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) == Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void SBC8_Func(ushort dest, ushort src) + { + int Reg16_d = Regs[dest]; + int c = FlagC ? 1 : 0; + + Reg16_d -= (Regs[src] + c); + + FlagC = Reg16_d.Bit(8); + FlagZ = (Reg16_d & 0xFF) == 0; + + ushort ans = (ushort)(Reg16_d & 0xFF); + + // redo for half carry flag + Reg16_d = Regs[dest] & 0xF; + Reg16_d -= ((Regs[src] & 0xF) + c); + + FlagH = Reg16_d.Bit(4); + FlagN = true; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + FlagP = (Regs[dest].Bit(7) != Regs[src].Bit(7)) && (Regs[dest].Bit(7) != ans.Bit(7)); + FlagS = ans > 127; + + Regs[dest] = ans; + } + + public void DA_Func(ushort src) + { + byte a = (byte)Regs[src]; + byte temp = a; + + if (FlagN) + { + if (FlagH || ((a & 0x0F) > 0x09)) { temp -= 0x06; } + if (FlagC || a > 0x99) { temp -= 0x60; } + } + else + { + if (FlagH || ((a & 0x0F) > 0x09)) { temp += 0x06; } + if (FlagC || a > 0x99) { temp += 0x60; } + } + + temp &= 0xFF; + + FlagC = FlagC || a > 0x99; + FlagZ = temp == 0; + FlagH = ((a ^ temp) & 0x10) != 0; + FlagP = TableParity[temp]; + FlagS = temp > 127; + Flag3 = (temp & 0x08) != 0; + Flag5 = (temp & 0x20) != 0; + + Regs[src] = temp; + } + + // used for signed operations + public void ADDS_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l]; + int Reg16_s = Regs[src_l]; + + Reg16_d += Reg16_s; + + ushort temp = 0; + + // since this is signed addition, calculate the high byte carry appropriately + // note that flags are unaffected by this operation + if (Reg16_s.Bit(7)) + { + if (((Reg16_d & 0xFF) >= Regs[dest_l])) + { + temp = 0xFF; + } + else + { + temp = 0; + } + } + else + { + temp = (ushort)(Reg16_d.Bit(8) ? 1 : 0); + } + + ushort ans_l = (ushort)(Reg16_d & 0xFF); + + Regs[dest_l] = ans_l; + Regs[dest_h] += temp; + Regs[dest_h] &= 0xFF; + + } + + public void EXCH_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + ushort temp = Regs[dest_l]; + Regs[dest_l] = Regs[src_l]; + Regs[src_l] = temp; + + temp = Regs[dest_h]; + Regs[dest_h] = Regs[src_h]; + Regs[src_h] = temp; + } + + public void SBC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + int c = FlagC ? 1 : 0; + + int ans = Reg16_d - Reg16_s - c; + + FlagN = true; + FlagC = ans.Bit(16); + FlagP = (Reg16_d.Bit(15) != Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15)); + FlagS = (ushort)(ans & 0xFFFF) > 32767; + FlagZ = (ans & 0xFFFF) == 0; + Flag3 = (ans & 0x0800) != 0; + Flag5 = (ans & 0x2000) != 0; + + // redo for half carry flag + Reg16_d &= 0xFFF; + Reg16_d -= ((Reg16_s & 0xFFF) + c); + + FlagH = Reg16_d.Bit(12); + + Regs[dest_l] = (ushort)(ans & 0xFF); + Regs[dest_h] = (ushort)((ans >> 8) & 0xFF); + } + + public void ADC_16_Func(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + int Reg16_d = Regs[dest_l] | (Regs[dest_h] << 8); + int Reg16_s = Regs[src_l] | (Regs[src_h] << 8); + + int ans = Reg16_d + Reg16_s + (FlagC ? 1 : 0); + + FlagH = ((Reg16_d & 0xFFF) + (Reg16_s & 0xFFF) + (FlagC ? 1 : 0)) > 0xFFF; + FlagN = false; + FlagC = ans.Bit(16); + FlagP = (Reg16_d.Bit(15) == Reg16_s.Bit(15)) && (Reg16_d.Bit(15) != ans.Bit(15)); + FlagS = (ans & 0xFFFF) > 32767; + FlagZ = (ans & 0xFFFF) == 0; + Flag3 = (ans & 0x0800) != 0; + Flag5 = (ans & 0x2000) != 0; + + Regs[dest_l] = (ushort)(ans & 0xFF); + Regs[dest_h] = (ushort)((ans >> 8) & 0xFF); + } + + public void NEG_8_Func(ushort src) + { + int Reg16_d = 0; + Reg16_d -= Regs[src]; + + FlagC = Regs[src] != 0x0; + FlagZ = (Reg16_d & 0xFF) == 0; + FlagP = Regs[src] == 0x80; + FlagS = (Reg16_d & 0xFF) > 127; + + ushort ans = (ushort)(Reg16_d & 0xFF); + // redo for half carry flag + Reg16_d = 0; + Reg16_d -= (Regs[src] & 0xF); + FlagH = Reg16_d.Bit(4); + Regs[src] = ans; + FlagN = true; + Flag3 = (ans & 0x08) != 0; + Flag5 = (ans & 0x20) != 0; + } + + public void RRD_Func(ushort dest, ushort src) + { + ushort temp1 = Regs[src]; + ushort temp2 = Regs[dest]; + Regs[dest] = (ushort)(((temp1 & 0x0F) << 4) + ((temp2 & 0xF0) >> 4)); + Regs[src] = (ushort)((temp1 & 0xF0) + (temp2 & 0x0F)); + + temp1 = Regs[src]; + FlagS = temp1 > 127; + FlagZ = temp1 == 0; + FlagH = false; + FlagP = TableParity[temp1]; + FlagN = false; + Flag3 = (temp1 & 0x08) != 0; + Flag5 = (temp1 & 0x20) != 0; + } + + public void RLD_Func(ushort dest, ushort src) + { + ushort temp1 = Regs[src]; + ushort temp2 = Regs[dest]; + Regs[dest] = (ushort)((temp1 & 0x0F) + ((temp2 & 0x0F) << 4)); + Regs[src] = (ushort)((temp1 & 0xF0) + ((temp2 & 0xF0) >> 4)); + + temp1 = Regs[src]; + FlagS = temp1 > 127; + FlagZ = temp1 == 0; + FlagH = false; + FlagP = TableParity[temp1]; + FlagN = false; + Flag3 = (temp1 & 0x08) != 0; + Flag5 = (temp1 & 0x20) != 0; + } + + // sets flags for LD/R + public void SET_FL_LD_Func() + { + FlagP = (Regs[C] | (Regs[B] << 8)) != 0; + FlagH = false; + FlagN = false; + Flag5 = ((Regs[ALU] + Regs[A]) & 0x02) != 0; + Flag3 = ((Regs[ALU] + Regs[A]) & 0x08) != 0; + } + + // set flags for CP/R + public void SET_FL_CP_Func() + { + int Reg8_d = Regs[A]; + int Reg8_s = Regs[ALU]; + + // get half carry flag + byte temp = (byte)((Reg8_d & 0xF) - (Reg8_s & 0xF)); + FlagH = temp.Bit(4); + + temp = (byte)(Reg8_d - Reg8_s); + FlagN = true; + FlagZ = temp == 0; + FlagS = temp > 127; + FlagP = (Regs[C] | (Regs[B] << 8)) != 0; + + temp = (byte)(Reg8_d - Reg8_s - (FlagH ? 1 : 0)); + Flag5 = (temp & 0x02) != 0; + Flag3 = (temp & 0x08) != 0; + } + + // set flags for LD A, I/R + public void SET_FL_IR_Func(ushort dest) + { + if (dest == A) + { + FlagN = false; + FlagH = false; + FlagZ = Regs[A] == 0; + FlagS = Regs[A] > 127; + FlagP = iff2; + Flag5 = (Regs[A] & 0x02) != 0; + Flag3 = (Regs[A] & 0x08) != 0; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/ReadMe.txt b/BizHawk.Emulation.Cores/CPUs/Z80A/ReadMe.txt new file mode 100644 index 0000000000..d11f79b637 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/ReadMe.txt @@ -0,0 +1,8 @@ +TODO: + +Mode 0 and 2 interrupts +Check T-cycle level memory access timing +Check R register +new tests for WZ Registers +Memory refresh - IR is pushed onto the address bus at instruction start, does anything need this? +Data Bus - For mode zero and 2 interrupts, need a system that uses it to test diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs new file mode 100644 index 0000000000..628243c19e --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Registers.cs @@ -0,0 +1,132 @@ +using System.Runtime.InteropServices; +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + // registers + // note these are not constants. When shadows are used, they will be changed accordingly + public ushort PCl = 0; + public ushort PCh = 1; + public ushort SPl = 2; + public ushort SPh = 3; + public ushort A = 4; + public ushort F = 5; + public ushort B = 6; + public ushort C = 7; + public ushort D = 8; + public ushort E = 9; + public ushort H = 10; + public ushort L = 11; + public ushort W = 12; + public ushort Z = 13; + public ushort Aim = 14; // use this indicator for RLCA etc., since the Z flag is reset on those + public ushort Ixl = 15; + public ushort Ixh = 16; + public ushort Iyl = 17; + public ushort Iyh = 18; + public ushort Int = 19; + public ushort R = 20; + public ushort I = 21; + public ushort ZERO = 22; // it is convenient to have a register that is always zero, to reuse instructions + public ushort ALU = 23; // This will be temporary arthimatic storage + // shadow registers + public ushort A_s = 24; + public ushort F_s = 25; + public ushort B_s = 26; + public ushort C_s = 27; + public ushort D_s = 28; + public ushort E_s = 29; + public ushort H_s = 30; + public ushort L_s = 31; + + public ushort[] Regs = new ushort[36]; + + public bool FlagI; + + public bool FlagC + { + get { return (Regs[5] & 0x01) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x01) | (value ? 0x01 : 0x00)); } + } + + public bool FlagN + { + get { return (Regs[5] & 0x02) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x02) | (value ? 0x02 : 0x00)); } + } + + public bool FlagP + { + get { return (Regs[5] & 0x04) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x04) | (value ? 0x04 : 0x00)); } + } + + public bool Flag3 + { + get { return (Regs[5] & 0x08) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x08) | (value ? 0x08 : 0x00)); } + } + + public bool FlagH + { + get { return (Regs[5] & 0x10) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x10) | (value ? 0x10 : 0x00)); } + } + + public bool Flag5 + { + get { return (Regs[5] & 0x20) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x20) | (value ? 0x20 : 0x00)); } + } + + public bool FlagZ + { + get { return (Regs[5] & 0x40) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x40) | (value ? 0x40 : 0x00)); } + } + + public bool FlagS + { + get { return (Regs[5] & 0x80) != 0; } + set { Regs[5] = (ushort)((Regs[5] & ~0x80) | (value ? 0x80 : 0x00)); } + } + + public ushort RegPC + { + get { return (ushort)(Regs[0] | (Regs[1] << 8)); } + set + { + Regs[0] = (ushort)(value & 0xFF); + Regs[1] = (ushort)((value >> 8) & 0xFF); + } + } + + private void ResetRegisters() + { + for (int i=0; i < 36; i++) + { + Regs[i] = 0; + } + } + + private bool[] TableParity; + private void InitTableParity() + { + TableParity = new bool[256]; + for (int i = 0; i < 256; ++i) + { + int Bits = 0; + for (int j = 0; j < 8; ++j) + { + Bits += (i >> j) & 1; + } + TableParity[i] = (Bits & 1) == 0; + } + } + + + + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs new file mode 100644 index 0000000000..71b39d6018 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Direct.cs @@ -0,0 +1,572 @@ +using System; + +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + // this contains the vectors of instrcution operations + // NOTE: This list is NOT confirmed accurate for each individual cycle + + private void NOP_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + OP }; + } + + // NOTE: In a real Z80, this operation just flips a switch to choose between 2 registers + // but it's simpler to emulate just by exchanging the register with it's shadow + private void EXCH_() + { + cur_instr = new ushort[] + {EXCH, + IDLE, + IDLE, + OP }; + } + + private void EXX_() + { + cur_instr = new ushort[] + {EXX, + IDLE, + IDLE, + OP }; + } + + // this exchanges 2 16 bit registers + private void EXCH_16_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {EXCH_16, dest_l, dest_h, src_l, src_h, + IDLE, + IDLE, + OP }; + } + + private void INC_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + INC16, src_l, src_h, + IDLE, + OP }; + } + + + private void DEC_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, src_l, src_h, + IDLE, + IDLE, + OP }; + } + + // this is done in two steps technically, but the flags don't work out using existing funcitons + // so let's use a different function since it's an internal operation anyway + private void ADD_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + TR16, Z, W, dest_l, dest_h, + INC16, Z, W, + IDLE, + IDLE, + ADD16, dest_l, dest_h, src_l, src_h, + IDLE, + IDLE, + OP }; + } + + private void REG_OP(ushort operation, ushort dest, ushort src) + { + cur_instr = new ushort[] + {operation, dest, src, + IDLE, + IDLE, + OP }; + } + + // Operations using the I and R registers take one T-cycle longer + private void REG_OP_IR(ushort operation, ushort dest, ushort src) + { + cur_instr = new ushort[] + {operation, dest, src, + IDLE, + IDLE, + SET_FL_IR, dest, + OP }; + } + + // note: do not use DEC here since no flags are affected by this operation + private void DJNZ_() + { + if ((Regs[B] - 1) != 0) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), + IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + ASGN, W, 0, + IDLE, + ADDS, PCl, PCh, Z, W, + TR16, Z, W, PCl, PCh, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + ASGN, B, (ushort)((Regs[B] - 1) & 0xFF), + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + OP }; + } + } + + private void HALT_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + HALT }; + } + + private void JR_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + IDLE, + ASGN, W, 0, + IDLE, + ADDS, PCl, PCh, Z, W, + TR16, Z, W, PCl, PCh, + IDLE, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + OP }; + } + } + + private void JP_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + TR16, PCl, PCh, Z, W, + IDLE, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + INC16, PCl, PCh, + IDLE, + IDLE, + OP }; + } + } + + private void RET_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + TR16, PCl, PCh, Z, W, + OP }; + } + + private void RETI_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + TR16, PCl, PCh, Z, W, + OP }; + } + + private void RETN_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + EI_RETN, + TR16, PCl, PCh, Z, W, + OP }; + } + + + private void RET_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, SPl, SPh, + INC16, SPl, SPh, + IDLE, + IDLE, + RD, W, SPl, SPh, + INC16, SPl, SPh, + IDLE, + TR16, PCl, PCh, Z, W, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + IDLE, + OP }; + } + } + + private void CALL_COND(bool cond) + { + if (cond) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + INC16, PCl, PCh, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, PCh, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + TR, PCl, Z, + TR, PCh, W, + OP }; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + OP }; + } + } + + private void INT_OP(ushort operation, ushort src) + { + cur_instr = new ushort[] + {operation, src, + IDLE, + IDLE, + OP }; + } + + private void BIT_OP(ushort operation, ushort bit, ushort src) + { + cur_instr = new ushort[] + {operation, bit, src, + IDLE, + IDLE, + OP }; + } + + private void PUSH_(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, src_h, + IDLE, + DEC16, SPl, SPh, + IDLE, + WR, SPl, SPh, src_l, + IDLE, + OP }; + } + + + private void POP_(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + RD, src_l, SPl, SPh, + IDLE, + INC16, SPl, SPh, + IDLE, + RD, src_h, SPl, SPh, + IDLE, + INC16, SPl, SPh, + IDLE, + OP }; + } + + private void RST_(ushort n) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + DEC16, SPl, SPh, + WR, SPl, SPh, PCh, + DEC16, SPl, SPh, + WR, SPl, SPh, PCl, + IDLE, + ASGN, Z, n, + ASGN, W, 0, + TR16, PCl, PCh, Z, W, + OP }; + } + + private void PREFIX_(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + PREFIX, src}; + } + + private void PREFETCH_(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {TR16, Z, W, src_l, src_h, + ADDS, Z, W, ALU, ZERO, + IDLE, + PREFIX, IXYprefetch }; + } + + private void DI_() + { + cur_instr = new ushort[] + {DI, + IDLE, + IDLE, + OP }; + } + + private void EI_() + { + cur_instr = new ushort[] + {EI, + IDLE, + IDLE, + OP }; + } + + private void JP_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {TR, PCl, src_l, + IDLE, + TR, PCh, src_h, + OP }; + } + + private void LD_SP_16(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR, SPl, src_l, + TR, SPh, src_h, + IDLE, + OP }; + } + + private void OUT_() + { + cur_instr = new ushort[] + {IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + TR, W, A, + OUT, ALU, A, + TR, Z, ALU, + INC16, Z, ALU, + IDLE, + IDLE, + OP}; + } + + private void OUT_REG_(ushort dest, ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + OUT, dest, src, + IDLE, + TR16, Z, W, C, B, + INC16, Z, W, + IDLE, + OP}; + } + + private void IN_() + { + cur_instr = new ushort[] + {IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + TR, W, A, + IN, A, ALU, + TR, Z, ALU, + INC16, Z, W, + IDLE, + IDLE, + OP}; + } + + private void IN_REG_(ushort dest, ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IN, dest, src, + IDLE, + TR16, Z, W, C, B, + INC16, Z, W, + IDLE, + OP}; + } + + private void REG_OP_16_(ushort op, ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + TR16, Z, W, dest_l, dest_h, + INC16, Z, W, + IDLE, + IDLE, + op, dest_l, dest_h, src_l, src_h, + IDLE, + IDLE, + OP}; + } + + private void INT_MODE_(ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + INT_MODE, src, + OP }; + } + + private void RRD_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, L, H, + IDLE, + RD, ALU, Z, W, + IDLE, + RRD, ALU, A, + IDLE, + WR, Z, W, ALU, + IDLE, + INC16, Z, W, + IDLE, + IDLE, + OP }; + } + + private void RLD_() + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, L, H, + IDLE, + RD, ALU, Z, W, + IDLE, + RLD, ALU, A, + IDLE, + WR, Z, W, ALU, + IDLE, + INC16, Z, W, + IDLE, + IDLE, + OP }; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs new file mode 100644 index 0000000000..4a1c46cc03 --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Tables_Indirect.cs @@ -0,0 +1,478 @@ +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public partial class Z80A + { + private void INT_OP_IND(ushort operation, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + operation, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + private void BIT_OP_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + operation, bit, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + // Note that this operation uses I_BIT, same as indexed BIT. + // This is where the strange behaviour in Flag bits 3 and 5 come from. + // normally WZ contain I* + n when doing I_BIT ops, but here we use that code path + // even though WZ is not assigned to, letting it's value from other operations show through + private void BIT_TE_IND(ushort operation, ushort bit, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + I_BIT, bit, ALU, + IDLE, + OP }; + } + + private void REG_OP_IND_INC(ushort operation, ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + operation, dest, ALU, + INC16, src_l, src_h, + OP }; + } + + private void REG_OP_IND(ushort operation, ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, src_l, src_h, + RD, ALU, Z, W, + INC16, Z, W, + operation, dest, ALU, + OP }; + } + + private void LD_16_IND_nn(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + WR, Z, W, src_l, + IDLE, + INC16, Z, W, + IDLE, + WR, Z, W, src_h, + IDLE, + OP }; + } + + private void LD_IND_16_nn(ushort dest_l, ushort dest_h) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, dest_l, Z, W, + IDLE, + INC16, Z, W, + IDLE, + RD, dest_h, Z, W, + IDLE, + OP }; + } + + private void LD_8_IND_nn(ushort src) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + WR, Z, W, src, + INC16, Z, W, + TR, W, A, + OP }; + } + + private void LD_IND_8_nn(ushort dest) + { + cur_instr = new ushort[] + {IDLE, + RD, Z, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, W, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + RD, dest, Z, W, + IDLE, + INC16, Z, W, + OP }; + } + + private void LD_8_IND(ushort dest_l, ushort dest_h, ushort src) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + TR16, Z, W, dest_l, dest_h, + WR, Z, W, src, + INC16, Z, W, + TR, W, A, + OP }; + } + + private void LD_8_IND_IND(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + INC16, src_l, src_h, + IDLE, + WR, dest_l, dest_h, ALU, + IDLE, + OP }; + } + + private void LD_IND_8_INC(ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, dest, src_l, src_h, + IDLE, + INC16, src_l, src_h, + OP }; + } + + private void LD_IND_8_DEC(ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, dest, src_l, src_h, + IDLE, + DEC16, src_l, src_h, + IDLE, + OP }; + } + + private void LD_IND_16(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, dest_l, src_l, src_h, + IDLE, + INC16, src_l, src_h, + RD, dest_h, src_l, src_h, + IDLE, + INC16, src_l, src_h, + OP }; + } + + private void INC_8_IND(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + INC8, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + private void DEC_8_IND(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, src_l, src_h, + IDLE, + DEC8, ALU, + IDLE, + WR, src_l, src_h, ALU, + IDLE, + IDLE, + OP }; + } + + // NOTE: WZ implied for the wollowing 3 functions + private void I_INT_OP(ushort operation, ushort dest) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, Z, W, + IDLE, + operation, ALU, + IDLE, + WR, Z, W, ALU, + IDLE, + TR, dest, ALU, + IDLE, + OP }; + } + + private void I_BIT_OP(ushort operation, ushort bit, ushort dest) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, Z, W, + IDLE, + operation, bit, ALU, + IDLE, + WR, Z, W, ALU, + IDLE, + TR, dest, ALU, + IDLE, + OP }; + } + + private void I_BIT_TE(ushort bit) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + RD, ALU, Z, W, + IDLE, + I_BIT, bit, ALU, + IDLE, + OP }; + } + + private void I_OP_n(ushort operation, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, src_l, src_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + RD, ALU, Z, W, + IDLE, + IDLE, + operation, ALU, + IDLE, + IDLE, + IDLE, + WR, Z, W, ALU, + IDLE, + OP }; + } + + private void I_OP_n_n(ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, src_l, src_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + RD, ALU, PCl, PCh, + INC16, PCl, PCh, + IDLE, + WR, Z, W, ALU, + IDLE, + OP }; + } + + private void I_REG_OP_IND_n(ushort operation, ushort dest, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, src_l, src_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + RD, ALU, Z, W, + IDLE, + operation, dest, ALU, + IDLE, + OP }; + } + + private void I_LD_8_IND_n(ushort dest_l, ushort dest_h, ushort src) + { + cur_instr = new ushort[] + {IDLE, + RD, ALU, PCl, PCh, + IDLE, + INC16, PCl, PCh, + IDLE, + TR16, Z, W, dest_l, dest_h, + IDLE, + ADDS, Z, W, ALU, ZERO, + IDLE, + WR, Z, W, src, + IDLE, + IDLE, + IDLE, + IDLE, + OP }; + } + + private void LD_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {RD, ALU, L, H, + IDLE, + WR, E, D, ALU, + IDLE, + operation, L, H, + IDLE, + operation, E, D, + IDLE, + DEC16, C, B, + SET_FL_LD, + IDLE, + OP_R, 0, operation, repeat_instr }; + } + + private void CP_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, ALU, L, H, + operation, L, H, + IDLE, + IDLE, + DEC16, C, B, + SET_FL_CP, + IDLE, + operation, Z, W, + IDLE, + OP_R, 1, operation, repeat_instr }; + } + + private void IN_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {IN, ALU, C, + IDLE, + WR, L, H, ALU, + IDLE, + operation, L, H, + IDLE, + TR16, Z, W, C, B, + operation, Z, W, + IDLE, + DEC8, B, + IDLE, + OP_R, 2, operation, repeat_instr }; + } + + private void OUT_OP_R(ushort operation, ushort repeat_instr) + { + cur_instr = new ushort[] + {RD, ALU, L, H, + IDLE, + OUT, C, ALU, + IDLE, + IDLE, + operation, L, H, + DEC8, B, + IDLE, + TR16, Z, W, C, B, + operation, Z, W, + IDLE, + OP_R, 3, operation, repeat_instr }; + } + + // this is an indirect change of a a 16 bit register with memory + private void EXCH_16_IND_(ushort dest_l, ushort dest_h, ushort src_l, ushort src_h) + { + cur_instr = new ushort[] + {IDLE, + IDLE, + RD, Z, dest_l, dest_h, + IDLE, + IDLE, + I_RD, W, dest_l, dest_h, 1, + IDLE, + IDLE, + WR, dest_l, dest_h, src_l, + IDLE, + IDLE, + I_WR, dest_l, dest_h, 1, src_h, + IDLE, + IDLE, + TR16, src_l, src_h, Z, W, + IDLE, + IDLE, + IDLE, + OP }; + } + } +} diff --git a/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs new file mode 100644 index 0000000000..d8743a7eab --- /dev/null +++ b/BizHawk.Emulation.Cores/CPUs/Z80A/Z80A.cs @@ -0,0 +1,687 @@ +using System; +using System.Globalization; +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; + +// Z80A CPU +namespace BizHawk.Emulation.Cores.Components.Z80A +{ + public sealed partial class Z80A + { + // operations that can take place in an instruction + public const ushort IDLE = 0; + public const ushort OP = 1; + public const ushort OP_R = 2; // used for repeating operations + public const ushort HALT = 3; + public const ushort RD = 4; + public const ushort WR = 5; + public const ushort I_RD = 6; + public const ushort I_WR = 7; + public const ushort TR = 8; + public const ushort TR16 = 9; + public const ushort ADD16 = 10; + public const ushort ADD8 = 11; + public const ushort SUB8 = 12; + public const ushort ADC8 = 13; + public const ushort SBC8 = 14; + public const ushort SBC16 = 15; + public const ushort ADC16 = 16; + public const ushort INC16 = 17; + public const ushort INC8 = 18; + public const ushort DEC16 = 19; + public const ushort DEC8 = 20; + public const ushort RLC = 21; + public const ushort RL = 22; + public const ushort RRC = 23; + public const ushort RR = 24; + public const ushort CPL = 25; + public const ushort DA = 26; + public const ushort SCF = 27; + public const ushort CCF = 28; + public const ushort AND8 = 29; + public const ushort XOR8 = 30; + public const ushort OR8 = 31; + public const ushort CP8 = 32; + public const ushort SLA = 33; + public const ushort SRA = 34; + public const ushort SRL = 35; + public const ushort SLL = 36; + public const ushort BIT = 37; + public const ushort RES = 38; + public const ushort SET = 39; + public const ushort EI = 40; + public const ushort DI = 41; + public const ushort EXCH = 42; + public const ushort EXX = 43; + public const ushort EXCH_16 = 44; + public const ushort PREFIX = 45; + public const ushort PREFETCH = 46; + public const ushort ASGN = 47; + public const ushort ADDS = 48; // signed 16 bit operation used in 2 instructions + public const ushort INT_MODE = 49; + public const ushort EI_RETN = 50; + public const ushort EI_RETI = 51; // reti has no delay in interrupt enable + public const ushort OUT = 52; + public const ushort IN = 53; + public const ushort NEG = 54; + public const ushort RRD = 55; + public const ushort RLD = 56; + public const ushort SET_FL_LD = 57; + public const ushort SET_FL_CP = 58; + public const ushort SET_FL_IR = 59; + public const ushort I_BIT = 60; + public const ushort HL_BIT = 61; + + public byte temp_R; + + public Z80A() + { + Reset(); + InitTableParity(); + } + + public void Reset() + { + ResetRegisters(); + ResetInterrupts(); + TotalExecutedCycles = 0; + cur_instr = new ushort[] { OP }; + NO_prefix = true; + } + + public IMemoryCallbackSystem MemoryCallbacks { get; set; } + + // Memory Access + public Func FetchMemory; + public Func ReadMemory; + public Action WriteMemory; + public Func PeekMemory; + public Func DummyReadMemory; + + // Hardware I/O Port Access + public Func ReadHardware; + public Action WriteHardware; + + //this only calls when the first byte of an instruction is fetched. + public Action OnExecFetch; + + public void UnregisterMemoryMapper() + { + ReadMemory = null; + WriteMemory = null; + PeekMemory = null; + DummyReadMemory = null; + ReadHardware = null; + WriteHardware = null; + } + + public void SetCallbacks + ( + Func ReadMemory, + Func DummyReadMemory, + Func PeekMemory, + Action WriteMemory, + Func ReadHardware, + Action WriteHardware + ) + { + this.ReadMemory = ReadMemory; + this.DummyReadMemory = DummyReadMemory; + this.PeekMemory = PeekMemory; + this.WriteMemory = WriteMemory; + this.ReadHardware = ReadHardware; + this.WriteHardware = WriteHardware; + } + + // Execute instructions + public void ExecuteOne() + { + if (Regs[A] > 255) { Console.WriteLine(RegPC); } + switch (cur_instr[instr_pntr++]) + { + case IDLE: + // do nothing + break; + case OP: + // Read the opcode of the next instruction + if (EI_pending > 0) + { + EI_pending--; + if (EI_pending == 0) { IFF1 = IFF2 = true; } + } + + // Process interrupt requests. + if (nonMaskableInterruptPending) + { + nonMaskableInterruptPending = false; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); + } + + iff2 = iff1; + iff1 = false; + NMI_(); + NMICallback(); + } + else if (iff1 && FlagI) + { + iff1 = iff2 = false; + EI_pending = 0; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); + } + + switch (interruptMode) + { + case 0: + // Requires something to be pushed onto the data bus + // we'll assume it's a zero for now + INTERRUPT_0(0); + break; + case 1: + INTERRUPT_1(); + break; + case 2: + // Low byte of interrupt vector comes from data bus + // We'll assume it's zero for now + INTERRUPT_2(0); + break; + } + IRQCallback(); + } + else + { + if (OnExecFetch != null) OnExecFetch(RegPC); + if (TraceCallback != null) TraceCallback(State()); + FetchInstruction(FetchMemory(RegPC++)); + } + instr_pntr = 0; + + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + break; + case OP_R: + // determine if we repeat based on what operation we are doing + // single execution versions also come here, but never repeat + ushort temp1 = cur_instr[instr_pntr++]; + ushort temp2 = cur_instr[instr_pntr++]; + ushort temp3 = cur_instr[instr_pntr++]; + + bool repeat = false; + int Reg16_d = Regs[C] | (Regs[B] << 8); + switch (temp1) + { + case 0: + repeat = Reg16_d != 0; + break; + case 1: + repeat = (Reg16_d != 0) && !FlagZ; + break; + case 2: + repeat = Regs[B] != 0; + break; + case 3: + repeat = Regs[B] != 0; + break; + } + + // if we repeat, we do a 5 cycle refresh which decrements PC by 2 + // if we don't repeat, continue on as a normal opcode fetch + if (repeat && temp3 > 0) + { + cur_instr = new ushort[] + {IDLE, + DEC16, PCl, PCh, + IDLE, + DEC16, PCl, PCh, + OP }; + + // adjust WZ register accordingly + switch (temp1) + { + case 0: + // TEST: PC before or after the instruction? + Regs[Z] = Regs[PCl]; + Regs[W] = Regs[PCh]; + INC16_Func(Z, W); + break; + case 1: + // TEST: PC before or after the instruction? + Regs[Z] = Regs[PCl]; + Regs[W] = Regs[PCh]; + INC16_Func(Z, W); + break; + case 2: + // Nothing + break; + case 3: + // Nothing + break; + } + } + else + { + // Interrupts can occur at this point, so process them accordingly + // Read the opcode of the next instruction + if (EI_pending > 0) + { + EI_pending--; + if (EI_pending == 0) { IFF1 = IFF2 = true; } + } + + // Process interrupt requests. + if (nonMaskableInterruptPending) + { + nonMaskableInterruptPending = false; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); + } + + iff2 = iff1; + iff1 = false; + NMI_(); + NMICallback(); + } + else if (iff1 && FlagI) + { + iff1 = iff2 = false; + EI_pending = 0; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); + } + + switch (interruptMode) + { + case 0: + // Requires something to be pushed onto the data bus + // we'll assume it's a zero for now + INTERRUPT_0(0); + break; + case 1: + INTERRUPT_1(); + break; + case 2: + // Low byte of interrupt vector comes from data bus + // We'll assume it's zero for now + INTERRUPT_2(0); + break; + } + IRQCallback(); + } + else + { + if (OnExecFetch != null) OnExecFetch(RegPC); + if (TraceCallback != null) TraceCallback(State()); + FetchInstruction(FetchMemory(RegPC++)); + } + + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + } + instr_pntr = 0; + break; + + case HALT: + halted = true; + if (EI_pending > 0) + { + EI_pending--; + if (EI_pending == 0) { IFF1 = IFF2 = true; } + } + + // Process interrupt requests. + if (nonMaskableInterruptPending) + { + nonMaskableInterruptPending = false; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====NMI====", RegisterInfo = ""}); + } + + iff2 = iff1; + iff1 = false; + NMI_(); + NMICallback(); + halted = false; + } + else if (iff1 && FlagI) + { + iff1 = iff2 = false; + EI_pending = 0; + + if (TraceCallback != null) + { + TraceCallback(new TraceInfo{Disassembly = "====IRQ====", RegisterInfo = ""}); + } + + switch (interruptMode) + { + case 0: + // Requires something to be pushed onto the data bus + // we'll assume it's a zero for now + INTERRUPT_0(0); + break; + case 1: + INTERRUPT_1(); + break; + case 2: + // Low byte of interrupt vector comes from data bus + // We'll assume it's zero for now + INTERRUPT_2(0); + break; + } + IRQCallback(); + halted = false; + } + else + { + cur_instr = new ushort[] + {IDLE, + IDLE, + IDLE, + HALT }; + } + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + + instr_pntr = 0; + break; + case RD: + Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case WR: + Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case I_RD: + I_Read_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case I_WR: + I_Write_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR: + TR_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case TR16: + TR16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD16: + ADD16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADD8: + ADD8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SUB8: + SUB8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC8: + ADC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADC16: + ADC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SBC8: + SBC8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SBC16: + SBC_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case INC16: + INC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case INC8: + INC8_Func(cur_instr[instr_pntr++]); + break; + case DEC16: + DEC16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case DEC8: + DEC8_Func(cur_instr[instr_pntr++]); + break; + case RLC: + RLC_Func(cur_instr[instr_pntr++]); + break; + case RL: + RL_Func(cur_instr[instr_pntr++]); + break; + case RRC: + RRC_Func(cur_instr[instr_pntr++]); + break; + case RR: + RR_Func(cur_instr[instr_pntr++]); + break; + case CPL: + CPL_Func(cur_instr[instr_pntr++]); + break; + case DA: + DA_Func(cur_instr[instr_pntr++]); + break; + case SCF: + SCF_Func(cur_instr[instr_pntr++]); + break; + case CCF: + CCF_Func(cur_instr[instr_pntr++]); + break; + case AND8: + AND8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case XOR8: + XOR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case OR8: + OR8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case CP8: + CP8_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SLA: + SLA_Func(cur_instr[instr_pntr++]); + break; + case SRA: + SRA_Func(cur_instr[instr_pntr++]); + break; + case SRL: + SRL_Func(cur_instr[instr_pntr++]); + break; + case SLL: + SLL_Func(cur_instr[instr_pntr++]); + break; + case BIT: + BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case I_BIT: + I_BIT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RES: + RES_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SET: + SET_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case EI: + EI_pending = 2; + break; + case DI: + IFF1 = IFF2 = false; + break; + case EXCH: + EXCH_16_Func(F_s, A_s, F, A); + break; + case EXX: + EXCH_16_Func(C_s, B_s, C, B); + EXCH_16_Func(E_s, D_s, E, D); + EXCH_16_Func(L_s, H_s, L, H); + break; + case EXCH_16: + EXCH_16_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case PREFIX: + ushort prefix_src = cur_instr[instr_pntr++]; + NO_prefix = false; + if (prefix_src == CBpre) { CB_prefix = true; } + if (prefix_src == EXTDpre) { EXTD_prefix = true; } + if (prefix_src == IXpre) { IX_prefix = true; } + if (prefix_src == IYpre) { IY_prefix = true; } + if (prefix_src == IXCBpre) { IXCB_prefix = true; IXCB_prefetch = true; } + if (prefix_src == IYCBpre) { IYCB_prefix = true; IYCB_prefetch = true; } + + FetchInstruction(FetchMemory(RegPC++)); + instr_pntr = 0; + // only the first prefix in a double prefix increases R, although I don't know how / why + if (prefix_src < 4) + { + temp_R = (byte)(Regs[R] & 0x7F); + temp_R++; + temp_R &= 0x7F; + Regs[R] = (byte)((Regs[R] & 0x80) | temp_R); + } + break; + case ASGN: + ASGN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case ADDS: + ADDS_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case EI_RETI: + // NOTE: This is needed for systems using multiple interrupt sources, it triggers the next interrupt + // Not currently implemented here + iff1 = iff2; + break; + case EI_RETN: + iff1 = iff2; + break; + case OUT: + OUT_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case IN: + IN_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case NEG: + NEG_8_Func(cur_instr[instr_pntr++]); + break; + case INT_MODE: + interruptMode = cur_instr[instr_pntr++]; + break; + case RRD: + RRD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case RLD: + RLD_Func(cur_instr[instr_pntr++], cur_instr[instr_pntr++]); + break; + case SET_FL_LD: + SET_FL_LD_Func(); + break; + case SET_FL_CP: + SET_FL_CP_Func(); + break; + case SET_FL_IR: + SET_FL_IR_Func(cur_instr[instr_pntr++]); + break; + } + totalExecutedCycles++; + } + + // tracer stuff + public Action TraceCallback; + + public string TraceHeader + { + get { return "Z80A: PC, machine code, mnemonic, operands, registers (AF, BC, DE, HL, IX, IY, SP, Cy), flags (CNP3H5ZS)"; } + } + + public TraceInfo State(bool disassemble = true) + { + ushort bytes_read = 0; + + string disasm = disassemble ? Disassemble(RegPC, ReadMemory, out bytes_read) : "---"; + string byte_code = null; + + for (ushort i = 0; i < bytes_read; i++) + { + byte_code += ReadMemory((ushort)(RegPC + i)).ToHexString(2); + if (i < (bytes_read - 1)) + { + byte_code += " "; + } + } + + return new TraceInfo + { + Disassembly = string.Format( + "{0:X4}: {1} {2}", + RegPC, + byte_code.PadRight(12), + disasm.PadRight(26)), + RegisterInfo = string.Format( + "AF:{0:X4} BC:{1:X4} DE:{2:X4} HL:{3:X4} IX:{4:X4} IY:{5:X4} SP:{6:X4} Cy:{7} {8}{9}{10}{11}{12}{13}{14}{15}{16}", + (Regs[A] << 8) + Regs[F], + (Regs[B] << 8) + Regs[C], + (Regs[D] << 8) + Regs[E], + (Regs[H] << 8) + Regs[L], + (Regs[Ixh] << 8) + Regs[Ixl], + (Regs[Iyh] << 8) + Regs[Iyl], + Regs[SPl] | (Regs[SPh] << 8), + TotalExecutedCycles, + FlagC ? "C" : "c", + FlagN ? "N" : "n", + FlagP ? "P" : "p", + Flag3 ? "3" : "-", + FlagH ? "H" : "h", + Flag5 ? "5" : "-", + FlagZ ? "Z" : "z", + FlagS ? "S" : "s", + FlagI ? "E" : "e") + }; + } + // State Save/Load + + public void SyncState(Serializer ser) + { + ser.BeginSection("Z80A"); + ser.Sync("Regs", ref Regs, false); + ser.Sync("NMI", ref nonMaskableInterrupt); + ser.Sync("NMIPending", ref nonMaskableInterruptPending); + ser.Sync("IM", ref interruptMode); + ser.Sync("IFF1", ref iff1); + ser.Sync("IFF2", ref iff2); + ser.Sync("Halted", ref halted); + ser.Sync("ExecutedCycles", ref totalExecutedCycles); + ser.Sync("EI_pending", ref EI_pending); + + ser.Sync("instruction_pointer", ref instr_pntr); + ser.Sync("current instruction", ref cur_instr, false); + ser.Sync("opcode", ref opcode); + ser.Sync("FlagI", ref FlagI); + + ser.Sync("NO Preifx", ref NO_prefix); + ser.Sync("CB Preifx", ref CB_prefix); + ser.Sync("IX_prefix", ref IX_prefix); + ser.Sync("IY_prefix", ref IY_prefix); + ser.Sync("IXCB_prefix", ref IXCB_prefix); + ser.Sync("IYCB_prefix", ref IYCB_prefix); + ser.Sync("EXTD_prefix", ref EXTD_prefix); + ser.Sync("IXCB_prefetch", ref IXCB_prefetch); + ser.Sync("IYCB_prefetch", ref IYCB_prefetch); + ser.Sync("PF", ref PF); + + ser.EndSection(); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs index 8f24144e73..c5d795fcd5 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IDebuggable.cs @@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Calculators { return new Dictionary { - ["A"] = _cpu.RegisterA, - ["AF"] = _cpu.RegisterAF, - ["B"] = _cpu.RegisterB, - ["BC"] = _cpu.RegisterBC, - ["C"] = _cpu.RegisterC, - ["D"] = _cpu.RegisterD, - ["DE"] = _cpu.RegisterDE, - ["E"] = _cpu.RegisterE, - ["F"] = _cpu.RegisterF, - ["H"] = _cpu.RegisterH, - ["HL"] = _cpu.RegisterHL, - ["I"] = _cpu.RegisterI, - ["IX"] = _cpu.RegisterIX, - ["IY"] = _cpu.RegisterIY, - ["L"] = _cpu.RegisterL, - ["PC"] = _cpu.RegisterPC, - ["R"] = _cpu.RegisterR, - ["Shadow AF"] = _cpu.RegisterShadowAF, - ["Shadow BC"] = _cpu.RegisterShadowBC, - ["Shadow DE"] = _cpu.RegisterShadowDE, - ["Shadow HL"] = _cpu.RegisterShadowHL, - ["SP"] = _cpu.RegisterSP, - ["Flag C"] = _cpu.RegisterF.Bit(0), - ["Flag N"] = _cpu.RegisterF.Bit(1), - ["Flag P/V"] = _cpu.RegisterF.Bit(2), - ["Flag 3rd"] = _cpu.RegisterF.Bit(3), - ["Flag H"] = _cpu.RegisterF.Bit(4), - ["Flag 5th"] = _cpu.RegisterF.Bit(5), - ["Flag Z"] = _cpu.RegisterF.Bit(6), - ["Flag S"] = _cpu.RegisterF.Bit(7) + ["A"] = _cpu.Regs[_cpu.A], + ["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8), + ["B"] = _cpu.Regs[_cpu.B], + ["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8), + ["C"] = _cpu.Regs[_cpu.C], + ["D"] = _cpu.Regs[_cpu.D], + ["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8), + ["E"] = _cpu.Regs[_cpu.E], + ["F"] = _cpu.Regs[_cpu.F], + ["H"] = _cpu.Regs[_cpu.H], + ["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8), + ["I"] = _cpu.Regs[_cpu.I], + ["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8), + ["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["L"] = _cpu.Regs[_cpu.L], + ["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8), + ["R"] = _cpu.Regs[_cpu.R], + ["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8), + ["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8), + ["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8), + ["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8), + ["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["Flag C"] = _cpu.FlagC, + ["Flag N"] = _cpu.FlagN, + ["Flag P/V"] = _cpu.FlagP, + ["Flag 3rd"] = _cpu.Flag3, + ["Flag H"] = _cpu.FlagH, + ["Flag 5th"] = _cpu.Flag5, + ["Flag Z"] = _cpu.FlagZ, + ["Flag S"] = _cpu.FlagS }; } @@ -49,73 +49,85 @@ namespace BizHawk.Emulation.Cores.Calculators { switch (register) { - default: - throw new InvalidOperationException(); - case "A": - _cpu.RegisterA = (byte)value; - break; - case "AF": - _cpu.RegisterAF = (byte)value; - break; - case "B": - _cpu.RegisterB = (byte)value; - break; - case "BC": - _cpu.RegisterBC = (byte)value; - break; - case "C": - _cpu.RegisterC = (byte)value; - break; - case "D": - _cpu.RegisterD = (byte)value; - break; - case "DE": - _cpu.RegisterDE = (byte)value; - break; - case "E": - _cpu.RegisterE = (byte)value; - break; - case "F": - _cpu.RegisterF = (byte)value; - break; - case "H": - _cpu.RegisterH = (byte)value; - break; - case "HL": - _cpu.RegisterHL = (byte)value; - break; - case "I": - _cpu.RegisterI = (byte)value; - break; - case "IX": - _cpu.RegisterIX = (byte)value; - break; - case "IY": - _cpu.RegisterIY = (byte)value; - break; - case "L": - _cpu.RegisterL = (byte)value; - break; - case "PC": - _cpu.RegisterPC = (ushort)value; - break; - case "R": - _cpu.RegisterR = (byte)value; - break; - case "Shadow AF": - _cpu.RegisterShadowAF = (byte)value; - break; - case "Shadow BC": - _cpu.RegisterShadowBC = (byte)value; - break; - case "Shadow DE": - _cpu.RegisterShadowDE = (byte)value; - break; - case "Shadow HL": - _cpu.RegisterShadowHL = (byte)value; - break; - case "SP": - _cpu.RegisterSP = (byte)value; + default: + throw new InvalidOperationException(); + case "A": + _cpu.Regs[_cpu.A] = (ushort)value; + break; + case "AF": + _cpu.Regs[_cpu.F] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00); + break; + case "B": + _cpu.Regs[_cpu.B] = (ushort)value; + break; + case "BC": + _cpu.Regs[_cpu.C] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00); + break; + case "C": + _cpu.Regs[_cpu.C] = (ushort)value; + break; + case "D": + _cpu.Regs[_cpu.D] = (ushort)value; + break; + case "DE": + _cpu.Regs[_cpu.E] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00); + break; + case "E": + _cpu.Regs[_cpu.E] = (ushort)value; + break; + case "F": + _cpu.Regs[_cpu.F] = (ushort)value; + break; + case "H": + _cpu.Regs[_cpu.H] = (ushort)value; + break; + case "HL": + _cpu.Regs[_cpu.L] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00); + break; + case "I": + _cpu.Regs[_cpu.I] = (ushort)value; + break; + case "IX": + _cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00); + break; + case "IY": + _cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00); + break; + case "L": + _cpu.Regs[_cpu.L] = (ushort)value; + break; + case "PC": + _cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00); + break; + case "R": + _cpu.Regs[_cpu.R] = (ushort)value; + break; + case "Shadow AF": + _cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00); + break; + case "Shadow BC": + _cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00); + break; + case "Shadow DE": + _cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00); + break; + case "Shadow HL": + _cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00); + break; + case "SP": + _cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00); break; } } diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs index f1de9171dd..622664bcc7 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IEmulator.cs @@ -13,21 +13,42 @@ namespace BizHawk.Emulation.Cores.Calculators _controller = controller; _lagged = true; - _cpu.Debug = _tracer.Enabled; - - if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first + if (_tracer.Enabled) { - _cpu.Logger = s => _tracer.Put(s); + _cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + _cpu.TraceCallback = null; } - // I eyeballed this speed - for (int i = 0; i < 5; i++) - { - _onPressed = controller.IsPressed("ON"); + _onPressed = controller.IsPressed("ON"); - // and this was derived from other emus - _cpu.ExecuteCycles(10000); - _cpu.Interrupt = true; + if (_onPressed && ON_key_int_EN && !ON_key_int) + { + ON_key_int = true; + _cpu.FlagI = true; + } + + // see: http://wikiti.brandonw.net/index.php?title=83:Ports:04 + // for timer interrupt frequency + + // CPU frequency is 6MHz + for (int i = 0; i < 100000; i++) + { + _cpu.ExecuteOne(); + + TIM_count++; + if (TIM_count >= TIM_hit) + { + TIM_count = 0; + + if (TIM_1_int_EN) + { + TIM_1_int = true; + _cpu.FlagI = true; + } + } } Frame++; diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs b/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs index e6927d9962..d2bd9192ca 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.IStatable.cs @@ -7,55 +7,52 @@ namespace BizHawk.Emulation.Cores.Calculators { public partial class TI83 : IStatable { - private byte[] _stateBuffer; + public bool BinarySaveStatesPreferred + { + get { return true; } + } - public bool BinarySaveStatesPreferred => false; + public void SaveStateText(TextWriter writer) + { + SyncState(new Serializer(writer)); + } + + public void LoadStateText(TextReader reader) + { + SyncState(new Serializer(reader)); + } public void SaveStateBinary(BinaryWriter bw) { - SyncState(Serializer.CreateBinaryWriter(bw)); + SyncState(new Serializer(bw)); } public void LoadStateBinary(BinaryReader br) { - SyncState(Serializer.CreateBinaryReader(br)); - } - - public void SaveStateText(TextWriter tw) - { - SyncState(Serializer.CreateTextWriter(tw)); - } - - public void LoadStateText(TextReader tr) - { - SyncState(Serializer.CreateTextReader(tr)); + SyncState(new Serializer(br)); } public byte[] SaveStateBinary() { - if (_stateBuffer == null) - { - var stream = new MemoryStream(); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - _stateBuffer = stream.ToArray(); - writer.Close(); - return _stateBuffer; - } - else - { - var stream = new MemoryStream(_stateBuffer); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - writer.Close(); - return _stateBuffer; - } + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); } private void SyncState(Serializer ser) { - ser.BeginSection("TI83"); + byte[] core = null; + if (ser.IsWriter) + { + var ms = new MemoryStream(); + ms.Close(); + core = ms.ToArray(); + } _cpu.SyncState(ser); + + ser.BeginSection("TI83"); ser.Sync("RAM", ref _ram, false); ser.Sync("romPageLow3Bits", ref _romPageLow3Bits); ser.Sync("romPageHighBit", ref _romPageHighBit); @@ -72,6 +69,15 @@ namespace BizHawk.Emulation.Cores.Calculators ser.Sync("Frame", ref _frame); ser.Sync("LagCount", ref _lagCount); ser.Sync("IsLag", ref _isLag); + ser.Sync("ON_key_int", ref ON_key_int); + ser.Sync("ON_key_int_EN", ref ON_key_int_EN); + ser.Sync("TIM_1_int", ref TIM_1_int); + ser.Sync("TIM_1_int_EN", ref TIM_1_int_EN); + ser.Sync("TIM_frq", ref TIM_frq); + ser.Sync("TIM_mult", ref TIM_mult); + ser.Sync("TIM_count", ref TIM_count); + ser.Sync("TIM_hit", ref TIM_hit); + ser.EndSection(); if (ser.IsReader) diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.cs b/BizHawk.Emulation.Cores/Calculator/TI83.cs index 53a69072b6..cfe82f74eb 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; // http://www.ticalc.org/pub/text/calcinfo/ namespace BizHawk.Emulation.Cores.Calculators @@ -23,6 +23,7 @@ namespace BizHawk.Emulation.Cores.Calculators PutSettings((TI83Settings)settings ?? new TI83Settings()); CoreComm = comm; + _cpu.FetchMemory = ReadMemory; _cpu.ReadMemory = ReadMemory; _cpu.WriteMemory = WriteMemory; _cpu.ReadHardware = ReadHardware; @@ -34,21 +35,13 @@ namespace BizHawk.Emulation.Cores.Calculators _rom = rom; LinkPort = new TI83LinkPort(this); - // different calculators (different revisions?) have different initPC. we track this in the game database by rom hash - // if( *(unsigned long *)(m_pRom + 0x6ce) == 0x04D3163E ) m_Regs.PC.W = 0x6ce; //KNOWN - // else if( *(unsigned long *)(m_pRom + 0x6f6) == 0x04D3163E ) m_Regs.PC.W = 0x6f6; //UNKNOWN - if (game["initPC"]) - { - _startPC = ushort.Parse(game.OptionValue("initPC"), NumberStyles.HexNumber); - } - HardReset(); SetupMemoryDomains(); _tracer = new TraceBuffer { Header = _cpu.TraceHeader }; ser.Register(_tracer); - ser.Register(new Disassembler()); + ser.Register(_cpu); } private readonly TraceBuffer _tracer; @@ -57,8 +50,6 @@ namespace BizHawk.Emulation.Cores.Calculators private readonly byte[] _rom; // configuration - private readonly ushort _startPC; - private IController _controller; private byte[] _ram; @@ -75,6 +66,10 @@ namespace BizHawk.Emulation.Cores.Calculators private bool _cursorMoved; private int _frame; + public bool ON_key_int, ON_key_int_EN; + public bool TIM_1_int, TIM_1_int_EN; + public int TIM_frq, TIM_mult, TIM_count, TIM_hit; + // Link Cable public TI83LinkPort LinkPort { get; } @@ -151,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Calculators if (LinkActive) { // Prevent rom calls from disturbing link port activity - if (LinkActive && _cpu.RegisterPC < 0x4000) + if (LinkActive && _cpu.RegPC < 0x4000) { return; } @@ -169,7 +164,60 @@ namespace BizHawk.Emulation.Cores.Calculators _romPageLow3Bits = value & 0x7; break; case 3: // PORT_STATUS - _maskOn = (byte)(value & 1); + // controls ON key interrupts + if ((value & 0x1) == 0) + { + ON_key_int = false; + ON_key_int_EN = false; + } + else + { + ON_key_int_EN = true; + } + + // controls first timer interrupts + if ((value & 0x2) == 0) + { + TIM_1_int = false; + TIM_1_int_EN = false; + } + else + { + TIM_1_int_EN = true; + } + + // controls second timer, not yet implemented and unclear how to differentiate + if ((value & 0x4) == 0) + { + } + else + { + } + + // controls low power mode, not yet implemeneted + if ((value & 0x8) == 0) + { + } + else + { + } + break; + case 4: // PORT_INTCTRL + // controls ON key interrupts + TIM_frq = value & 6; + + TIM_mult = ((value & 0x10) == 0x10) ? 1800 : 1620; + + TIM_hit = (int)Math.Floor((double)TIM_mult / (3 + TIM_frq * 2)); + + TIM_hit = (int)Math.Floor((double)6000000 / TIM_hit); + + // Bit 0 is some form of memory mapping + + // Bit 5 controls reset + + // Bit 6-7 controls battery power compare (not implemented, will always return full power) + break; case 16: // PORT_DISPCTRL ////Console.WriteLine("write PORT_DISPCTRL {0}",value); @@ -198,22 +246,23 @@ namespace BizHawk.Emulation.Cores.Calculators { // Console.WriteLine("read PORT_STATUS"); // Bits: - // 0 - Set if ON key is down and ON key is trapped + // 0 - Set if ON key Interrupt generated // 1 - Update things (keyboard etc) // 2 - Unknown, but used // 3 - Set if ON key is up // 4-7 - Unknown - ////if (onPressed && maskOn) ret |= 1; - ////if (!onPressed) ret |= 0x8; - return (byte)((_controller.IsPressed("ON") ? _maskOn : 8) | (LinkActive ? 0 : 2)); + + return (byte)((_controller.IsPressed("ON") ? 0 : 8) | + (TIM_1_int ? 2 : 0) | + (ON_key_int ? 1 : 0)); } case 4: // PORT_INTCTRL - ////Console.WriteLine("read PORT_INTCTRL"); - return 0xFF; + // returns mirror of link port + return (byte)((_romPageHighBit << 4) | (LinkState << 2) | LinkOutput); case 16: // PORT_DISPCTRL - ////Console.WriteLine("read DISPCTRL"); + // Console.WriteLine("read DISPCTRL"); break; case 17: // PORT_DISPDATA @@ -428,13 +477,13 @@ namespace BizHawk.Emulation.Cores.Calculators private void IRQCallback() { - // Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", cpu.RegisterI, cpu.InterruptMode); - _cpu.Interrupt = false; + //Console.WriteLine("IRQ with vec {0} and cpu.InterruptMode {1}", _cpu.Regs[_cpu.I], _cpu.InterruptMode); + _cpu.FlagI = false; } private void NMICallback() { - Console.WriteLine("NMI"); + //Console.WriteLine("NMI"); _cpu.NonMaskableInterrupt = false; } @@ -447,7 +496,7 @@ namespace BizHawk.Emulation.Cores.Calculators _ram[i] = 0xFF; } - _cpu.RegisterPC = _startPC; + _cpu.RegPC = 0; _cpu.IFF1 = false; _cpu.IFF2 = false; @@ -463,4 +512,4 @@ namespace BizHawk.Emulation.Cores.Calculators _displayX = _displayY = 0; } } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs index 65b06c3e1f..e6fa2f8307 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.Core.cs @@ -21,7 +21,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 private IController _controller; private int _frame; private int _lastAddress; - private bool _frameStartPending = true; private bool _leftDifficultySwitchPressed; private bool _rightDifficultySwitchPressed; @@ -34,6 +33,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 internal byte[] Rom { get; } internal int DistinctAccessCount { get; private set; } + // keeps track of tia cycles, 3 cycles per CPU cycle + private int cyc_counter; + private static MapperBase SetMultiCartMapper(int romLength, int gameTotal) { switch (romLength / gameTotal) @@ -319,17 +321,10 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _m6532 = new M6532(this); - // Set up the system state here. for instance.. - // Read from the reset vector for where to start - Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC + HardReset(); // Show mapper class on romstatusdetails CoreComm.RomStatusDetails = $"{this._game.Name}\r\nSHA1:{Rom.HashSHA1()}\r\nMD5:{Rom.HashMD5()}\r\nMapper Impl \"{_mapper.GetType()}\""; - - // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. - // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 - // executing a reset sequence at power on, but it's needed so let's hard code it for now - Cpu.S = 0xFD; } private bool _pal; @@ -349,96 +344,28 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 }; _tia.Reset(); - _m6532 = new M6532(this); - Cpu.PC = (ushort)(ReadMemory(0x1FFC) + (ReadMemory(0x1FFD) << 8)); // set the initial PC - - // as it turns out, the stack pointer cannot be set to 0 for some games as they do not initilize it themselves. - // some documentation seems to indicate it should beset to FD, but currently there is no documentation of the 6532 - // executing a reset sequence at power on, but it's needed so let's hard code it for now - Cpu.S = 0xFD; - SetupMemoryDomains(); - } - - private void VFrameAdvance() // advance up to 500 lines looking for end of video frame - // after vsync falling edge, continues to end of next line - { - bool frameend = false; - _tia.FrameEndCallBack = (n) => frameend = true; - for (int i = 0; i < 500 && !frameend; i++) - { - ScanlineAdvance(); - } - - _tia.FrameEndCallBack = null; - } - - private void StartFrameCond() - { - if (_frameStartPending) - { - _frame++; - _islag = true; - - if (_controller.IsPressed("Power")) - { - HardReset(); - } - - if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld) - { - _leftDifficultySwitchPressed ^= true; - _leftDifficultySwitchHeld = true; - } - else if (!_controller.IsPressed("Toggle Left Difficulty")) - { - _leftDifficultySwitchHeld = false; - } - - if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld) - { - _rightDifficultySwitchPressed ^= true; - _rightDifficultySwitchHeld = true; - } - else if (!_controller.IsPressed("Toggle Right Difficulty")) - { - _rightDifficultySwitchHeld = false; - } - - _tia.BeginAudioFrame(); - _frameStartPending = false; - } - } - - private void FinishFrameCond() - { - if (_tia.LineCount >= _tia.NominalNumScanlines) - { - _tia.CompleteAudioFrame(); - if (_islag) - { - _lagcount++; - } - - _tia.LineCount = 0; - _frameStartPending = true; - } + cyc_counter = 0; } private void Cycle() { - _tia.Execute(1); - _tia.Execute(1); - _tia.Execute(1); - _m6532.Timer.Tick(); - if (Tracer.Enabled) + _tia.Execute(); + cyc_counter++; + if (cyc_counter == 3) { - Tracer.Put(Cpu.TraceState()); - } + _m6532.Timer.Tick(); + if (Tracer.Enabled) + { + Tracer.Put(Cpu.TraceState()); + } - Cpu.ExecuteOne(); - _mapper.ClockCpu(); + Cpu.ExecuteOne(); + _mapper.ClockCpu(); + + cyc_counter = 0; + } } internal byte ReadControls1(bool peek) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs index 597b552f00..75c16f62ff 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IDebuggable.cs @@ -60,97 +60,18 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 public bool CanStep(StepType type) { - switch (type) - { - case StepType.Into: - case StepType.Out: - case StepType.Over: - return true; - default: - return false; - } + return false; } [FeatureNotImplemented] public void Step(StepType type) { - switch (type) - { - case StepType.Into: - StepInto(); - break; - case StepType.Out: - StepOut(); - break; - case StepType.Over: - StepOver(); - break; - } + throw new NotImplementedException(); } + public int TotalExecutedCycles => Cpu.TotalExecutedCycles; - private void StepInto() - { - do - { - CycleAdvance(); - } while (!Cpu.AtStart); - } - - private void StepOver() - { - var instruction = Cpu.PeekMemory(Cpu.PC); - - if (instruction == JSR) - { - var destination = Cpu.PC + opsize[JSR]; - while (Cpu.PC != destination) - { - StepInto(); - } - } - else - { - StepInto(); - } - } - - private void StepOut() - { - var instruction = Cpu.PeekMemory(Cpu.PC); - - JSRCount = instruction == JSR ? 1 : 0; - - var bailOutFrame = Frame + 1; - while (true) - { - StepInto(); - var instr = Cpu.PeekMemory(Cpu.PC); - if (instr == JSR) - { - JSRCount++; - } - else if (instr == RTS && JSRCount <= 0) - { - StepInto(); - JSRCount = 0; - break; - } - else if (instr == RTS) - { - JSRCount--; - } - else // Emergency bail out logic - { - if (Frame == bailOutFrame) - { - break; - } - } - } - } - private int JSRCount = 0; private const byte JSR = 0x20; @@ -212,22 +133,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 #region Currently Unused Debug hooks - private void ScanlineAdvance() - { - StartFrameCond(); - int currentLine = _tia.LineCount; - while (_tia.LineCount == currentLine) - Cycle(); - FinishFrameCond(); - } - - private void CycleAdvance() - { - StartFrameCond(); - Cycle(); - FinishFrameCond(); - } - private int CurrentScanLine { get { return _tia.LineCount; } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs index 65d910b1c1..cfcd8176bc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IEmulator.cs @@ -12,18 +12,53 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { _controller = controller; - StartFrameCond(); - while (_tia.LineCount < _tia.NominalNumScanlines) + _frame++; + _islag = true; + + // Handle all the console controls here + if (_controller.IsPressed("Power")) + { + HardReset(); + } + + if (_controller.IsPressed("Toggle Left Difficulty") && !_leftDifficultySwitchHeld) + { + _leftDifficultySwitchPressed ^= true; + _leftDifficultySwitchHeld = true; + } + else if (!_controller.IsPressed("Toggle Left Difficulty")) + { + _leftDifficultySwitchHeld = false; + } + + if (_controller.IsPressed("Toggle Right Difficulty") && !_rightDifficultySwitchHeld) + { + _rightDifficultySwitchPressed ^= true; + _rightDifficultySwitchHeld = true; + } + else if (!_controller.IsPressed("Toggle Right Difficulty")) + { + _rightDifficultySwitchHeld = false; + } + + while (!_tia.New_Frame) { Cycle(); } + _tia.New_Frame = false; + if (rendersound == false) { _tia.AudioClocks = 0; // we need this here since the async sound provider won't check in this case } - FinishFrameCond(); + if (_islag) + { + _lagcount++; + } + + _tia.LineCount = 0; } public int Frame => _frame; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs index aa6d4e78b4..dcff99f432 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.IStatable.cs @@ -46,7 +46,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("Lag", ref _lagcount); ser.Sync("Frame", ref _frame); ser.Sync("IsLag", ref _islag); - ser.Sync("frameStartPending", ref _frameStartPending); + ser.Sync("cyc_counter", ref cyc_counter); ser.Sync("leftDifficultySwitchPressed", ref _leftDifficultySwitchPressed); ser.Sync("rightDifficultySwitchPressed", ref _rightDifficultySwitchPressed); ser.Sync("leftDifficultySwitchHeld", ref _leftDifficultySwitchHeld); diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs index 5a7d466c6f..e44db03cf7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs @@ -102,18 +102,25 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // give the emu a minimal of input\output connections so it doesn't crash var comm = new CoreComm(null, null); + + // here we advance past start up irregularities to see how long a frame is based on calls to Vsync + // we run 72 frames, then run 270 scanlines worth of cycles. + // if we don't hit a new frame, we can be pretty confident we are in PAL using (Atari2600 emu = new Atari2600(new CoreComm(null, null), newgame, rom, null, null)) { - List framecounts = new List(); - emu._tia.FrameEndCallBack = (i) => framecounts.Add(i); - for (int i = 0; i < 71; i++) // run for 71 * 262 lines, since we're in NTSC mode + for (int i = 0; i < 72; i++) { emu.FrameAdvance(NullController.Instance, false, false); } - int numpal = framecounts.Count((i) => i > 287); - bool pal = numpal >= 25; - Console.WriteLine("PAL Detection: {0} lines, {1}", numpal, pal); + for (int i = 0; i < 61560; i++) + { + emu.Cycle(); + } + + bool pal = !emu._tia.New_Frame; + + Console.WriteLine("PAL Detection: {0}", pal); return pal; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs index 1fd27cd171..af5ea5f124 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/TIA.cs @@ -35,6 +35,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 _spf = _vsyncNum / (double)_vsyncDen > 55.0 ? 735 : 882; } + // indicates to the core where a new frame is starting + public bool New_Frame = false; + private const int BackColor = unchecked((int)0xff000000); private const int ScreenWidth = 160; private const int MaxScreenHeight = 312; @@ -161,11 +164,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 /// public int LineCount { get; set; } - /// - /// Gets or sets a callback that is called at the end of a video frame. used internally - /// - public Action FrameEndCallBack { private get; set; } - public void Reset() { _hsyncCnt = 0; @@ -229,11 +227,9 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } // Execute TIA cycles - public void Execute(int cycles) + public void Execute() { - // Still ignoring cycles... - - // delay vblank latch + // Handle all of the Latch delays that occur in the TIA if (_vblankDelay > 0) { _vblankDelay++; @@ -244,7 +240,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to new playfield register if (_pf0Updater) { _pf0DelayClock++; @@ -275,7 +270,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to missile enable if (_enam0Delay > 0) { _enam0Delay++; @@ -296,7 +290,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to ball enable if (_enambDelay > 0) { _enambDelay++; @@ -307,7 +300,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // delay latch to player graphics registers if (_prg0Delay > 0) { _prg0Delay++; @@ -333,7 +325,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 } } - // HMP write delay if (_hmp0Delay > 0) { _hmp0Delay++; @@ -773,9 +764,12 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // do the audio sampling if (_hsyncCnt == 36 || _hsyncCnt == 148) { - LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2); - LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2); - AudioClocks++; + if (AudioClocks < 2000) + { + LocalAudioCycles[AudioClocks] += (short)(AUD[0].Cycle() / 2); + LocalAudioCycles[AudioClocks] += (short)(AUD[1].Cycle() / 2); + AudioClocks++; + } } // Increment the hsync counter @@ -796,7 +790,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 int topLine = _pal ? _core.Settings.PALTopLine : _core.Settings.NTSCTopLine; int bottomLine = _pal ? _core.Settings.PALBottomLine : _core.Settings.NTSCBottomLine; - // if vsync occured unexpectedly early, black out the remainer + // if vsync occured unexpectedly early, black out the remainder for (; validlines < bottomLine; validlines++) { for (int i = 0; i < 160; i++) @@ -972,7 +966,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 // write to frame buffer OutputFrame(_currentScanLine); - FrameEndCallBack?.Invoke(_currentScanLine); + New_Frame = true; // Clear all from last frame _currentScanLine = 0; @@ -1337,17 +1331,5 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 { AUDC, AUDF, AUDV } - - private int _frameStartCycles, _frameEndCycles; - - public void BeginAudioFrame() - { - _frameStartCycles = _core.Cpu.TotalExecutedCycles; - } - - public void CompleteAudioFrame() - { - _frameEndCycles = _core.Cpu.TotalExecutedCycles; - } } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs index 00aa6e7669..1f3807247a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Tia/Tia.SyncState.cs @@ -62,10 +62,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 ser.Sync("vblankEnabled", ref _vblankEnabled); ser.Sync("vsyncEnabled", ref _vsyncEnabled); ser.Sync("CurrentScanLine", ref _currentScanLine); - ser.Sync("scanlinebuffer", ref _scanlinebuffer, false); ser.Sync("AudioClocks", ref AudioClocks); - ser.Sync("FrameStartCycles", ref _frameStartCycles); - ser.Sync("FrameEndCycles", ref _frameEndCycles); + ser.Sync("New_Frame", ref New_Frame); ser.BeginSection("Player0"); _player0.SyncState(ser); diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IDebuggable.cs deleted file mode 100644 index f590372d21..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IDebuggable.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System; -using System.Collections.Generic; - -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public partial class Atari7800 : IDebuggable - { - public IDictionary GetCpuFlagsAndRegisters() - { - return new Dictionary - { - ["A"] = _theMachine.CPU.A, - ["P"] = _theMachine.CPU.P, - ["PC"] = _theMachine.CPU.PC, - ["S"] = _theMachine.CPU.S, - ["X"] = _theMachine.CPU.X, - ["Y"] = _theMachine.CPU.Y, - ["Flag B"] = _theMachine.CPU.fB, - ["Flag C"] = _theMachine.CPU.fC, - ["Flag D"] = _theMachine.CPU.fD, - ["Flag I"] = _theMachine.CPU.fI, - ["Flag N"] = _theMachine.CPU.fN, - ["Flag V"] = _theMachine.CPU.fV, - ["Flag Z"] = _theMachine.CPU.fZ - }; - } - - public void SetCpuRegister(string register, int value) - { - switch (register) - { - default: - throw new InvalidOperationException(); - case "A": - _theMachine.CPU.A = (byte)value; - break; - case "P": - _theMachine.CPU.P = (byte)value; - break; - case "PC": - _theMachine.CPU.PC = (ushort)value; - break; - case "S": - _theMachine.CPU.S = (byte)value; - break; - case "X": - _theMachine.CPU.X = (byte)value; - break; - case "Y": - _theMachine.CPU.Y = (byte)value; - 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 => (int)_theMachine.CPU.Clock; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IEmulator.cs deleted file mode 100644 index dd2093830c..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IEmulator.cs +++ /dev/null @@ -1,59 +0,0 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public partial class Atari7800 : 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(); - } - - ControlAdapter.Convert(controller, _theMachine.InputState); - _theMachine.ComputeNextFrame(_avProvider.Framebuffer); - - _islag = _theMachine.InputState.Lagged; - - if (_islag) - { - _lagcount++; - } - - _avProvider.FillFrameBuffer(); - } - - public int Frame => _frame; - - public string SystemId => "A78"; // TODO 2600? - - public bool DeterministicEmulation { get; set; } - - public void ResetCounters() - { - _frame = 0; - _lagcount = 0; - _islag = false; - } - - public CoreComm CoreComm { get; } - - public void Dispose() - { - if (_avProvider != null) - { - _avProvider.Dispose(); - _avProvider = null; - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IInputPollable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IInputPollable.cs deleted file mode 100644 index ddd18290a0..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IInputPollable.cs +++ /dev/null @@ -1,24 +0,0 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public partial class Atari7800 : 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; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IMemoryDomains.cs deleted file mode 100644 index abc645e827..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IMemoryDomains.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; - -using BizHawk.Emulation.Common; -using EMU7800.Core; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public partial class Atari7800 - { - private List _MemoryDomains; - - private IMemoryDomains MemoryDomains; - - public void SetupMemoryDomains(HSC7800 hsc7800) - { - // reset memory domains - if (_MemoryDomains == null) - { - _MemoryDomains = new List(); - if (_theMachine is Machine7800) - { - _MemoryDomains.Add(new MemoryDomainDelegate( - "RAM", 0x1000, MemoryDomain.Endian.Unknown, - delegate(long addr) - { - if (addr < 0 || addr >= 0x1000) - { - throw new ArgumentOutOfRangeException(); - } - - if (addr < 0x800) - { - return ((Machine7800)_theMachine).RAM1[(ushort)addr]; - } - - return ((Machine7800)_theMachine).RAM2[(ushort)addr]; - }, - - delegate(long addr, byte val) - { - if (addr < 0 || addr >= 0x1000) - { - throw new ArgumentOutOfRangeException(); - } - else if (addr < 0x800) - { - ((Machine7800)_theMachine).RAM1[(ushort)(addr & 0x800)] = val; - } - else - { - ((Machine7800)_theMachine).RAM2[(ushort)addr] = val; - } - }, 1)); - - _MemoryDomains.Add(new MemoryDomainByteArray( - "BIOS ROM", MemoryDomain.Endian.Unknown, - _bios, false, 1)); - - if (hsc7800 != null) - { - _MemoryDomains.Add(new MemoryDomainByteArray( - "HSC ROM", MemoryDomain.Endian.Unknown, _hsbios, false, 1)); - - _MemoryDomains.Add(new MemoryDomainByteArray( - "HSC RAM", MemoryDomain.Endian.Unknown, _hsram, true, 1)); - } - - _MemoryDomains.Add(new MemoryDomainDelegate( - "System Bus", 65536, MemoryDomain.Endian.Unknown, - delegate(long addr) - { - if (addr < 0 || addr >= 0x10000) - throw new ArgumentOutOfRangeException(); - return _theMachine.Mem[(ushort)addr]; - }, - delegate(long addr, byte val) - { - if (addr < 0 || addr >= 0x10000) - throw new ArgumentOutOfRangeException(); - _theMachine.Mem[(ushort)addr] = val; - }, 1)); - } - else // todo 2600? - { - } - - MemoryDomains = new MemoryDomainList(_MemoryDomains); - (ServiceProvider as BasicServiceProvider).Register(MemoryDomains); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.ISaveRam.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.ISaveRam.cs deleted file mode 100644 index 64c572c4ba..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.ISaveRam.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using BizHawk.Emulation.Common; -using EMU7800.Core; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public partial class Atari7800 : ISaveRam - { - public byte[] CloneSaveRam() - { - return (byte[])_hsram.Clone(); - } - - public void StoreSaveRam(byte[] data) - { - Buffer.BlockCopy(data, 0, _hsram, 0, data.Length); - } - - public bool SaveRamModified => _gameInfo.MachineType == MachineType.A7800PAL - || _gameInfo.MachineType == MachineType.A7800NTSC; - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IStatable.cs deleted file mode 100644 index 428887c250..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.IStatable.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.IO; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using EMU7800.Core; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public partial class Atari7800 : 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(); - _theMachine.Serialize(new BinaryWriter(ms)); - 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(); - if (ser.IsReader) - { - _theMachine = MachineBase.Deserialize(new BinaryReader(new MemoryStream(core, false))); - _avProvider.ConnectToMachine(_theMachine, _gameInfo); - } - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs deleted file mode 100644 index 9db05ae935..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs +++ /dev/null @@ -1,301 +0,0 @@ -using System; -using System.IO; - -using BizHawk.Emulation.Common; -using EMU7800.Core; -using EMU7800.Win; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - [Core( - "EMU7800", - "", - isPorted: true, - isReleased: true, - portedVersion: "v1.5", - portedUrl: "http://emu7800.sourceforge.net/")] - [ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))] - public partial class Atari7800 : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable - { - // TODO: - // some things don't work when you try to plug in a 2600 game - static Atari7800() - { - // add alpha bits to palette tables - for (int i = 0; i < TIATables.NTSCPalette.Length; i++) - { - TIATables.NTSCPalette[i] |= unchecked((int)0xff000000); - } - - for (int i = 0; i < TIATables.PALPalette.Length; i++) - { - TIATables.PALPalette[i] |= unchecked((int)0xff000000); - } - - for (int i = 0; i < MariaTables.NTSCPalette.Length; i++) - { - MariaTables.NTSCPalette[i] |= unchecked((int)0xff000000); - } - - for (int i = 0; i < MariaTables.PALPalette.Length; i++) - { - MariaTables.PALPalette[i] |= unchecked((int)0xff000000); - } - } - - public Atari7800(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn) - { - var ser = new BasicServiceProvider(this); - ser.Register(_avProvider); - ser.Register(_avProvider); - 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 (GameProgramLibrary.EMU7800DB == null) - { - GameProgramLibrary.EMU7800DB = new GameProgramLibrary(new StreamReader(gameDbFn)); - } - - 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; - } - - _gameInfo = GameProgramLibrary.EMU7800DB.TryRecognizeRom(rom); - CoreComm.RomStatusDetails = _gameInfo.ToString(); - Console.WriteLine("Rom Determiniation from 7800DB:"); - Console.WriteLine(_gameInfo.ToString()); - - _rom = rom; - _hsbios = highscoreBios; - _bios = _gameInfo.MachineType == MachineType.A7800PAL ? palBios : ntscBios; - _pal = _gameInfo.MachineType == MachineType.A7800PAL || _gameInfo.MachineType == MachineType.A2600PAL; - - if (_bios == null) - { - throw new MissingFirmwareException("The BIOS corresponding to the region of the game you loaded is required to run Atari 7800 games."); - } - - HardReset(); - } - - public DisplayType Region => _pal ? DisplayType.PAL : DisplayType.NTSC; - - public Atari7800Control ControlAdapter { get; private set; } - - private readonly byte[] _rom; - private readonly byte[] _hsbios; - private readonly byte[] _bios; - private readonly GameProgram _gameInfo; - private readonly byte[] _hsram = new byte[2048]; - private readonly bool _pal; - - private Cart _cart; - private MachineBase _theMachine; - private int _frame = 0; - - private class ConsoleLogger : ILogger - { - public void WriteLine(string format, params object[] args) - { - Console.WriteLine(format, args); - } - - public void WriteLine(object value) - { - Console.WriteLine(value); - } - - public void Write(string format, params object[] args) - { - Console.Write(format, args); - } - - public void Write(object value) - { - Console.Write(value); - } - } - - private void HardReset() - { - _cart = Cart.Create(_rom, _gameInfo.CartType); - ILogger logger = new ConsoleLogger(); - - HSC7800 hsc7800 = null; - if (_hsbios != null) - { - hsc7800 = new HSC7800(_hsbios, _hsram); - } - - Bios7800 bios7800 = new Bios7800(_bios); - _theMachine = MachineBase.Create( - _gameInfo.MachineType, - _cart, - bios7800, - hsc7800, - _gameInfo.LController, - _gameInfo.RController, - logger); - - _theMachine.Reset(); - _theMachine.InputState.InputPollCallback = InputCallbacks.Call; - - ControlAdapter = new Atari7800Control(_theMachine); - ControllerDefinition = ControlAdapter.ControlType; - - _avProvider.ConnectToMachine(_theMachine, _gameInfo); - - SetupMemoryDomains(hsc7800); - } - - #region audio\video - - private MyAVProvider _avProvider = new MyAVProvider(); - - private class MyAVProvider : IVideoProvider, ISoundProvider, IDisposable - { - // to sync exactly with audio as this emulator creates and times it, the frame rate should be exactly 60:1 or 50:1 - private int _frameHz; - - public FrameBuffer Framebuffer { get; private set; } - public void ConnectToMachine(MachineBase m, GameProgram g) - { - _frameHz = m.FrameHZ; - Framebuffer = m.CreateFrameBuffer(); - BufferWidth = Framebuffer.VisiblePitch; - BufferHeight = Framebuffer.Scanlines; - _vidbuffer = new int[BufferWidth * BufferHeight]; - - uint newsamplerate = (uint)m.SoundSampleFrequency; - if (newsamplerate != _samplerate) - { - // really shouldn't happen (after init), but if it does, we're ready - _resampler?.Dispose(); - _resampler = new SpeexResampler((SpeexResampler.Quality)3, newsamplerate, 44100, newsamplerate, 44100, null, null); - _samplerate = newsamplerate; - _dcfilter = new DCFilter(256); - } - - if (g.MachineType == MachineType.A2600PAL) - { - _palette = TIATables.PALPalette; - } - else if (g.MachineType == MachineType.A7800PAL) - { - _palette = MariaTables.PALPalette; - } - else if (g.MachineType == MachineType.A2600NTSC) - { - _palette = TIATables.NTSCPalette; - } - else - { - _palette = MariaTables.NTSCPalette; - } - } - - private uint _samplerate; - private int[] _vidbuffer; - private SpeexResampler _resampler; - private DCFilter _dcfilter; - private int[] _palette; - - public void FillFrameBuffer() - { - unsafe - { - fixed (byte* src_ = Framebuffer.VideoBuffer) - fixed (int* dst_ = _vidbuffer) - fixed (int* pal = _palette) - { - byte* src = src_; - int* dst = dst_; - for (int i = 0; i < _vidbuffer.Length; i++) - { - *dst++ = pal[*src++]; - } - } - } - } - - 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; - - #region ISoundProvider - - public bool CanProvideAsync => false; - - public void GetSamplesSync(out short[] samples, out int nsamp) - { - int nsampin = Framebuffer.SoundBufferByteLength; - unsafe - { - fixed (byte* src = Framebuffer.SoundBuffer) - { - for (int i = 0; i < nsampin; i++) - { - // the buffer values don't really get very large at all, - // so this doesn't overflow - short s = (short)(src[i] * 200); - _resampler.EnqueueSample(s, s); - } - } - } - - _resampler.GetSamplesSync(out samples, out nsamp); - _dcfilter.PushThroughSamples(samples, nsamp * 2); - } - - public SyncSoundMode SyncMode => SyncSoundMode.Sync; - - public void SetSyncMode(SyncSoundMode mode) - { - if (mode == SyncSoundMode.Async) - { - throw new NotSupportedException("Async mode is not supported."); - } - } - - public void GetSamplesAsync(short[] samples) - { - throw new InvalidOperationException("Async mode is not supported."); - } - - public void DiscardSamples() - { - _resampler?.DiscardSamples(); - } - - #endregion - - public void Dispose() - { - if (_resampler != null) - { - _resampler.Dispose(); - _resampler = null; - } - } - } - - #endregion - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800Control.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800Control.cs deleted file mode 100644 index 28a86f8328..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800Control.cs +++ /dev/null @@ -1,411 +0,0 @@ -using System; - -using EMU7800.Core; -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Atari.Atari7800 -{ - public class Atari7800Control - { - 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", - "Pause", - - // 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", - "BW", // should be "Color"?? - "Toggle Left Difficulty", // better not put P# on these as they might not correspond to player numbers - "Toggle Right Difficulty", - "Pause", - - // 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 Convert; - - public ControlAdapter(ControllerDefinition type, Controller left, Controller right, Action 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 Convert { get; private set; } - - public ControllerDefinition ControlType { get; private set; } - - public Atari7800Control(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}\""); - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs index 82fc52e990..27f51380c7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IEmulator.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { - public partial class A7800Hawk : IEmulator, IVideoProvider + public partial class A7800Hawk : IEmulator, IVideoProvider, ISoundProvider { public IEmulatorServiceProvider ServiceProvider { get; } @@ -76,7 +76,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk GetControllerState(controller); GetConsoleState(controller); - + maria.RunFrame(); if (_islag) @@ -160,15 +160,25 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk if (tia._hsyncCnt == 113 || tia._hsyncCnt == 340) { tia.Execute(0); + + // even though its clocked seperately, we sample the Pokey here + if (is_pokey) { pokey.sample(); } } // tick the m6532 timer, which is still active although not recommended to use // also it runs off of the cpu cycle timer + // similarly tick the pokey if it is in use if (cpu_cycle== 4) { m6532.Timer.Tick(); } + // the pokey chip ticks at the nominal clock rate (same as maria) + if (is_pokey) + { + pokey.Tick(); + } + if (cpu_cycle <= (2 + (slow_access ? 1 : 0))) { cpu_is_haltable = true; @@ -284,7 +294,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public int Frame => _frame; - public string SystemId => "A7800"; + public string SystemId => "A78"; public bool DeterministicEmulation { get; set; } @@ -344,5 +354,53 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk }; #endregion + + #region Sound provider + + private int _spf; + + 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]; + + nsamp = _spf; + tia.GetSamples(ret); + if (is_pokey) + { + short[] ret2 = new short[_spf * 2]; + pokey.GetSamples(ret2); + for (int i = 0; i < _spf * 2; i ++) + { + ret[i] += ret2[i]; + } + } + + samples = ret; + } + + public void GetSamplesAsync(short[] samples) + { + throw new NotSupportedException("Async is not available"); + } + + public void DiscardSamples() + { + tia.AudioClocks = 0; + } + + #endregion + } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IStatable.cs index d438ce8a87..1a698d4b9d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.IStatable.cs @@ -62,6 +62,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk ser.Sync("A7800_control_register", ref A7800_control_register); ser.Sync("_isPAL", ref _isPAL); + ser.Sync("_spf", ref _spf); ser.Sync("Maria_regs", ref Maria_regs, false); ser.Sync("RAM", ref RAM, false); @@ -80,7 +81,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk 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("is_pokey", ref is_pokey); ser.Sync("left_toggle", ref left_toggle); ser.Sync("right_toggle", ref right_toggle); ser.Sync("left_was_pressed", ref left_was_pressed); diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs index 3221192b71..6f2ce9b238 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.cs @@ -13,8 +13,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk isPorted: false, isReleased: true)] [ServiceNotApplicable(typeof(ISettable<,>), typeof(IDriveLight))] - public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, - ISettable + public partial class A7800Hawk : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, + IRegionable, IBoardInfo, ISettable { // 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 @@ -40,7 +40,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public bool small_flag = false; public bool PAL_Kara = false; public int cart_RAM = 0; - public bool pokey = false; + public bool is_pokey = false; private readonly ITraceable _tracer; @@ -49,6 +49,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk public bool _isPAL; public M6532 m6532; public TIA tia; + public Pokey pokey; public A7800Hawk(CoreComm comm, GameInfo game, byte[] rom, string gameDbFn, object settings, object syncSettings) { @@ -57,6 +58,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk maria = new Maria(); tia = new TIA(); m6532 = new M6532(); + pokey = new Pokey(); cpu = new MOS6502X { @@ -131,7 +133,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk if (dict.ContainsKey("Pokey")) { - bool.TryParse(dict["Pokey"], out pokey); + bool.TryParse(dict["Pokey"], out is_pokey); } // some games will not function with the high score bios @@ -222,18 +224,22 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk maria.Core = this; m6532.Core = this; tia.Core = this; + pokey.Core = this; ser.Register(this); - ser.Register(tia); + ser.Register(this); ServiceProvider = ser; _tracer = new TraceBuffer { Header = cpu.TraceHeader }; ser.Register(_tracer); SetupMemoryDomains(); - HardReset(); + ser.Register(cpu); + HardReset(); } + public string BoardName => mapper.GetType().Name.Replace("Mapper", ""); + public DisplayType Region => _isPAL ? DisplayType.PAL : DisplayType.NTSC; private readonly A7800HawkControllerDeck _controllerDeck; @@ -248,6 +254,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk maria.Reset(); m6532.Reset(); + pokey.Reset(); Maria_regs = new byte[0x20]; RAM = new byte[0x1000]; @@ -255,6 +262,8 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk cpu_cycle = 0; _vidbuffer = new int[VirtualWidth * VirtualHeight]; + + _spf = (_frameHz > 55) ? 740 : 880; } private void ExecFetch(ushort addr) diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperDefault.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperDefault.cs index 509c6c2e00..6b1b627a33 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperDefault.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperDefault.cs @@ -31,6 +31,10 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk return Core.RAM[0x800 + addr & 0x7FF]; } } + else if (addr < 0x8000 && Core.is_pokey) + { + return Core.pokey.ReadReg(addr & 0xF); + } else { // cartridge and other OPSYS @@ -75,8 +79,12 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk Core.RAM[0x800 + addr & 0x7FF] = value; } } - else + else if (addr < 0x8000 && Core.is_pokey) { + Core.pokey.WriteReg(addr & 0xF, value); + } + else + { // cartridge and other OPSYS } } diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperSG.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperSG.cs index 7fe0fdb1e3..fc5525a6fc 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperSG.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Mappers/MapperSG.cs @@ -55,7 +55,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk } else { - if (Core.cart_RAM == 0 && !Core.pokey) + if (Core.cart_RAM == 0 && !Core.is_pokey) { // return bank 6 int temp_addr = addr - 0x4000; @@ -80,11 +80,11 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk else if (Core.cart_RAM > 0) { // return RAM - if (Core.cart_RAM==8 && addr >= 0x6000) + if (Core.cart_RAM == 8 && addr >= 0x6000) { return RAM[addr - 0x6000]; } - else if (Core.cart_RAM==16) + else if (Core.cart_RAM == 16) { return RAM[addr - 0x4000]; } @@ -92,12 +92,15 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { // this would coorespond to reading from 0x4000-0x5FFF with only 8k of RAM // Let's just return FF for now - return 0xFF; + return 0xFF; } } + else if (Core.is_pokey) + { + return Core.pokey.ReadReg(addr & 0xF); + } else { - // pokey return 0xFF; } } @@ -138,9 +141,9 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { bank = (byte)(value & (Core.small_flag ? 0x3 : 0x7)); } - else if (Core.pokey) + else if (Core.is_pokey) { - + Core.pokey.WriteReg(addr & 0xF, value); } else if (Core.cart_RAM > 0) { diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Pokey.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Pokey.cs new file mode 100644 index 0000000000..c9c9e22302 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/Pokey.cs @@ -0,0 +1,316 @@ +using System; +using BizHawk.Emulation.Common; +using BizHawk.Common.NumberExtensions; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Atari.A7800Hawk +{ + // emualtes pokey sound chip + // note: A7800 implementation is used only for sound + // potentiometers, keyboard, and IRQs are not used in this context + /* + * Regs 0,2,4,6: Frequency control (divider = value + 1) + * Regs 1,3,5,7: Channel control (Bits 0-3 = volume) (bits 4 - 7 control clocking) + * Reg 8: Control register + * + * Reg A: Random number generator + * + * The registers are write only, except for the RNG none of the things that would return reads are connected + * for now return FF + */ + public class Pokey + { + public A7800Hawk Core { get; set; } + + public readonly short[] LocalAudioCycles = new short[2000]; + public int AudioClocks; + + // state variables + public byte[] Regs = new byte[16]; + public int poly4, poly5, poly9, poly17; + public int[] ch_div = new int[4]; + public int[] inc_ch = new int[4]; + public bool[] ch_out = new bool[4]; + public bool[] ch_src = new bool[4]; + public int[] ch_vol = new int[4]; + public bool high_pass_1; + public bool high_pass_2; + + // these are derived values and do not need to be save-stated + public bool[] clock_ch = new bool[4]; + public int bit_xor; + + public Pokey() + { + + } + + public void sample() + { + LocalAudioCycles[AudioClocks] += (short)(ch_vol[0] + ch_vol[1] + ch_vol[2] + ch_vol[3]); + AudioClocks++; + } + + public 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; + } + + public byte ReadReg(int reg) + { + byte ret = 0xFF; + + if (reg==0xA) + { + ret = (byte)(poly17 >> 9); + } + + return ret; + } + + public void WriteReg(int reg, byte value) + { + Regs[reg] = value; + + // this condition resets poly counters and holds them in place + if ((Regs[0xF] & 3) == 0) + { + poly4 = 0xF; + poly5 = 0x1F; + poly17 = 0x1FFFF; + } + } + + public void Tick() + { + // clock the 4-5-(9 or 17) bit poly counters + // NOTE: These might not be the exact poly implementation, I just picked a maximal one from wikipedia + // poly 4 and 5 are known to result in: + // poly4 output: 000011101100101 + // poly5 output: 1101001100000111001000101011110 + if ((Regs[0xF] & 3) != 0) + { + bit_xor = ((poly4) ^ (poly4 >> 1)) & 1; + poly4 = (poly4 >> 1) | (bit_xor << 3); + + bit_xor = ((poly5 >> 2) ^ poly5) & 1; + poly5 = (poly5 >> 1) | (bit_xor << 4); + + if (Regs[8].Bit(7)) + { + // clock only 9 bits of the 17 bit poly + poly9 = poly17 >> 8; + bit_xor = ((poly9 >> 4) ^ poly9) & 1; + poly9 = (poly9 >> 1) | (bit_xor << 8); + poly17 = (poly17 & 0xFF) | (poly9 << 8); + } + else + { + // clock the whole 17 bit poly + bit_xor = ((poly17 >> 3) ^ poly17) & 1; + poly17 = (poly17 >> 1) | (bit_xor << 16); + } + } + + clock_ch[0] = clock_ch[1] = clock_ch[2] = clock_ch[3] = false; + + // now that we have the poly counters, check which channels to clock + if (Regs[8].Bit(6)) + { + clock_ch[0] = true; + clock_ch[2] = true; + } + else + { + inc_ch[0]++; + inc_ch[2]++; + if (Regs[8].Bit(0)) + { + if (inc_ch[0] >= 114) { inc_ch[0] = 0; clock_ch[0] = true; } + if (inc_ch[2] >= 114) { inc_ch[2] = 0; clock_ch[2] = true; } + } + else + { + if (inc_ch[0] >= 28) { inc_ch[0] = 0; clock_ch[0] = true; } + if (inc_ch[2] >= 28) { inc_ch[2] = 0; clock_ch[2] = true; } + } + } + + if (Regs[8].Bit(4)) + { + if (clock_ch[0]) { clock_ch[1] = true; } + } + else + { + inc_ch[1]++; + if (Regs[8].Bit(0)) + { + if (inc_ch[1] >= 114) { inc_ch[1] = 0; clock_ch[1] = true; } + } + else + { + if (inc_ch[1] >= 28) { inc_ch[1] = 0; clock_ch[1] = true; } + } + } + + if (Regs[8].Bit(3)) + { + if (clock_ch[2]) { clock_ch[3] = true; } + } + else + { + inc_ch[3]++; + if (Regs[8].Bit(0)) + { + if (inc_ch[3] >= 114) { inc_ch[3] = 0; clock_ch[3] = true; } + } + else + { + if (inc_ch[3] >= 28) { inc_ch[3] = 0; clock_ch[3] = true; } + } + } + + // first update the high pass filter latch + if (clock_ch[2] && Regs[8].Bit(2)) { high_pass_1 = ch_out[0]; } + if (clock_ch[3] && Regs[8].Bit(1)) { high_pass_2 = ch_out[1]; } + + // now we know what channels to clock, execute the cycles + for (int i = 0; i < 4; i++) { + if (clock_ch[i]) + { + ch_div[i]++; + + if (ch_div[i] >= (Regs[i * 2] + 1)) + { + ch_div[i] = 0; + + // select the next source based on the channel control register + if (Regs[i * 2 + 1].Bit(4)) + { + // forced output always on (used with volume modulation) + ch_out[i] = true; + } + else if ((Regs[i * 2 + 1] & 0xF0) == 0) + { + // 17 bit poly then 5 bit poly + if (ch_src[i]) + { + ch_out[i] = poly5.Bit(4); + } + else + { + ch_out[i] = poly5.Bit(16); + } + } + else if (((Regs[i * 2 + 1] & 0xF0) == 0x20) || ((Regs[i * 2 + 1] & 0xF0) == 0x60)) + { + // 5 bit poly + if (ch_src[i]) + { + ch_out[i] = poly5.Bit(4); + } + } + else if ((Regs[i * 2 + 1] & 0xF0) == 0x40) + { + // 4 bit poly then 5 bit poly + if (ch_src[i]) + { + ch_out[i] = poly5.Bit(4); + } + else + { + ch_out[i] = poly4.Bit(3); + } + } + else if ((Regs[i * 2 + 1] & 0xF0) == 0x80) + { + // 17 bit poly + if (ch_src[i]) + { + ch_out[i] = poly17.Bit(16); + } + } + else if ((Regs[i * 2 + 1] & 0xF0) == 0xA0) + { + // tone + if (ch_src[i]) + { + ch_out[i] = !ch_out[i]; + } + } + else if ((Regs[i * 2 + 1] & 0xF0) == 0xC0) + { + // 4 bit poly + if (ch_src[i]) + { + ch_out[i] = poly4.Bit(3); + } + } + ch_src[i] = !ch_src[i]; + + // for channels 1 and 2, an optional high pass filter exists + // the filter is just a flip flop and xor combo + if ((i == 0 && Regs[8].Bit(2)) || (i == 1 && Regs[8].Bit(1))) + { + if (i == 0) { ch_vol[0] = (ch_out[0] ^ high_pass_1) ? (Regs[1] & 0xF) : 0; } + if (i == 1) { ch_vol[1] = (ch_out[1] ^ high_pass_2) ? (Regs[3] & 0xF) : 0; } + + } + else + { + ch_vol[i] = (ch_out[i] ? (Regs[i * 2 + 1] & 0xF) : 0) * 70; + } + } + } + } + } + + public void Reset() + { + Regs = new byte[16]; + poly4 = 0xF; + poly5 = 0x1F; + poly17 = 0x1FFFF; + } + + public void SyncState(Serializer ser) + { + ser.BeginSection("Pokey"); + + ser.Sync("Regs", ref Regs, false); + + ser.Sync("poly4", ref poly4); + ser.Sync("poly5", ref poly5); + ser.Sync("poly9", ref poly9); + ser.Sync("poly17", ref poly17); + ser.Sync("ch_div", ref ch_div, false); + ser.Sync("inc_ch", ref inc_ch, false); + ser.Sync("ch_out", ref ch_out, false); + ser.Sync("ch_src", ref ch_src, false); + ser.Sync("ch_vol", ref ch_vol, false); + ser.Sync("high_pass_1", ref high_pass_1); + ser.Sync("high_pass_2", ref high_pass_2); + + ser.EndSection(); + } + + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/TIA.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/TIA.cs index ee7212933a..d0571d2f5b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/TIA.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/TIA.cs @@ -6,20 +6,17 @@ using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { // Emulates the TIA - public partial class TIA : ISoundProvider + public partial class TIA { public A7800Hawk Core { get; set; } public byte BusState; private bool _doTicks; - - private int _spf; - + public int AudioClocks; // not savestated public int _hsyncCnt; private int _capChargeStart; private bool _capCharging; - public int AudioClocks; // not savestated private readonly Audio[] AUD = { new Audio(), new Audio() }; @@ -33,7 +30,6 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk _capChargeStart = 0; _capCharging = false; AudioClocks = 0; - _spf = (Core._frameHz > 55) ? 740 : 880; _doTicks = false; } @@ -45,11 +41,32 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk AudioClocks++; } + public 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; + } + public byte ReadMemory(ushort addr, bool peek) { var maskedAddr = (ushort)(addr & 0x000F); - byte coll = 0; - int mask = 0; if (maskedAddr == 0x00) // CXM0P { diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.ISoundProvider.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.ISoundProvider.cs deleted file mode 100644 index 0cdba141aa..0000000000 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.ISoundProvider.cs +++ /dev/null @@ -1,63 +0,0 @@ -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]; - nsamp = _spf; - GetSamples(ret); - samples = ret; - } - - public void GetSamplesAsync(short[] samples) - { - throw new NotSupportedException("Async is not available"); - } - - public void DiscardSamples() - { - AudioClocks = 0; - } - - // 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; - } - } -} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.SyncState.cs b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.SyncState.cs index 58fa1b875a..89a2c50cfd 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.SyncState.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/TIA_Sound/Tia.SyncState.cs @@ -14,7 +14,6 @@ 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 diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.IStatable.cs index ac1c1a41d0..e2c600f015 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.IStatable.cs @@ -22,10 +22,6 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx _ser.Serialize(writer, s); - // write extra copy of stuff we don't use - writer.WriteLine(); - writer.WriteLine("Frame {0}", Frame); - ////Console.WriteLine(BizHawk.Common.BufferExtensions.BufferExtensions.HashSHA1(SaveStateBinary())); } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs index 2ad8b5cd5b..97a45d4e9b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllerDeck.cs @@ -30,6 +30,10 @@ namespace BizHawk.Emulation.Cores.ColecoVision Name = "ColecoVision Basic Controller", BoolButtons = Port1.Definition.BoolButtons .Concat(Port2.Definition.BoolButtons) + .Concat(new[] + { + "Power", "Reset" + }) .ToList() }; diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs index a44baeb679..bf018db6b5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoControllers.cs @@ -38,7 +38,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision public byte Read(IController c, bool left_mode, int wheel) { - return 0; // needs checking + return 0x7F; // needs checking } public ControllerDefinition Definition { get; } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs index 1c4e048e64..c48bbabf8f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IDebuggable.cs @@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.ColecoVision { return new Dictionary { - ["A"] = _cpu.RegisterA, - ["AF"] = _cpu.RegisterAF, - ["B"] = _cpu.RegisterB, - ["BC"] = _cpu.RegisterBC, - ["C"] = _cpu.RegisterC, - ["D"] = _cpu.RegisterD, - ["DE"] = _cpu.RegisterDE, - ["E"] = _cpu.RegisterE, - ["F"] = _cpu.RegisterF, - ["H"] = _cpu.RegisterH, - ["HL"] = _cpu.RegisterHL, - ["I"] = _cpu.RegisterI, - ["IX"] = _cpu.RegisterIX, - ["IY"] = _cpu.RegisterIY, - ["L"] = _cpu.RegisterL, - ["PC"] = _cpu.RegisterPC, - ["R"] = _cpu.RegisterR, - ["Shadow AF"] = _cpu.RegisterShadowAF, - ["Shadow BC"] = _cpu.RegisterShadowBC, - ["Shadow DE"] = _cpu.RegisterShadowDE, - ["Shadow HL"] = _cpu.RegisterShadowHL, - ["SP"] = _cpu.RegisterSP, - ["Flag C"] = _cpu.RegisterF.Bit(0), - ["Flag N"] = _cpu.RegisterF.Bit(1), - ["Flag P/V"] = _cpu.RegisterF.Bit(2), - ["Flag 3rd"] = _cpu.RegisterF.Bit(3), - ["Flag H"] = _cpu.RegisterF.Bit(4), - ["Flag 5th"] = _cpu.RegisterF.Bit(5), - ["Flag Z"] = _cpu.RegisterF.Bit(6), - ["Flag S"] = _cpu.RegisterF.Bit(7) + ["A"] = _cpu.Regs[_cpu.A], + ["AF"] = _cpu.Regs[_cpu.F] + (_cpu.Regs[_cpu.A] << 8), + ["B"] = _cpu.Regs[_cpu.B], + ["BC"] = _cpu.Regs[_cpu.C] + (_cpu.Regs[_cpu.B] << 8), + ["C"] = _cpu.Regs[_cpu.C], + ["D"] = _cpu.Regs[_cpu.D], + ["DE"] = _cpu.Regs[_cpu.E] + (_cpu.Regs[_cpu.D] << 8), + ["E"] = _cpu.Regs[_cpu.E], + ["F"] = _cpu.Regs[_cpu.F], + ["H"] = _cpu.Regs[_cpu.H], + ["HL"] = _cpu.Regs[_cpu.L] + (_cpu.Regs[_cpu.H] << 8), + ["I"] = _cpu.Regs[_cpu.I], + ["IX"] = _cpu.Regs[_cpu.Ixl] + (_cpu.Regs[_cpu.Ixh] << 8), + ["IY"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["L"] = _cpu.Regs[_cpu.L], + ["PC"] = _cpu.Regs[_cpu.PCl] + (_cpu.Regs[_cpu.PCh] << 8), + ["R"] = _cpu.Regs[_cpu.R], + ["Shadow AF"] = _cpu.Regs[_cpu.F_s] + (_cpu.Regs[_cpu.A_s] << 8), + ["Shadow BC"] = _cpu.Regs[_cpu.C_s] + (_cpu.Regs[_cpu.B_s] << 8), + ["Shadow DE"] = _cpu.Regs[_cpu.E_s] + (_cpu.Regs[_cpu.D_s] << 8), + ["Shadow HL"] = _cpu.Regs[_cpu.L_s] + (_cpu.Regs[_cpu.H_s] << 8), + ["SP"] = _cpu.Regs[_cpu.Iyl] + (_cpu.Regs[_cpu.Iyh] << 8), + ["Flag C"] = _cpu.FlagC, + ["Flag N"] = _cpu.FlagN, + ["Flag P/V"] = _cpu.FlagP, + ["Flag 3rd"] = _cpu.Flag3, + ["Flag H"] = _cpu.FlagH, + ["Flag 5th"] = _cpu.Flag5, + ["Flag Z"] = _cpu.FlagZ, + ["Flag S"] = _cpu.FlagS }; } @@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.ColecoVision default: throw new InvalidOperationException(); case "A": - _cpu.RegisterA = (byte)value; + _cpu.Regs[_cpu.A] = (ushort)value; break; case "AF": - _cpu.RegisterAF = (byte)value; + _cpu.Regs[_cpu.F] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A] = (ushort)(value & 0xFF00); break; case "B": - _cpu.RegisterB = (byte)value; + _cpu.Regs[_cpu.B] = (ushort)value; break; case "BC": - _cpu.RegisterBC = (byte)value; + _cpu.Regs[_cpu.C] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B] = (ushort)(value & 0xFF00); break; case "C": - _cpu.RegisterC = (byte)value; + _cpu.Regs[_cpu.C] = (ushort)value; break; case "D": - _cpu.RegisterD = (byte)value; + _cpu.Regs[_cpu.D] = (ushort)value; break; case "DE": - _cpu.RegisterDE = (byte)value; + _cpu.Regs[_cpu.E] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D] = (ushort)(value & 0xFF00); break; case "E": - _cpu.RegisterE = (byte)value; + _cpu.Regs[_cpu.E] = (ushort)value; break; case "F": - _cpu.RegisterF = (byte)value; + _cpu.Regs[_cpu.F] = (ushort)value; break; case "H": - _cpu.RegisterH = (byte)value; + _cpu.Regs[_cpu.H] = (ushort)value; break; case "HL": - _cpu.RegisterHL = (byte)value; + _cpu.Regs[_cpu.L] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H] = (ushort)(value & 0xFF00); break; case "I": - _cpu.RegisterI = (byte)value; + _cpu.Regs[_cpu.I] = (ushort)value; break; case "IX": - _cpu.RegisterIX = (byte)value; + _cpu.Regs[_cpu.Ixl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Ixh] = (ushort)(value & 0xFF00); break; case "IY": - _cpu.RegisterIY = (byte)value; + _cpu.Regs[_cpu.Iyl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.Iyh] = (ushort)(value & 0xFF00); break; case "L": - _cpu.RegisterL = (byte)value; + _cpu.Regs[_cpu.L] = (ushort)value; break; case "PC": - _cpu.RegisterPC = (ushort)value; + _cpu.Regs[_cpu.PCl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.PCh] = (ushort)(value & 0xFF00); break; case "R": - _cpu.RegisterR = (byte)value; + _cpu.Regs[_cpu.R] = (ushort)value; break; case "Shadow AF": - _cpu.RegisterShadowAF = (byte)value; + _cpu.Regs[_cpu.F_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.A_s] = (ushort)(value & 0xFF00); break; case "Shadow BC": - _cpu.RegisterShadowBC = (byte)value; + _cpu.Regs[_cpu.C_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.B_s] = (ushort)(value & 0xFF00); break; case "Shadow DE": - _cpu.RegisterShadowDE = (byte)value; + _cpu.Regs[_cpu.E_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.D_s] = (ushort)(value & 0xFF00); break; case "Shadow HL": - _cpu.RegisterShadowHL = (byte)value; + _cpu.Regs[_cpu.L_s] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.H_s] = (ushort)(value & 0xFF00); break; case "SP": - _cpu.RegisterSP = (byte)value; + _cpu.Regs[_cpu.SPl] = (ushort)(value & 0xFF); + _cpu.Regs[_cpu.SPh] = (ushort)(value & 0xFF00); break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs index 68d8493693..22e67db446 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IEmulator.cs @@ -12,16 +12,30 @@ namespace BizHawk.Emulation.Cores.ColecoVision public void FrameAdvance(IController controller, bool render, bool renderSound) { _controller = controller; - _cpu.Debug = _tracer.Enabled; + + // NOTE: Need to research differences between reset and power cycle + if (_controller.IsPressed("Power")) + { + HardReset(); + } + + if (_controller.IsPressed("Reset")) + { + SoftReset(); + } + _frame++; _isLag = true; PSG.BeginFrame(_cpu.TotalExecutedCycles); - if (_cpu.Debug && _cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first + if (_tracer.Enabled) { - _cpu.Logger = (s) => _tracer.Put(s); + _cpu.TraceCallback = s => _tracer.Put(s); + } + else + { + _cpu.TraceCallback = null; } - byte tempRet1 = ControllerDeck.ReadPort1(controller, true, true); byte tempRet2 = ControllerDeck.ReadPort2(controller, true, true); diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs index 62b5297675..d079fa50f4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.IStatable.cs @@ -7,53 +7,52 @@ namespace BizHawk.Emulation.Cores.ColecoVision { public partial class ColecoVision : IStatable { - public bool BinarySaveStatesPreferred => false; + public bool BinarySaveStatesPreferred + { + get { return 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(Serializer.CreateBinaryWriter(bw)); + SyncState(new Serializer(bw)); } public void LoadStateBinary(BinaryReader br) { - SyncState(Serializer.CreateBinaryReader(br)); - } - - public void SaveStateText(TextWriter tw) - { - SyncState(Serializer.CreateTextWriter(tw)); - } - - public void LoadStateText(TextReader tr) - { - SyncState(Serializer.CreateTextReader(tr)); + SyncState(new Serializer(br)); } public byte[] SaveStateBinary() { - if (_stateBuffer == null) - { - var stream = new MemoryStream(); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - _stateBuffer = stream.ToArray(); - writer.Close(); - return _stateBuffer; - } - else - { - var stream = new MemoryStream(_stateBuffer); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - writer.Close(); - return _stateBuffer; - } + MemoryStream ms = new MemoryStream(); + BinaryWriter bw = new BinaryWriter(ms); + SaveStateBinary(bw); + bw.Flush(); + return ms.ToArray(); } private void SyncState(Serializer ser) { - ser.BeginSection("Coleco"); + byte[] core = null; + if (ser.IsWriter) + { + var ms = new MemoryStream(); + ms.Close(); + core = ms.ToArray(); + } _cpu.SyncState(ser); + + ser.BeginSection("Coleco"); _vdp.SyncState(ser); PSG.SyncState(ser); ser.Sync("RAM", ref _ram, false); diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs index 0d487433fd..070c8a2655 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/ColecoVision.cs @@ -1,6 +1,6 @@ using BizHawk.Emulation.Common; using BizHawk.Emulation.Cores.Components; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; namespace BizHawk.Emulation.Cores.ColecoVision { @@ -24,6 +24,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision _cpu = new Z80A { + FetchMemory = ReadMemory, ReadMemory = ReadMemory, WriteMemory = WriteMemory, ReadHardware = ReadPort, @@ -53,7 +54,7 @@ namespace BizHawk.Emulation.Cores.ColecoVision SetupMemoryDomains(); _tracer.Header = _cpu.TraceHeader; - ser.Register(new Disassembler()); + ser.Register(_cpu); ser.Register(_tracer); } @@ -223,5 +224,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision ////Console.WriteLine("Unhandled write at {0:X4}:{1:X2}", addr, value); } + + private void HardReset() + { + PSG.Reset(); + _cpu.Reset(); + } + + private void SoftReset() + { + PSG.Reset(); + _cpu.Reset(); + } } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs b/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs index 1e5abd1445..c86bd515c1 100644 --- a/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs +++ b/BizHawk.Emulation.Cores/Consoles/Coleco/TMS9918A.cs @@ -2,7 +2,7 @@ using BizHawk.Common; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; namespace BizHawk.Emulation.Cores.ColecoVision { @@ -54,14 +54,17 @@ namespace BizHawk.Emulation.Cores.ColecoVision Cpu.NonMaskableInterrupt = true; } - Cpu.ExecuteCycles(228); - - Cpu.Interrupt = false; + for (int i = 0; i < 228; i++) + { + Cpu.ExecuteOne(); + } + + Cpu.FlagI = false; if (Int_pending && scanLine==50) { if (EnableInterrupts) { - Cpu.Interrupt = true; + Cpu.FlagI = true; Int_pending = false; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs index ed28391129..514b3850c8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.IStatable.cs @@ -22,10 +22,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA ser.Serialize(writer, s); - // write extra copy of stuff we don't use - writer.WriteLine(); - writer.WriteLine("Frame {0}", Frame); - //Console.WriteLine(BizHawk.Common.BufferExtensions.BufferExtensions.HashSHA1(SaveStateBinary())); } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs new file mode 100644 index 0000000000..05066dfed8 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ILinkable.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.Gameboy +{ + public partial class Gameboy : ILinkable + { + public bool LinkConnected { get; private set; } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs index f3d31aee93..5818d6634b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.IStatable.cs @@ -14,10 +14,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy { var s = SaveState(); ser.Serialize(writer, s); - - // write extra copy of stuff we don't use - writer.WriteLine(); - writer.WriteLine("Frame {0}", Frame); } public void LoadStateText(TextReader reader) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index 864cdd856d..fcfa9a0486 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy [ServiceNotApplicable(typeof(IDriveLight), typeof(IDriveLight))] public partial class Gameboy : IEmulator, IVideoProvider, ISoundProvider, ISaveRam, IStatable, IInputPollable, ICodeDataLogger, IBoardInfo, IDebuggable, ISettable, - IGameboyCommon + IGameboyCommon, ICycleTiming, ILinkable { [CoreConstructor("GB", "GBC")] public Gameboy(CoreComm comm, GameInfo game, byte[] file, object settings, object syncSettings, bool deterministic) @@ -253,7 +253,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy /// number of extra cycles we overran in the last frame /// private uint frameOverflow = 0; - public ulong CycleCount => _cycleCount; + public long CycleCount => (long)_cycleCount; + public double ClockRate => TICKSPERSECOND; #endregion @@ -496,6 +497,32 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy } } + GambattePrinter printer; + + /// + /// set up Printer callback + /// + public void SetPrinterCallback(PrinterCallback callback) + { + // Copying SetScanlineCallback for this check, I assume this is still a bug somewhere + if (GambatteState == IntPtr.Zero) + { + return; // not sure how this is being reached. tried the debugger... + } + + if (callback != null) + { + printer = new GambattePrinter(this, callback); + LinkConnected = true; + } + else + { + LinkConnected = false; + printer.Disconnect(); + printer = null; + } + } + LibGambatte.ScanlineCallback scanlinecb; ScanlineCallback endofframecallback; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs index 44d477940f..ea6e8bf0ed 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambatteLink.IStatable.cs @@ -27,10 +27,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy cablediscosignal = _cablediscosignal }; ser.Serialize(writer, s); - // write extra copy of stuff we don't use - // is this needed anymore?? - writer.WriteLine(); - writer.WriteLine("Frame {0}", Frame); } public void LoadStateText(TextReader reader) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs new file mode 100644 index 0000000000..2cc834e5ff --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/GambattePrinter.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.Gameboy +{ + /// + /// Emulate the gameboy printer in managed code + /// + public class GambattePrinter + { + // A loose c->c# port of SameBoy's printer code + + enum CommandState : byte + { + GB_PRINTER_COMMAND_MAGIC1, + GB_PRINTER_COMMAND_MAGIC2, + GB_PRINTER_COMMAND_ID, + GB_PRINTER_COMMAND_COMPRESSION, + GB_PRINTER_COMMAND_LENGTH_LOW, + GB_PRINTER_COMMAND_LENGTH_HIGH, + GB_PRINTER_COMMAND_DATA, + GB_PRINTER_COMMAND_CHECKSUM_LOW, + GB_PRINTER_COMMAND_CHECKSUM_HIGH, + GB_PRINTER_COMMAND_ACTIVE, + GB_PRINTER_COMMAND_STATUS, + } + enum CommandID : byte + { + GB_PRINTER_INIT_COMMAND = 1, + GB_PRINTER_START_COMMAND = 2, + GB_PRINTER_DATA_COMMAND = 4, + GB_PRINTER_NOP_COMMAND = 0xF, + } + + const int GB_PRINTER_MAX_COMMAND_LENGTH = 0x280; + const int GB_PRINTER_DATA_SIZE = 0x280; + + const ushort SerialIRQAddress = 0x58; + + Gameboy gb; + PrinterCallback callback; + LibGambatte.LinkCallback linkCallback; + + CommandState command_state; + CommandID command_id; + + bool compression; + ushort length_left; + byte[] command_data = new byte[GB_PRINTER_MAX_COMMAND_LENGTH]; + ushort command_length; + ushort checksum; + byte status; + + byte[] image = new byte[160 * 200]; + ushort image_offset; + + byte compression_run_lenth; + bool compression_run_is_compressed; + + public GambattePrinter(Gameboy gb, PrinterCallback callback) + { + this.gb = gb; + this.callback = callback; + + linkCallback = OnSerial; + LibGambatte.gambatte_setlinkcallback(gb.GambatteState, linkCallback); + + // connect the cable + LibGambatte.gambatte_linkstatus(gb.GambatteState, 259); + } + + public void Disconnect() + { + if (gb.GambatteState != IntPtr.Zero) + LibGambatte.gambatte_setlinkcallback(gb.GambatteState, null); + } + + void OnSerial() + { + if (LibGambatte.gambatte_linkstatus(gb.GambatteState, 256) != 0) // ClockTrigger + { + LibGambatte.gambatte_linkstatus(gb.GambatteState, 257); // ack + + byte output = HandleSerial((byte)LibGambatte.gambatte_linkstatus(gb.GambatteState, 258)); // GetOut + LibGambatte.gambatte_linkstatus(gb.GambatteState, output); // ShiftIn + } + } + + byte HandleSerial(byte byte_received) + { + byte byte_to_send = 0; + + switch (command_state) + { + case CommandState.GB_PRINTER_COMMAND_MAGIC1: + if (byte_received != 0x88) + { + return byte_to_send; + } + status &= 254; + command_length = 0; + checksum = 0; + break; + + case CommandState.GB_PRINTER_COMMAND_MAGIC2: + if (byte_received != 0x33) + { + if (byte_received != 0x88) + { + command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1; + } + return byte_to_send; + } + break; + + case CommandState.GB_PRINTER_COMMAND_ID: + command_id = (CommandID)(byte_received & 0xF); + break; + + case CommandState.GB_PRINTER_COMMAND_COMPRESSION: + compression = (byte_received & 1) != 0; + break; + + case CommandState.GB_PRINTER_COMMAND_LENGTH_LOW: + length_left = byte_received; + break; + + case CommandState.GB_PRINTER_COMMAND_LENGTH_HIGH: + length_left |= (ushort)((byte_received & 3) << 8); + break; + + case CommandState.GB_PRINTER_COMMAND_DATA: + if (command_length != GB_PRINTER_MAX_COMMAND_LENGTH) + { + if (compression) + { + if (compression_run_lenth == 0) + { + compression_run_is_compressed = (byte_received & 0x80) != 0; + compression_run_lenth = (byte)((byte_received & 0x7F) + 1 + (compression_run_is_compressed ? 1 : 0)); + } + else if (compression_run_is_compressed) + { + while (compression_run_lenth > 0) + { + command_data[command_length++] = byte_received; + compression_run_lenth--; + if (command_length == GB_PRINTER_MAX_COMMAND_LENGTH) + { + compression_run_lenth = 0; + } + } + } + else + { + command_data[command_length++] = byte_received; + compression_run_lenth--; + } + } + else + { + command_data[command_length++] = byte_received; + } + } + length_left--; + break; + + case CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW: + checksum ^= byte_received; + break; + + case CommandState.GB_PRINTER_COMMAND_CHECKSUM_HIGH: + checksum ^= (ushort)(byte_received << 8); + if (checksum != 0) + { + status |= 1; /* Checksum error*/ + command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1; + return byte_to_send; + } + break; + + case CommandState.GB_PRINTER_COMMAND_ACTIVE: + byte_to_send = 0x81; + break; + + case CommandState.GB_PRINTER_COMMAND_STATUS: + + if (((int)command_id & 0xF) == (byte)CommandID.GB_PRINTER_INIT_COMMAND) + { + /* Games expect INIT commands to return 0? */ + byte_to_send = 0; + } + else + { + byte_to_send = status; + } + + /* Printing is done instantly, but let the game recieve a 6 (Printing) status at least once, for compatibility */ + if (status == 6) + { + status = 4; /* Done */ + } + + command_state = CommandState.GB_PRINTER_COMMAND_MAGIC1; + HandleCommand(); + return byte_to_send; + } + + if (command_state >= CommandState.GB_PRINTER_COMMAND_ID && command_state < CommandState.GB_PRINTER_COMMAND_CHECKSUM_LOW) + { + checksum += byte_received; + } + + if (command_state != CommandState.GB_PRINTER_COMMAND_DATA) + { + command_state++; + } + + if (command_state == CommandState.GB_PRINTER_COMMAND_DATA) + { + if (length_left == 0) + { + command_state++; + } + } + + return byte_to_send; + } + + void HandleCommand() + { + switch (command_id) + { + case CommandID.GB_PRINTER_INIT_COMMAND: + status = 0; + image_offset = 0; + break; + + case CommandID.GB_PRINTER_START_COMMAND: + if (command_length == 4) + { + status = 6; /* Printing */ + uint[] outputImage = new uint[image_offset]; + + int palette = command_data[2]; + uint[] colors = new uint[] { + 0xFFFFFFFFU, + 0xFFAAAAAAU, + 0xFF555555U, + 0xFF000000U + }; + for (int i = 0; i < image_offset; i++) + { + outputImage[i] = colors[(palette >> (image[i] * 2)) & 3]; + } + + if (callback != null) + { + // The native-friendly callback almost seems silly now :P + unsafe + { + fixed (uint* imagePtr = outputImage) + { + callback((IntPtr)imagePtr, (byte)(image_offset / 160), + (byte)(command_data[1] >> 4), (byte)(command_data[1] & 7), + (byte)(command_data[3] & 0x7F)); + } + } + } + + image_offset = 0; + } + break; + + case CommandID.GB_PRINTER_DATA_COMMAND: + if (command_length == GB_PRINTER_DATA_SIZE) + { + image_offset %= (ushort)image.Length; + status = 8; /* Received 0x280 bytes */ + + int data_index = 0; + + for (int row = 2; row > 0; row--) + { + for (int tile_x = 0; tile_x < 160 / 8; tile_x++) + { + for (int y = 0; y < 8; y++, data_index += 2) + { + for (int x_pixel = 0; x_pixel < 8; x_pixel++) + { + image[image_offset + tile_x * 8 + x_pixel + y * 160] = + (byte)((command_data[data_index] >> 7) | ((command_data[data_index + 1] >> 7) << 1)); + command_data[data_index] <<= 1; + command_data[data_index + 1] <<= 1; + } + } + } + + image_offset += 8 * 160; + } + } + break; + + default: + break; + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs index b874919ad7..bc7d54a30e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/IGameboyCommon.cs @@ -13,6 +13,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy /// current value of register $ff40 (LCDC) public delegate void ScanlineCallback(byte lcdc); + /// + /// + /// The image data + /// How tall an image is, in pixels. Image is only valid up to that height and must be assumed to be garbage below that. + /// The top margin of blank pixels. Just form feeds the printer a certain amount at the top. + /// The bottom margin of blank pixels. Just form feeds the printer a certain amount at the bottom. + /// The darkness/intensity of the print job. What the exact values mean is somewhat subjective but 127 is the most exposed/darkest value. + public delegate void PrinterCallback(IntPtr image, byte height, byte top_margin, byte bottom_margin, byte exposure); + public interface IGameboyCommon : ISpecializedEmulatorService { bool IsCGBMode(); @@ -23,6 +32,12 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy /// /// scanline. -1 = end of frame, -2 = RIGHT NOW void SetScanlineCallback(ScanlineCallback callback, int line); + + /// + /// Set up printer callback + /// + /// The callback to get the image. Setting this to non-null also "connects" the printer as the serial device. + void SetPrinterCallback(PrinterCallback callback); } public class GPUMemoryAreas : IMonitor diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs index 06aaa58fa6..88c68bd3ed 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibGambatte.cs @@ -264,6 +264,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy /// the callback [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void gambatte_setrtccallback(IntPtr core, RTCCallback callback); + + /// + /// type of the link data sent callback + /// + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void LinkCallback(); + + /// + /// sets the Link data sent callback. + /// + /// opaque state pointer + /// the callback + [DllImport("libgambatte.dll", CallingConvention = CallingConvention.Cdecl)] + public static extern void gambatte_setlinkcallback(IntPtr core, LinkCallback callback); /// /// Returns true if the currently loaded ROM image is treated as having CGB support. diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs index 405635404c..0e33c042fe 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/LibSameboy.cs @@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy public long Time; public Buttons Keys; } - + [BizImport(CC)] public abstract bool Init(bool cgb, byte[] spc, int spclen); @@ -51,5 +51,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy [BizImport(CC)] public abstract bool HasSaveRam(); + + [BizImport(CC)] + public abstract void SetPrinterCallback(PrinterCallback callback); } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs index 69695f892f..59a3c7aa7c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Sameboy.cs @@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy { Filename = "sameboy.wbx", SbrkHeapSizeKB = 192, - InvisibleHeapSizeKB = 4, + InvisibleHeapSizeKB = 12, SealedHeapSizeKB = 9 * 1024, PlainHeapSizeKB = 4, MmapHeapSizeKB = 1024 @@ -300,6 +300,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy protected override void LoadStateBinaryInternal(BinaryReader reader) { UpdateCoreScanlineCallback(false); + _core.SetPrinterCallback(_printerCallback); } public bool IsCGBMode() => _cgb; @@ -339,5 +340,13 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.Gameboy } } } + + private PrinterCallback _printerCallback; + + public void SetPrinterCallback(PrinterCallback callback) + { + _printerCallback = callback; + _core.SetPrinterCallback(callback); + } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IStatable.cs index 547e566477..31434f2b0c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.IStatable.cs @@ -17,9 +17,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 { var temp = SaveStateBinary(); temp.SaveAsHexFast(writer); - - // write extra copy of stuff we don't use - writer.WriteLine("Frame {0}", Frame); } public void LoadStateText(TextReader reader) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs index 828f2f1a8e..ee927c10d0 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64Input.cs @@ -73,9 +73,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 } private const sbyte _maxAnalogX = 127; - private const sbyte _minAnalogX = -127; + private const sbyte _minAnalogX = -128; private const sbyte _maxAnalogY = 127; - private const sbyte _minAnalogY = -127; + private const sbyte _minAnalogY = -128; /// /// Translates controller input from EmuHawk into diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs index f45b8719a1..72cbcba367 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/APU.cs @@ -20,13 +20,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { public sealed class APU { - public static bool CFG_DECLICK = true; - - public int Square1V = 376; - public int Square2V = 376; - public int TriangleV = 426; - public int NoiseV = 247; - public int DMCV = 167; + public int m_vol = 1; public int dmc_dma_countdown = -1; public bool call_from_write; @@ -53,11 +47,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES pulse[1] = new PulseUnit(this, 1); if (old != null) { - Square1V = old.Square1V; - Square2V = old.Square2V; - TriangleV = old.TriangleV; - NoiseV = old.NoiseV; - DMCV = old.DMCV; + m_vol = old.m_vol; } } @@ -1338,8 +1328,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } SyncIRQ(); - nes.irq_apu = irq_pending; - + // since the units run concurrently, the APU frame sequencer is ran last because // it can change the ouput values of the pulse/triangle channels // we want the changes to affect it on the *next* cycle. @@ -1419,7 +1408,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES float output = pulse_out + tnd_out; // output = output * 2 - 1; // this needs to leave enough headroom for straying DC bias due to the DMC unit getting stuck outputs. smb3 is bad about that. - int mix = (int)(20000 * output); + int mix = (int)(20000 * output * (1 + m_vol/5)); dlist.Add(new Delta(sampleclock, mix - oldmix)); oldmix = mix; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs index f51293921e..09583ef19c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MLT-ACTION52.cs @@ -1,5 +1,6 @@ using BizHawk.Common; using BizHawk.Common.NumberExtensions; +using System; namespace BizHawk.Emulation.Cores.Nintendo.NES { @@ -108,6 +109,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { cheetahmen = true; } + else + { + prg_bank_mask_16k = 0x1F; + prg_bank_mask_32k = 0xF; + } AutoMapperProps.Apply(this); @@ -155,6 +161,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //$8000-FFFF: [.... ..CC] Low 2 bits of CHR //A~[..MH HPPP PPO. CCCC] + addr += 0x8000; + if (addr.Bit(13)) { SetMirrorType(EMirrorType.Horizontal); @@ -173,7 +181,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES switch (chip) { case 0: - chip_offset = 0; + chip_offset = 0x0; break; case 1: chip_offset = 0x80000; @@ -201,7 +209,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (prg_mode == false) { int bank = (prg_reg >> 1) & prg_bank_mask_32k; - return ROM[(bank * 0x8000) + addr]; + return ROM[(bank * 0x8000) + addr + chip_offset]; } else { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper114.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper114.cs new file mode 100644 index 0000000000..9405823f0d --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper114.cs @@ -0,0 +1,104 @@ +using BizHawk.Common; +using System; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + // Mapper for Aladdin Super Game + public sealed class Mapper114 : MMC3Board_Base + { + private ByteBuffer EXPREGS = new ByteBuffer(2); + + private byte[] sec = { 0, 3, 1, 5, 6, 7, 2, 4 }; + + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER114": + break; + default: + return false; + } + + BaseSetup(); + SetMirrorType(EMirrorType.Horizontal); + mmc3.MMC3Type = MMC3.EMMC3Type.MMC3A; + return true; + } + + public override void Dispose() + { + EXPREGS.Dispose(); + base.Dispose(); + } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("expregs", ref EXPREGS); + } + + public override void WriteEXP(int addr, byte value) + { + if ((addr & 0x7) == 0 && addr >= 0x1000) + { + EXPREGS[0] = value; + } + } + + public override void WriteWRAM(int addr, byte value) + { + if ((addr & 0x7) == 0) + { + EXPREGS[0] = value; + } + } + + public override void WritePRG(int addr, byte value) + { + switch (addr & 0x6000) + { + case 0x0000: //$8000 + base.SetMirrorType((value & 1) == 1 ? EMirrorType.Horizontal : EMirrorType.Vertical); + break; + case 0x2000: //$A000 + value = (byte)((value & 0xC0) | sec[value & 0x07]); + EXPREGS[1] = 1; + base.WritePRG(0, value); + break; + case 0x4000: //$C000 + if(EXPREGS[1] == 1) + { + EXPREGS[1] = 0; + base.WritePRG(1, value); + } + break; + case 0x6000: //$E000 + if (value > 0) + { + base.WritePRG(0x6001, value); + base.WritePRG(0x4000, value); + base.WritePRG(0x4001, value); + } + else + { + base.WritePRG(0x6000, value); + } + break; + } + } + + public override byte ReadPRG(int addr) + { + if ((EXPREGS[0] & 0x80) > 0) + { + var bank = (EXPREGS[0] & 0x1F); + return ROM[(bank << 14) + (addr & 0x3FFF)]; + } + else + { + return base.ReadPRG(addr); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper036.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper036.cs index 3514bf1618..8c55044f87 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper036.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper036.cs @@ -1,17 +1,21 @@ using BizHawk.Common; +using BizHawk.Common.NumberExtensions; +using System; namespace BizHawk.Emulation.Cores.Nintendo.NES { // mapper036 // Strike Wolf (MGC-014) [!].nes - // like an oversize GxROM - // information from fceux + // Using https://wiki.nesdev.com/w/index.php/INES_Mapper_036 public sealed class Mapper036 : NES.NESBoardBase { int chr; int prg; int chr_mask; int prg_mask; + byte R; + bool M; + byte P; public override bool Configure(NES.EDetectionOrigin origin) { @@ -46,10 +50,44 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public override void WritePRG(int addr, byte value) { // either hack emulation of a weird bus conflict, or crappy pirate safeguard - if (addr >= 0x400 && addr <= 0x7ffe) + prg = (R >> 4) & prg_mask; + } + + public override byte ReadEXP(int addr) + { + return (byte)(R | (NES.DB & 0xCF)); + } + + public override void WriteEXP(int addr, byte value) + { + Console.WriteLine(addr); + Console.WriteLine(value); + if ((addr & 0xE200) == 0x200) { chr = value & 15 & chr_mask; - prg = value >> 4 & 15 & prg_mask; + } + switch (addr & 0xE103) + { + case 0x100: + if (!M) + { + R = P; + } + else + { + R++; + R &= 0x30; + } + + + break; + case 0x102: + P = (byte)(value & 0x30); + prg = (value >> 4) & prg_mask; + break; + case 0x103: + M = value.Bit(4); + break; } } @@ -58,6 +96,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES base.SyncState(ser); ser.Sync("chr", ref chr); ser.Sync("prg", ref prg); + ser.Sync("R", ref R); + ser.Sync("M", ref M); + ser.Sync("P", ref P); } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/TENGEN-800032.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/TENGEN-800032.cs index 7a59062a2a..9c17d9e76d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/TENGEN-800032.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/TENGEN-800032.cs @@ -1,5 +1,6 @@ using BizHawk.Common; using BizHawk.Common.NumberExtensions; +using System; namespace BizHawk.Emulation.Cores.Nintendo.NES { @@ -25,6 +26,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES bool irq_mode; bool irq_reload_pending; int separator_counter; + int irq_countdown_2 = 0; + bool clock_scanline_irq; public override void Dispose() @@ -172,20 +175,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES case 0x4001: irq_mode = value.Bit(0); - if (irq_mode) irq_countdown = 12; + if (irq_mode) irq_countdown = 4; irq_reload_pending = true; break; case 0x6000: irq_enable = false; irq_pending = false; + irq_counter = 0; SyncIRQ(); break; case 0x6001: irq_enable = true; SyncIRQ(); break; - } } @@ -224,20 +227,79 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES { irq_counter = irq_reload + 1; irq_reload_pending = false; + + if (irq_counter == 0) + { + if (irq_enable) + { + irq_countdown_2 = 9; + } + } + } - else if (irq_counter == 0) + + irq_counter--; + if (irq_counter==0) + { + if (irq_enable) + { + irq_countdown_2 = 9; + } + + irq_counter = irq_reload + 1; + } + + if (irq_counter < 0) { irq_counter = irq_reload; } + /* + else if (irq_counter == 0) + { + + irq_counter = irq_reload; + if (irq_counter == 0) + { + if (irq_enable) + { + irq_countdown_2 = 9; + } + } + } else { irq_counter--; - if (irq_counter == 0 && irq_enable) + if (irq_enable) { - irq_pending = true; - SyncIRQ(); - } + + if (irq_counter==0) + irq_countdown_2 = 9; + } } + */ + } + + public override void ClockCPU() + { + + if (irq_mode == true) + { + irq_countdown--; + if (irq_countdown == 0) + { + ClockIRQ(); + irq_countdown = 4; + } + } + else + { + if (clock_scanline_irq) + { + clock_scanline_irq = false; + ClockIRQ(); + } + } + } public override void ClockPPU() @@ -245,14 +307,13 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if (separator_counter > 0) separator_counter--; - if (irq_countdown > 0) + if (irq_countdown_2 > 0) { - irq_countdown--; - if (irq_countdown == 0) + irq_countdown_2--; + if (irq_countdown_2==0) { - ClockIRQ(); - if (irq_mode==true) - irq_countdown = 12; + irq_pending = true; + SyncIRQ(); } } } @@ -270,7 +331,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES else { separator_counter = 15; - irq_countdown = 11; + clock_scanline_irq = true; + } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs index 9f46fdf560..e649c730e5 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/FDS.cs @@ -255,19 +255,29 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES case 0x0020: timerlatch &= 0xff00; timerlatch |= value; - //timerirq = false; break; case 0x0021: timerlatch &= 0x00ff; timerlatch |= value << 8; - //timerirq = false; break; case 0x0022: - timerreg = (byte)(value & 3); - timervalue = timerlatch; + if (diskenable) + { + timerreg = (byte)(value & 3); + if ((value & 0x02) == 0x02) + { + timervalue = timerlatch; + } + else + { + _timerirq = false; + } + } + break; case 0x0023: diskenable = (value & 1) != 0; + if (!diskenable) { _timerirq = false; } soundenable = (value & 2) != 0; break; case 0x0024: @@ -344,7 +354,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public override void ClockCPU() { - if ((timerreg & 2) != 0)// && timervalue > 0) + if ((timerreg & 2) != 0 && diskenable) { if (timervalue!=0) { @@ -352,22 +362,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } if (timervalue == 0) { - - /* - if ((timerreg & 1) != 0) - { - timervalue = timerlatch; - //timervalue = 0xFFFF; - } - else - { - timerreg &= unchecked((byte)~2); - timervalue = 0; - timerlatch = 0; - } - */ timervalue = timerlatch; timerirq = true; + if ((timerreg & 1) == 0) + { + timerreg -= 2; + } } } audio.Clock(); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs index 4861d49708..9c86f953e7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/FDS/RamAdapter.cs @@ -67,14 +67,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES byte[] fileheader = br.ReadBytes(16); if (fileheader[0] != 0x03) { - throw new Exception("Corrupt FDS block 3"); + // Instead of exceptions, display strong warnings + Console.WriteLine("WARNING: INVALID FILE, BLOCK 3 ERROR"); + //throw new Exception("Corrupt FDS block 3"); } int filesize = fileheader[13] + fileheader[14] * 256; byte[] file = br.ReadBytes(filesize + 1); if (file[0] != 0x04) { - throw new Exception("Corrupt FDS block 4"); + Console.WriteLine("WARNING: INVALID FILE, BLOCK 4 ERROR"); + //throw new Exception("Corrupt FDS block 4"); } WriteBlock(ret, fileheader, 122); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs index b23e5a55b8..667f92a230 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.Core.cs @@ -9,11 +9,10 @@ using BizHawk.Emulation.Cores.Components.M6502; namespace BizHawk.Emulation.Cores.Nintendo.NES { - public partial class NES : IEmulator + public partial class NES : IEmulator, ICycleTiming { //hardware/state public MOS6502X cpu; - int cpu_accumulate; //cpu timekeeper public PPU ppu; public APU apu; public byte[] ram; @@ -26,12 +25,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES int sprdma_countdown; bool _irq_apu; //various irq signals that get merged to the cpu irq pin - /// clock speed of the main cpu in hz + + /// clock speed of the main cpu in hz public int cpuclockrate { get; private set; } - //irq state management - public bool irq_apu { get { return _irq_apu; } set { _irq_apu = value; } } - //user configuration int[] palette_compiled = new int[64 * 8]; @@ -62,11 +59,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES private DisplayType _display_type = DisplayType.NTSC; //Sound config - public void SetSquare1(int v) { apu.Square1V = v; } - public void SetSquare2(int v) { apu.Square2V = v; } - public void SetTriangle(int v) { apu.TriangleV = v; } - public void SetNoise(int v) { apu.NoiseV = v; } - public void SetDMC(int v) { apu.DMCV = v; } + public void SetVol1(int v) { apu.m_vol = v; } /// /// for debugging only! @@ -216,6 +209,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES cpuclockrate = 1662607; cpu_sequence = cpu_sequence_PAL; _display_type = DisplayType.PAL; + ClockRate = 5320342.5; break; case Common.DisplayType.NTSC: apu = new APU(this, apu, false); @@ -224,6 +218,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES VsyncDen = 655171; cpuclockrate = 1789773; cpu_sequence = cpu_sequence_NTSC; + ClockRate = 5369318.1818181818181818181818182; break; // this is in bootgod, but not used at all case Common.DisplayType.Dendy: @@ -234,6 +229,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES cpuclockrate = 1773448; cpu_sequence = cpu_sequence_NTSC; _display_type = DisplayType.Dendy; + ClockRate = 5320342.5; break; default: throw new Exception("Unknown displaytype!"); @@ -296,6 +292,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } + public long CycleCount => ppu.TotalCycles; + public double ClockRate { get; private set; } + private int VsyncNum { get; set; } private int VsyncDen { get; set; } @@ -360,7 +359,40 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES VS_coin_inserted &= 1; } - ppu.FrameAdvance(); + if (ppu.ppudead > 0) + { + while (ppu.ppudead > 0) + { + ppu.NewDeadPPU(); + } + } + else + { + ppu.ppu_init_frame(); + + ppu.do_vbl = true; + ppu.do_active_sl = true; + ppu.do_pre_vbl = true; + + // do the vbl ticks seperate, that will save us a few checks that don't happen in active region + while (ppu.do_vbl) + { + ppu.TickPPU_VBL(); + } + + // now do the rest of the frame + while (ppu.do_active_sl) + { + ppu.TickPPU_active(); + } + + // now do the pre-NMI lines + while (ppu.do_pre_vbl) + { + ppu.TickPPU_preVBL(); + } + } + if (lagged) { _lagcount++; @@ -380,7 +412,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //PAL: - //0 15 30 45 60 -> 12 27 42 57 -> 9 24 39 54 -> 6 21 36 51 -> 3 18 33 48 -> 0 //sequence of ppu clocks per cpu clock: 3,3,3,3,4 //at least it should be, but something is off with that (start up time?) so it is 3,3,3,4,3 for now //NTSC: diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ICodeDataLogger.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ICodeDataLogger.cs new file mode 100644 index 0000000000..c1f2a5b4fa --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ICodeDataLogger.cs @@ -0,0 +1,113 @@ +using System; +using System.IO; +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + public sealed partial class NES : ICodeDataLogger + { + public void SetCDL(ICodeDataLog cdl) + { + CDL = cdl; + if (cdl == null) + { + cpu.ReadMemory = ReadMemory; + cpu.WriteMemory = WriteMemory; + cpu.PeekMemory = PeekMemory; + } + else + { + cpu.ReadMemory = ReadMemory_CDL; + cpu.WriteMemory = WriteMemory; + cpu.PeekMemory = FetchMemory_CDL; + } + } + + public void NewCDL(ICodeDataLog cdl) + { + cdl["RAM"] = new byte[_memoryDomains["RAM"].Size]; + + if (_memoryDomains.Has("Save RAM")) + { + cdl["Save RAM"] = new byte[_memoryDomains["Save RAM"].Size]; + } + + if (_memoryDomains.Has("Battery RAM")) + { + cdl["Battery RAM"] = new byte[_memoryDomains["Battery RAM"].Size]; + } + + if (_memoryDomains.Has("Battery RAM")) + { + cdl["Battery RAM"] = new byte[_memoryDomains["Battery RAM"].Size]; + } + + cdl.SubType = "NES"; + cdl.SubVer = 0; + } + + [FeatureNotImplemented] + public void DisassembleCDL(Stream s, ICodeDataLog cdl) + { + + } + + private enum CDLog_AddrType + { + None, + ROM, + MainRAM, + SaveRAM, + } + + [Flags] + private enum CDLog_Flags + { + ExecFirst = 0x01, + ExecOperand = 0x02, + Data = 0x04 + }; + + private struct CDLog_MapResults + { + public CDLog_AddrType Type; + public int Address; + } + + private delegate CDLog_MapResults MapMemoryDelegate(ushort addr, bool write); + private MapMemoryDelegate MapMemory; + private ICodeDataLog CDL; + + private void RunCDL(ushort address, CDLog_Flags flags) + { + if (MapMemory != null) + { + CDLog_MapResults results = MapMemory(address, false); + switch (results.Type) + { + case CDLog_AddrType.None: break; + case CDLog_AddrType.MainRAM: CDL["Main RAM"][results.Address] |= (byte)flags; break; + case CDLog_AddrType.SaveRAM: CDL["Save RAM"][results.Address] |= (byte)flags; break; + } + } + } + + /// + /// A wrapper for FetchMemory which inserts CDL logic + /// + private byte FetchMemory_CDL(ushort address) + { + RunCDL(address, CDLog_Flags.ExecFirst); + return PeekMemory(address); + } + + /// + /// A wrapper for ReadMemory which inserts CDL logic + /// + private byte ReadMemory_CDL(ushort address) + { + RunCDL(address, CDLog_Flags.Data); + return ReadMemory(address); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs index 784b3b6fa5..40a8878a69 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISettable.cs @@ -39,11 +39,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES SetPalette(Settings.Palette); - apu.Square1V = Settings.Square1; - apu.Square2V = Settings.Square2; - apu.TriangleV = Settings.Triangle; - apu.NoiseV = Settings.Noise; - apu.DMCV = Settings.DMC; + apu.m_vol = Settings.APU_vol; return false; } @@ -157,11 +153,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public byte[,] Palette; - public int Square1 = 376; - public int Square2 = 376; - public int Triangle = 426; - public int Noise = 247; - public int DMC = 167; + public int APU_vol = 1; public NESSettings Clone() { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs index e5ac4f54b9..e2dd212602 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.IStatable.cs @@ -57,7 +57,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES cpu.SyncState(ser); ser.Sync("ram", ref ram, false); ser.Sync("CIRAM", ref CIRAM, false); - ser.Sync("cpu_accumulate", ref cpu_accumulate); ser.Sync("_irq_apu", ref _irq_apu); ser.Sync("sprdma_countdown", ref sprdma_countdown); ser.Sync("cpu_deadcounter", ref cpu_deadcounter); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index df7200f478..f575a7c71e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES isPorted: false, isReleased: true)] public partial class NES : IEmulator, ISaveRam, IDebuggable, IStatable, IInputPollable, IRegionable, - IBoardInfo, ISettable + IBoardInfo, ISettable, ICodeDataLogger { [CoreConstructor("NES")] public NES(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings) @@ -876,10 +876,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //todo //http://blog.ntrq.net/?p=428 -//cpu bus junk bits - -//UBER DOC -//http://nocash.emubase.de/everynes.htm //A VERY NICE board assignments list //http://personales.epsg.upv.es/~jogilmo1/nes/TEXTOS/ARXIUS/BOARDTABLE.TXT @@ -889,6 +885,3 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //a mappers list //http://tuxnes.sourceforge.net/nesmapper.txt - -//some ppu tests -//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs index 7e97f907cc..320113d52f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.cs @@ -135,7 +135,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //when the ppu issues a write it goes through here and into the game board public void ppubus_write(int addr, byte value) { - if (ppur.status.sl == 241 || !PPUON) + if (ppur.status.sl >= 241 || !PPUON) nes.Board.AddressPPU(addr); nes.Board.WritePPU(addr, value); @@ -194,7 +194,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //state - int ppudead; //measured in frames + public int ppudead; //measured in frames bool idleSynch; int NMI_PendingInstructions; byte PPUGenLatch; @@ -203,6 +203,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public byte[] OAM; public byte[] PALRAM; + private long _totalCycles; + public long TotalCycles => _totalCycles; + public void SyncState(Serializer ser) { ser.Sync("cpu_step", ref cpu_step); @@ -215,12 +218,22 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("VRAMBuffer", ref VRAMBuffer); ser.Sync("ppu_addr_temp", ref ppu_addr_temp); + ser.Sync("spr_true_count", ref spr_true_count); + ser.Sync("sprite_eval_write", ref sprite_eval_write); ser.Sync("Read_Value", ref read_value); ser.Sync("Prev_soam_index", ref soam_index_prev); ser.Sync("Spr_Zero_Go", ref sprite_zero_go); ser.Sync("Spr_zero_in_Range", ref sprite_zero_in_range); ser.Sync("Is_even_cycle", ref is_even_cycle); ser.Sync("soam_index", ref soam_index); + ser.Sync("soam_m_index", ref soam_m_index); + ser.Sync("oam_index", ref oam_index); + ser.Sync("oam_index_aux", ref oam_index_aux); + ser.Sync("soam_index_aux", ref soam_index_aux); + ser.Sync("yp", ref yp); + ser.Sync("target", ref target); + ser.Sync("ppu_was_on", ref ppu_was_on); + ser.Sync("spriteHeight", ref spriteHeight); ser.Sync("install_2006", ref install_2006); ser.Sync("race_2006", ref race_2006); ser.Sync("install_2001", ref install_2001); @@ -233,6 +246,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("glitchy_reads_2003", ref glitchy_reads_2003, false); ser.Sync("OAM", ref OAM, false); + ser.Sync("soam", ref soam, false); ser.Sync("PALRAM", ref PALRAM, false); ser.Sync("Reg2002_objoverflow", ref Reg2002_objoverflow); @@ -248,6 +262,61 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //don't sync framebuffer into binary (rewind) states if(ser.IsText) ser.Sync("xbuf", ref xbuf, false); + + ser.Sync("_totalCycles", ref _totalCycles); + + ser.Sync("do_vbl", ref do_vbl); + ser.Sync("do_active_sl", ref do_active_sl); + ser.Sync("do_pre_vbl", ref do_pre_vbl); + + ser.Sync("nmi_destiny", ref nmi_destiny); + ser.Sync("yp_shift", ref yp_shift); + ser.Sync("sprite_eval_cycle", ref sprite_eval_cycle); + ser.Sync("xt", ref xt); + ser.Sync("xp", ref xp); + ser.Sync("xstart", ref xstart); + ser.Sync("rasterpos", ref rasterpos); + ser.Sync("renderspritenow", ref renderspritenow); + ser.Sync("renderbgnow", ref renderbgnow); + ser.Sync("hit_pending", ref hit_pending); + ser.Sync("s", ref s); + ser.Sync("ppu_aux_index", ref ppu_aux_index); + ser.Sync("junksprite", ref junksprite); + ser.Sync("line", ref line); + ser.Sync("patternNumber", ref patternNumber); + ser.Sync("patternAddress", ref patternAddress); + ser.Sync("temp_addr", ref temp_addr); + ser.Sync("sl_sprites", ref sl_sprites, false); + + byte bg_byte; + for (int i = 0; i < 34; i++) + { + string str = "bgdata" + i.ToString() + "at"; + bg_byte = bgdata[i].at; ser.Sync(str, ref bg_byte); bgdata[i].at = bg_byte; + str = "bgdata" + i.ToString() + "nt"; + bg_byte = bgdata[i].nt; ser.Sync(str, ref bg_byte); bgdata[i].nt = bg_byte; + str = "bgdata" + i.ToString() + "pt0"; + bg_byte = bgdata[i].pt_0; ser.Sync(str, ref bg_byte); bgdata[i].pt_0 = bg_byte; + str = "bgdata" + i.ToString() + "pt1"; + bg_byte = bgdata[i].pt_1; ser.Sync(str, ref bg_byte); bgdata[i].pt_1 = bg_byte; + } + + byte oam_byte; + for (int i = 0; i < 64; i++) + { + string str = "oamdata" + i.ToString() + "y"; + oam_byte = t_oam[i].oam_y; ser.Sync(str, ref oam_byte); t_oam[i].oam_y = oam_byte; + str = "oamdata" + i.ToString() + "ind"; + oam_byte = t_oam[i].oam_ind; ; ser.Sync(str, ref oam_byte); t_oam[i].oam_ind = oam_byte; + str = "oamdata" + i.ToString() + "attr"; + oam_byte = t_oam[i].oam_attr; ser.Sync(str, ref oam_byte); t_oam[i].oam_attr = oam_byte; + str = "oamdata" + i.ToString() + "x"; + oam_byte = t_oam[i].oam_x; ser.Sync(str, ref oam_byte); t_oam[i].oam_x = oam_byte; + str = "oamdata" + i.ToString() + "p0"; + oam_byte = t_oam[i].patterns_0; ser.Sync(str, ref oam_byte); t_oam[i].patterns_0 = oam_byte; + str = "oamdata" + i.ToString() + "p1"; + oam_byte = t_oam[i].patterns_1; ser.Sync(str, ref oam_byte); t_oam[i].patterns_1 = oam_byte; + } } public void Reset() @@ -259,87 +328,91 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppu_open_bus_decay_timer = new int[8]; } - void runppu(int x) + void runppu() { //run one ppu cycle at a time so we can interact with the ppu and clockPPU at high granularity - for (int i = 0; i < x; i++) + + race_2006 = false; + if (install_2006>0) { - race_2006 = false; - if (install_2006>0) + install_2006--; + if (install_2006==0) { - install_2006--; - if (install_2006==0) - { - ppur.install_latches(); + ppur.install_latches(); - //nes.LogLine("addr wrote vt = {0}, ht = {1}", ppur._vt, ppur._ht); - //normally the address isnt observed by the board till it gets clocked by a read or write. - //but maybe thats just because a ppu read/write shoves it on the address bus - //apparently this shoves it on the address bus, too, or else blargg's mmc3 tests dont pass - //ONLY if the ppu is not rendering - if (ppur.status.sl == 241 || !PPUON) - nes.Board.AddressPPU(ppur.get_2007access()); + //nes.LogLine("addr wrote vt = {0}, ht = {1}", ppur._vt, ppur._ht); + //normally the address isnt observed by the board till it gets clocked by a read or write. + //but maybe thats just because a ppu read/write shoves it on the address bus + //apparently this shoves it on the address bus, too, or else blargg's mmc3 tests dont pass + //ONLY if the ppu is not rendering + if (ppur.status.sl >= 241 || !PPUON) + nes.Board.AddressPPU(ppur.get_2007access()); - race_2006 = true; - } - } - - if (install_2001 > 0) - { - install_2001--; - if (install_2001 == 0) - { - show_bg_new = reg_2001.show_bg; - show_obj_new = reg_2001.show_obj; - } - } - - ppur.status.cycle++; - is_even_cycle = !is_even_cycle; - - // Here we execute a CPU instruction if enough PPU cycles have passed - // also do other things that happen at instruction level granularity - cpu_stepcounter++; - if (cpu_stepcounter == nes.cpu_sequence[cpu_step]) - { - cpu_step++; - if (cpu_step == 5) cpu_step = 0; - cpu_stepcounter = 0; - - // this is where the CPU instruction is called - nes.RunCpuOne(); - - // decay the ppu bus, approximating real behaviour - PpuOpenBusDecay(DecayType.None); - - // Check for NMIs - if (NMI_PendingInstructions > 0) - { - NMI_PendingInstructions--; - if (NMI_PendingInstructions <= 0) - { - nes.cpu.NMI = true; - } - } - } - - if (Reg2002_vblank_active_pending) - { - Reg2002_vblank_active = 1; - Reg2002_vblank_active_pending = false; - } - - if (Reg2002_vblank_clear_pending) - { - Reg2002_vblank_active = 0; - Reg2002_vblank_clear_pending = false; - } - - if (HasClockPPU) - { - nes.Board.ClockPPU(); + race_2006 = true; } } - } + + if (install_2001 > 0) + { + install_2001--; + if (install_2001 == 0) + { + show_bg_new = reg_2001.show_bg; + show_obj_new = reg_2001.show_obj; + } + } + + ppur.status.cycle++; + is_even_cycle = !is_even_cycle; + + if (PPUON && ppur.status.cycle >= 257 && ppur.status.cycle <= 320 && ppur.status.sl <= 240) + { + reg_2003 = 0; + } + + // Here we execute a CPU instruction if enough PPU cycles have passed + // also do other things that happen at instruction level granularity + cpu_stepcounter++; + if (cpu_stepcounter == nes.cpu_sequence[cpu_step]) + { + cpu_step++; + if (cpu_step == 5) cpu_step = 0; + cpu_stepcounter = 0; + + // this is where the CPU instruction is called + nes.RunCpuOne(); + + // decay the ppu bus, approximating real behaviour + PpuOpenBusDecay(DecayType.None); + + // Check for NMIs + if (NMI_PendingInstructions > 0) + { + NMI_PendingInstructions--; + if (NMI_PendingInstructions <= 0) + { + nes.cpu.NMI = true; + } + } + } + + if (Reg2002_vblank_active_pending) + { + Reg2002_vblank_active = 1; + Reg2002_vblank_active_pending = false; + } + + if (Reg2002_vblank_clear_pending) + { + Reg2002_vblank_active = 0; + Reg2002_vblank_clear_pending = false; + } + + if (HasClockPPU) + { + nes.Board.ClockPPU(); + } + _totalCycles += 1; + } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs index 5e6865a382..a0aed3f502 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.regs.cs @@ -1,10 +1,10 @@ //blargg: Reading from $2007 when the VRAM address is $3fxx will fill the internal read buffer with the contents at VRAM address $3fxx, in addition to reading the palette RAM. - //static const byte powerUpPalette[] = - //{ - // 0x3F,0x01,0x00,0x01, 0x00,0x02,0x02,0x0D, 0x08,0x10,0x08,0x24, 0x00,0x00,0x04,0x2C, - // 0x09,0x01,0x34,0x03, 0x00,0x04,0x00,0x14, 0x08,0x3A,0x00,0x02, 0x00,0x20,0x2C,0x08 - //}; +//static const byte powerUpPalette[] = +//{ +// 0x3F,0x01,0x00,0x01, 0x00,0x02,0x02,0x0D, 0x08,0x10,0x08,0x24, 0x00,0x00,0x04,0x2C, +// 0x09,0x01,0x34,0x03, 0x00,0x04,0x00,0x14, 0x08,0x3A,0x00,0x02, 0x00,0x20,0x2C,0x08 +//}; using System; using BizHawk.Common; @@ -40,10 +40,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES show_obj_leftmost = (value >> 2) & 1; show_bg = (value >> 3) & 1; show_obj = (value >> 4) & 1; - intense_green = (value >> 5) & 1; intense_blue = (value >> 6) & 1; intense_red = (value >> 7) & 1; - intensity_lsl_6 = ((value >> 5) & 7)<<6; + intense_green = (value >> 5) & 1; + intensity_lsl_6 = ((value >> 5) & 7)<<6; } } } @@ -90,8 +90,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ser.Sync("_ht", ref _ht); ser.Sync("fh", ref fh); ser.Sync("status.cycle", ref status.cycle); - int junk = 0; - ser.Sync("status.end_cycle", ref junk); ser.Sync("status.sl", ref status.sl); } @@ -148,7 +146,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES fh = 0; _fv = _v = _h = _vt = _ht = 0; status.cycle = 0; - status.sl = 241; + status.sl = 0; } public void install_latches() @@ -427,10 +425,33 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //OAM DATA (write) void write_2004(byte value) { - if ((reg_2003 & 3) == 2) value &= 0xE3; //some of the OAM bits are unwired so we mask them out here - //otherwise we just write this value and move on to the next oam byte - OAM[reg_2003] = value; - reg_2003++; + if ((reg_2003 & 3) == 2) + { + //some of the OAM bits are unwired so we mask them out here + //otherwise we just write this value and move on to the next oam byte + value &= 0xE3; + } + if (ppur.status.rendering) + { + // don't write to OAM if the screen is on and we are in the active display area + // this impacts sprite evaluation + if (show_bg_new || show_obj_new) + { + // glitchy increment of OAM index + oam_index += 4; + } + else + { + OAM[reg_2003] = value; + reg_2003++; + } + } + else + { + OAM[reg_2003] = value; + reg_2003++; + } + } byte read_2004() { @@ -564,7 +585,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppur.increment2007(ppur.status.rendering && PPUON, reg_2000.vram_incr32 != 0); //see comments in $2006 - if (ppur.status.sl == 241 || !PPUON) + if (ppur.status.sl >= 241 || !PPUON) nes.Board.AddressPPU(ppur.get_2007access()); } byte read_2007() @@ -588,7 +609,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES ppur.increment2007(ppur.status.rendering && PPUON, reg_2000.vram_incr32 != 0); //see comments in $2006 - if (ppur.status.sl == 241 || !PPUON) + if (ppur.status.sl >= 241 || !PPUON) nes.Board.AddressPPU(ppur.get_2007access()); // update open bus here diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs index 781adc1ec4..768c95f13b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/PPU.run.cs @@ -1,21 +1,21 @@ //TODO - correctly emulate PPU OFF state using BizHawk.Common; +using BizHawk.Common.NumberExtensions; using System; namespace BizHawk.Emulation.Cores.Nintendo.NES { sealed partial class PPU { - const int kFetchTime = 2; - const int kLineTime = 341; - struct BGDataRecord { public byte nt, at; public byte pt_0, pt_1; }; + BGDataRecord[] bgdata = new BGDataRecord[34]; + public short[] xbuf = new short[256 * 240]; // values here are used in sprite evaluation @@ -26,8 +26,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int soam_index_prev; public int soam_m_index; public int oam_index; - public byte read_value_aux; - public int soam_m_index_aux; public int oam_index_aux; public int soam_index_aux; public bool is_even_cycle; @@ -36,9 +34,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES public int yp; public int target; public int spriteHeight; - public byte[] soam = new byte[512]; // in a real nes, this would only be 32, but we wish to allow more then 8 sprites per scanline - public bool reg_2001_color_disable_latch; // the value used here is taken + public byte[] soam = new byte[256]; // in a real nes, this would only be 32, but we wish to allow more then 8 sprites per scanline public bool ppu_was_on; + public byte[] sl_sprites = new byte[3 * 256]; // installing vram address is delayed after second write to 2006, set this up here public int install_2006; @@ -60,36 +58,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES TempOAM[] t_oam = new TempOAM[64]; int ppu_addr_temp; - void Read_bgdata(ref BGDataRecord bgdata) - { - for (int i = 0; i < 8; i++) - { - Read_bgdata(i, ref bgdata); - runppu(1); - - if (PPUON && i==6) - { - ppu_was_on = true; - } - - if (PPUON && i==7) - { - if (!race_2006) - ppur.increment_hsc(); - - if (ppur.status.cycle == 256 && !race_2006) - ppur.increment_vs(); - - ppu_was_on = false; - } - } - } // attempt to emulate graphics pipeline behaviour // experimental int pixelcolor_latch_1; int pixelcolor_latch_2; - void pipeline(int pixelcolor, int target, int row_check) + void pipeline(int pixelcolor, int row_check) { if (row_check > 1) { @@ -101,11 +75,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES xbuf[(target - 2)] = (short)(pixelcolor_latch_2 | reg_2001.intensity_lsl_6); } - if (row_check >= 1) - { - pixelcolor_latch_2 = pixelcolor_latch_1; - } - + pixelcolor_latch_2 = pixelcolor_latch_1; pixelcolor_latch_1 = pixelcolor; } @@ -129,7 +99,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES if ((ppur.ht & 2) != 0) at >>= 2; at &= 0x03; at <<= 2; - bgdata.at = at; + bgdata.at = at; break; } case 3: @@ -149,560 +119,477 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } //switch(cycle) } - public unsafe void FrameAdvance() - { - BGDataRecord* bgdata = stackalloc BGDataRecord[34]; //one at the end is junk, it can never be rendered + // these are states for the ppu incrementer + public bool do_vbl; + public bool do_active_sl; + public bool do_pre_vbl; - //262 scanlines - if (ppudead != 0) - { - FrameAdvance_ppudead(); - return; - } + bool nmi_destiny; + int yp_shift; + int sprite_eval_cycle; + int xt; + int xp; + int xstart; + int rasterpos; + bool renderspritenow; + bool renderbgnow; + bool hit_pending; + int s; + int ppu_aux_index; + bool junksprite; + int line; + int patternNumber; + int patternAddress; + int temp_addr; + + public void ppu_init_frame() + { + ppur.status.sl = 241 + preNMIlines; + ppur.status.cycle = 0; + + // These things happen at the start of every frame Reg2002_vblank_active_pending = true; ppuphase = PPUPHASE.VBL; - ppur.status.sl = 241; + bgdata = new BGDataRecord[34]; + } - //Not sure if this is correct. According to Matt Conte and my own tests, it is. Timing is probably off, though. - //NOTE: Not having this here breaks a Super Donkey Kong game. - if (PPUON) reg_2003 = 0; + public void TickPPU_VBL() + { + if (ppur.status.cycle == 3 && ppur.status.sl == 241 + preNMIlines) + { + nmi_destiny = reg_2000.vblank_nmi_gen && Reg2002_vblank_active; + } + else if (ppur.status.cycle == 6 && ppur.status.sl == 241 + preNMIlines) + { + if (nmi_destiny) { nes.cpu.NMI = true; } + nes.Board.AtVsyncNMI(); + } - //this was repeatedly finetuned from the fceux days thrugh the old cpu core and into the new one to pass 05-nmi_timing.nes - //note that there is still some leniency. for instance, 4,2 will pass in addition to 3,3 - const int delay = 6; - runppu(3); - bool nmi_destiny = reg_2000.vblank_nmi_gen && Reg2002_vblank_active; - runppu(3); - if (nmi_destiny) nes.cpu.NMI = true; + runppu(); // note cycle ticks inside runppu - nes.Board.AtVsyncNMI(); - runppu(postNMIlines * kLineTime - delay); - - //this seems to happen just before the dummy scanline begins - Reg2002_objhit = Reg2002_objoverflow = 0; - Reg2002_vblank_clear_pending = true; - - idleSynch ^= true; - - //render 241 scanlines (including 1 dummy at beginning) - for (int sl = 0; sl < 241; sl++) + if (ppur.status.cycle == 341) { ppur.status.cycle = 0; + ppur.status.sl++; + if (ppur.status.sl == 241 + preNMIlines + postNMIlines) + { + Reg2002_objhit = Reg2002_objoverflow = 0; + Reg2002_vblank_clear_pending = true; + idleSynch ^= true; - ppur.status.sl = sl; + do_vbl = false; + ppur.status.sl = 0; + } + } + } + + public void TickPPU_active() + { + if (ppur.status.cycle == 0) + { + ppur.status.cycle = 0; spr_true_count = 0; soam_index = 0; soam_m_index = 0; - soam_m_index_aux = 0; oam_index_aux = 0; oam_index = 0; is_even_cycle = true; sprite_eval_write = true; sprite_zero_go = sprite_zero_in_range; - sprite_zero_in_range = false; + sprite_zero_in_range = false; - yp = sl - 1; + yp = ppur.status.sl - 1; ppuphase = PPUPHASE.BG; - // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM and written to from - // the current location off PPUADDR" - if (sl == 0 && PPUON && reg_2003 >= 8 && region==Region.NTSC) + // "If PPUADDR is not less then 8 when rendering starts, the first 8 bytes in OAM are written to from + // the current location of PPUADDR" + if (ppur.status.sl == 0 && PPUON && reg_2003 >= 8 && region == Region.NTSC) { for (int i = 0; i < 8; i++) { - OAM[i] = OAM[reg_2003 & 0xF8 + i]; + OAM[i] = OAM[(reg_2003 & 0xF8) + i]; } } - + if (NTViewCallback != null && yp == NTViewCallback.Scanline) NTViewCallback.Callback(); if (PPUViewCallback != null && yp == PPUViewCallback.Scanline) PPUViewCallback.Callback(); - //ok, we're also going to draw here. - //unless we're on the first dummy scanline - if (sl != 0) + // set up intial values to use later + yp_shift = yp << 8; + xt = 0; + xp = 0; + + sprite_eval_cycle = 0; + + xstart = xt << 3; + target = yp_shift + xstart; + rasterpos = xstart; + + spriteHeight = reg_2000.obj_size_16 ? 16 : 8; + + //check all the conditions that can cause things to render in these 8px + renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost); + hit_pending = false; + + } + + if (ppur.status.cycle < 256) + { + if (ppur.status.sl != 0) { - //the main scanline rendering loop: - //32 times, we will fetch a tile and then render 8 pixels. - //two of those tiles were read in the last scanline. - int yp_shift = yp << 8; - for (int xt = 0; xt < 32; xt++) + ///////////////////////////////////////////// + // Sprite Evaluation Start + ///////////////////////////////////////////// + + if (sprite_eval_cycle <= 63 && !is_even_cycle) { - int xstart = xt << 3; + // the first 64 cycles of each scanline are used to initialize sceondary OAM + // the actual effect setting a flag that always returns 0xFF from a OAM read + // this is a bit of a shortcut to save some instructions + // data is read from OAM as normal but never used + soam[soam_index] = 0xFF; + soam_index++; + } + if (sprite_eval_cycle == 64) + { + soam_index = 0; + oam_index = reg_2003; + } + + // otherwise, scan through OAM and test if sprites are in range + // if they are, they get copied to the secondary OAM + if (sprite_eval_cycle >= 64) + { + if (oam_index >= 256) + { + oam_index = 0; + sprite_eval_write = false; + } + + if (is_even_cycle && oam_index < 256) + { + if ((oam_index + soam_m_index) < 256) + read_value = OAM[oam_index + soam_m_index]; + else + read_value = OAM[oam_index + soam_m_index - 256]; + } + else if (!sprite_eval_write) + { + // if we don't write sprites anymore, just scan through the oam + read_value = soam[0]; + oam_index += 4; + } + else if (sprite_eval_write) + { + //look for sprites + if (spr_true_count == 0 && soam_index < 8) + { + soam[soam_index * 4] = read_value; + } + + if (soam_index < 8) + { + if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) + { + //a flag gets set if sprite zero is in range + if (oam_index == reg_2003) + sprite_zero_in_range = true; + + spr_true_count++; + soam_m_index++; + } + else if (spr_true_count > 0 && spr_true_count < 4) + { + soam[soam_index * 4 + soam_m_index] = read_value; + + soam_m_index++; + + spr_true_count++; + if (spr_true_count == 4) + { + oam_index += 4; + soam_index++; + if (soam_index == 8) + { + // oam_index could be pathologically misaligned at this point, so we have to find the next + // nearest actual sprite to work on >8 sprites per scanline option + oam_index_aux = (oam_index % 4) * 4; + } + + soam_m_index = 0; + spr_true_count = 0; + } + } + else + { + oam_index += 4; + } + } + else if (soam_index >= 8) + { + if (yp >= read_value && yp < read_value + spriteHeight && PPUON) + { + hit_pending = true; + //Reg2002_objoverflow = true; + } + + if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) + { + spr_true_count++; + soam_m_index++; + } + else if (spr_true_count > 0 && spr_true_count < 4) + { + soam_m_index++; + + spr_true_count++; + if (spr_true_count == 4) + { + oam_index += 4; + soam_index++; + soam_m_index = 0; + spr_true_count = 0; + } + } + else + { + oam_index += 4; + if (soam_index == 8) + { + soam_m_index++; // glitchy increment + soam_m_index &= 3; + } + + } + + read_value = soam[0]; //writes change to reads + } + } + } + + ///////////////////////////////////////////// + // Sprite Evaluation End + ///////////////////////////////////////////// + + //process the current clock's worth of bg data fetching + //this needs to be split into 8 pieces or else exact sprite 0 hitting wont work + // due to the cpu not running while the sprite renders below + if (PPUON) { Read_bgdata(xp, ref bgdata[xt + 2]); } + + runppu(); + + if (PPUON && xp == 6) + { + ppu_was_on = true; + } + + if (PPUON && xp == 7) + { + if (!race_2006) + ppur.increment_hsc(); + + if (ppur.status.cycle == 256 && !race_2006) + ppur.increment_vs(); + + ppu_was_on = false; + } + + if (hit_pending) + { + hit_pending = false; + Reg2002_objoverflow = true; + } + + renderbgnow = show_bg_new && (xt > 0 || reg_2001.show_bg_leftmost); + //bg pos is different from raster pos due to its offsetability. + //so adjust for that here + int bgpos = rasterpos + ppur.fh; + int bgpx = bgpos & 7; + int bgtile = bgpos >> 3; + + int pixel = 0, pixelcolor = PALRAM[pixel]; + + //according to qeed's doc, use palette 0 or $2006's value if it is & 0x3Fxx + //at one point I commented this out to fix bottom-left garbage in DW4. but it's needed for full_nes_palette. + //solution is to only run when PPU is actually OFF (left-suppression doesnt count) + if (!PPUON) + { + // if there's anything wrong with how we're doing this, someone please chime in + int addr = ppur.get_2007access(); + if ((addr & 0x3F00) == 0x3F00) + { + pixel = addr & 0x1F; + } + pixelcolor = PALRAM[pixel]; + pixelcolor |= 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later + } + + //generate the BG data + if (renderbgnow) + { + byte pt_0 = bgdata[bgtile].pt_0; + byte pt_1 = bgdata[bgtile].pt_1; + int sel = 7 - bgpx; + pixel = ((pt_0 >> sel) & 1) | (((pt_1 >> sel) & 1) << 1); + if (pixel != 0) + pixel |= bgdata[bgtile].at; + pixelcolor = PALRAM[pixel]; + } + + if (!nes.Settings.DispBackground) + pixelcolor = 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later + + //check if the pixel has a sprite in it + if (sl_sprites[256 + xt * 8 + xp] != 0 && renderspritenow) + { + int s = sl_sprites[xt * 8 + xp]; + int spixel = sl_sprites[256 + xt * 8 + xp]; + int temp_attr = sl_sprites[512 + xt * 8 + xp]; + + //TODO - make sure we dont trigger spritehit if the edges are masked for either BG or OBJ + //spritehit: + //1. is it sprite#0? + //2. is the bg pixel nonzero? + //then, it is spritehit. + Reg2002_objhit |= (sprite_zero_go && s == 0 && pixel != 0 && rasterpos < 255 && show_bg_new && show_obj_new); + + //priority handling, if in front of BG: + bool drawsprite = !(((temp_attr & 0x20) != 0) && ((pixel & 3) != 0)); + if (drawsprite && nes.Settings.DispSprites) + { + //bring in the palette bits and palettize + spixel |= (temp_attr & 3) << 2; + //save it for use in the framebuffer + pixelcolor = PALRAM[0x10 + spixel]; + } + } //oamcount loop + + + pipeline(pixelcolor, xt * 8 + xp); + target++; + + // clear out previous sprites from scanline buffer + //sl_sprites[xt * 8 + xp] = 0; + sl_sprites[256 + xt * 8 + xp] = 0; + //sl_sprites[512 + xt * 8 + xp] = 0; + + // end of visible part of the scanline + sprite_eval_cycle++; + xp++; + rasterpos++; + + if (xp == 8) + { + xp = 0; + xt++; + + xstart = xt << 3; target = yp_shift + xstart; - int rasterpos = xstart; + rasterpos = xstart; spriteHeight = reg_2000.obj_size_16 ? 16 : 8; //check all the conditions that can cause things to render in these 8px - bool renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost); - bool renderbgnow; - bool hit_pending = false; + renderspritenow = show_obj_new && (xt > 0 || reg_2001.show_obj_leftmost); + hit_pending = false; - for (int xp = 0; xp < 8; xp++, rasterpos++) - { - ////////////////////////////////////////////////// - //Sprite Evaluation Start - ////////////////////////////////////////////////// - if (ppur.status.cycle <= 63 && !is_even_cycle) - { - // the first 64 cycles of each scanline are used to initialize sceondary OAM - // the actual effect setting a flag that always returns 0xFF from a OAM read - // this is a bit of a shortcut to save some instructions - // data is read from OAM as normal but never used - soam[soam_index] = 0xFF; - soam_index++; - } - if (ppur.status.cycle == 64) - { - soam_index = 0; - oam_index = 0;// reg_2003; - } - - // otherwise, scan through OAM and test if sprites are in range - // if they are, they get copied to the secondary OAM - if (ppur.status.cycle >= 64) - { - if (oam_index >= 256) - { - oam_index = 0; - sprite_eval_write = false; - } - - if (is_even_cycle && oam_index<256) - { - if ((oam_index + soam_m_index) < 256) - read_value = OAM[oam_index + soam_m_index]; - else - read_value = OAM[oam_index + soam_m_index - 256]; - } - else if (!sprite_eval_write) - { - // if we don't write sprites anymore, just scan through the oam - read_value = soam[0]; - oam_index+=4; - } - else if (sprite_eval_write) - { - //look for sprites - if (spr_true_count==0 && soam_index<8) - { - soam[soam_index*4] = read_value; - } - - if (soam_index < 8) - { - if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) - { - //a flag gets set if sprite zero is in range - if (oam_index == 0)//reg_2003) - sprite_zero_in_range = true; - - spr_true_count++; - soam_m_index++; - } - else if (spr_true_count > 0 && spr_true_count < 4) - { - soam[soam_index * 4 + soam_m_index] = read_value; - - soam_m_index++; - - spr_true_count++; - if (spr_true_count == 4) - { - oam_index+=4; - soam_index++; - if (soam_index == 8) - { - // oam_index could be pathologically misaligned at this point, so we have to find the next - // nearest actual sprite to work on >8 sprites per scanline option - oam_index_aux = (oam_index%4)*4; - } - - soam_m_index = 0; - spr_true_count = 0; - } - } - else - { - oam_index+=4; - } - } - else if (soam_index>=8) - { - if (yp >= read_value && yp < read_value + spriteHeight && PPUON) - { - hit_pending = true; - //Reg2002_objoverflow = true; - } - - if (yp >= read_value && yp < read_value + spriteHeight && spr_true_count == 0) - { - spr_true_count++; - soam_m_index++; - } - else if (spr_true_count > 0 && spr_true_count < 4) - { - soam_m_index++; - - spr_true_count++; - if (spr_true_count == 4) - { - oam_index+=4; - soam_index++; - soam_m_index = 0; - spr_true_count = 0; - } - } - else - { - oam_index+=4; - if (soam_index==8) - { - soam_m_index++; // glitchy increment - soam_m_index &= 3; - } - - } - - read_value = soam[0]; //writes change to reads - } - - } - - } - - ////////////////////////////////////////////////// - //Sprite Evaluation End - ////////////////////////////////////////////////// - - //process the current clock's worth of bg data fetching - //this needs to be split into 8 pieces or else exact sprite 0 hitting wont work due to the cpu not running while the sprite renders below - - - if (PPUON) - Read_bgdata(xp, ref bgdata[xt + 2]); - - runppu(1); - - if (PPUON && xp == 6) - { - ppu_was_on = true; - } - - if (PPUON && xp == 7) - { - if (!race_2006) - ppur.increment_hsc(); - - if (ppur.status.cycle == 256 && !race_2006) - ppur.increment_vs(); - - ppu_was_on = false; - } - - if (hit_pending) - { - hit_pending = false; - Reg2002_objoverflow = true; - } - - renderbgnow = show_bg_new && (xt > 0 || reg_2001.show_bg_leftmost); - //bg pos is different from raster pos due to its offsetability. - //so adjust for that here - int bgpos = rasterpos + ppur.fh; - int bgpx = bgpos & 7; - int bgtile = bgpos >> 3; - - int pixel = 0, pixelcolor = PALRAM[pixel]; - - //according to qeed's doc, use palette 0 or $2006's value if it is & 0x3Fxx - //at one point I commented this out to fix bottom-left garbage in DW4. but it's needed for full_nes_palette. - //solution is to only run when PPU is actually OFF (left-suppression doesnt count) - if (!PPUON) - { - // if there's anything wrong with how we're doing this, someone please chime in - int addr = ppur.get_2007access(); - if ((addr & 0x3F00) == 0x3F00) - { - pixel = addr & 0x1F; - } - pixelcolor = PALRAM[pixel]; - pixelcolor |= 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later - } - - //generate the BG data - if (renderbgnow) - { - byte pt_0 = bgdata[bgtile].pt_0; - byte pt_1 = bgdata[bgtile].pt_1; - int sel = 7 - bgpx; - pixel = ((pt_0 >> sel) & 1) | (((pt_1 >> sel) & 1) << 1); - if (pixel != 0) - pixel |= bgdata[bgtile].at; - pixelcolor = PALRAM[pixel]; - } - - if (!nes.Settings.DispBackground) - pixelcolor = 0x8000; //whats this? i think its a flag to indicate a hidden background to be used by the canvas filling logic later - - //look for a sprite to be drawn - bool havepixel = false; - for (int s = 0; s < soam_index_prev; s++) - { - int x = t_oam[s].oam_x; - if (rasterpos >= x && rasterpos < x + 8) - { - //build the pixel. - //fetch the LSB of the patterns - int spixel = t_oam[s].patterns_0 & 1; - spixel |= (t_oam[s].patterns_1 & 1) << 1; - - //shift down the patterns so the next pixel is in the LSB - t_oam[s].patterns_0 >>= 1; - t_oam[s].patterns_1 >>= 1; - - //bail out if we already have a pixel from a higher priority sprite. - //notice that we continue looping anyway, so that we can shift down the patterns - //transparent pixel bailout - if (!renderspritenow || havepixel || spixel == 0) continue; - - havepixel = true; - - //TODO - make sure we dont trigger spritehit if the edges are masked for either BG or OBJ - //spritehit: - //1. is it sprite#0? - //2. is the bg pixel nonzero? - //then, it is spritehit. - Reg2002_objhit |= (sprite_zero_go && s == 0 && pixel != 0 && rasterpos < 255 && show_bg_new && show_obj_new); - - //priority handling, if in front of BG: - bool drawsprite = !(((t_oam[s].oam_attr & 0x20) != 0) && ((pixel & 3) != 0)); - if (drawsprite && nes.Settings.DispSprites) - { - //bring in the palette bits and palettize - spixel |= (t_oam[s].oam_attr & 3) << 2; - //save it for use in the framebuffer - pixelcolor = PALRAM[0x10 + spixel]; - } - } //rasterpos in sprite range - } //oamcount loop - - pipeline(pixelcolor, target, xt*32+xp); - target++; - } //loop across 8 pixels - } //loop across 32 tiles - } - else - for (int xt = 0; xt < 32; xt++) - Read_bgdata(ref bgdata[xt + 2]); - - // normally only 8 sprites are allowed, but with a particular setting we can have more then that - // this extra bit takes care of it quickly - soam_index_aux = 8; - - if (nes.Settings.AllowMoreThanEightSprites) - { - while (oam_index_aux < 64 && soam_index_aux<64) - { - //look for sprites - soam[soam_index_aux * 4] = OAM[oam_index_aux * 4]; - read_value_aux = OAM[oam_index_aux * 4]; - if (yp >= read_value_aux && yp < read_value_aux + spriteHeight) - { - soam[soam_index_aux * 4 + 1] = OAM[oam_index_aux * 4 + 1]; - soam[soam_index_aux * 4 + 2] = OAM[oam_index_aux * 4 + 2]; - soam[soam_index_aux * 4 + 3] = OAM[oam_index_aux * 4 + 3]; - soam_index_aux++; - oam_index_aux++; - } - else - { - oam_index_aux++; - } } } - - soam_index_prev = soam_index_aux; - - if (soam_index_prev > 8 && !nes.Settings.AllowMoreThanEightSprites) - soam_index_prev = 8; - - ppuphase = PPUPHASE.OBJ; - - spriteHeight = reg_2000.obj_size_16 ? 16 : 8; - - for (int s = 0; s < 8; s++) + else { - bool junksprite = (!PPUON); + // if scanline is the pre-render line, we just read BG data + Read_bgdata(xp, ref bgdata[xt + 2]); + + runppu(); + + if (PPUON && xp == 6) + { + ppu_was_on = true; + } + + if (PPUON && xp == 7) + { + if (!race_2006) + ppur.increment_hsc(); + + if (ppur.status.cycle == 256 && !race_2006) + ppur.increment_vs(); + + ppu_was_on = false; + } + + xp++; + + if (xp == 8) + { + xp = 0; + xt++; + } + } + } + else if (ppur.status.cycle < 320) + { + // after we are done with the visible part of the frame, we reach sprite transfer to temp OAM tables and such + if (ppur.status.cycle == 256) + { + // do the more then 8 sprites stuff here where it is convenient + // normally only 8 sprites are allowed, but with a particular setting we can have more then that + // this extra bit takes care of it quickly + soam_index_aux = 8; + + if (nes.Settings.AllowMoreThanEightSprites) + { + while (oam_index_aux < 64 && soam_index_aux < 64) + { + //look for sprites + soam[soam_index_aux * 4] = OAM[oam_index_aux * 4]; + if (yp >= OAM[oam_index_aux * 4] && yp < OAM[oam_index_aux * 4] + spriteHeight) + { + soam[soam_index_aux * 4 + 1] = OAM[oam_index_aux * 4 + 1]; + soam[soam_index_aux * 4 + 2] = OAM[oam_index_aux * 4 + 2]; + soam[soam_index_aux * 4 + 3] = OAM[oam_index_aux * 4 + 3]; + soam_index_aux++; + oam_index_aux++; + } + else + { + oam_index_aux++; + } + } + } + + soam_index_prev = soam_index_aux; + + if (soam_index_prev > 8 && !nes.Settings.AllowMoreThanEightSprites) + soam_index_prev = 8; + + ppuphase = PPUPHASE.OBJ; + + spriteHeight = reg_2000.obj_size_16 ? 16 : 8; + + s = 0; + ppu_aux_index = 0; + + junksprite = (!PPUON); t_oam[s].oam_y = soam[s * 4]; t_oam[s].oam_ind = soam[s * 4 + 1]; t_oam[s].oam_attr = soam[s * 4 + 2]; t_oam[s].oam_x = soam[s * 4 + 3]; - int line = yp - t_oam[s].oam_y; + line = yp - t_oam[s].oam_y; if ((t_oam[s].oam_attr & 0x80) != 0) //vflip line = spriteHeight - line - 1; - int patternNumber = t_oam[s].oam_ind; - int patternAddress; + patternNumber = t_oam[s].oam_ind; + } - //8x16 sprite handling: - if (reg_2000.obj_size_16) - { - int bank = (patternNumber & 1) << 12; - patternNumber = patternNumber & ~1; - patternNumber |= (line >> 3) & 1; - patternAddress = (patternNumber << 4) | bank; - } - else - patternAddress = (patternNumber << 4) | (reg_2000.obj_pattern_hi << 12); - - //offset into the pattern for the current line. - //tricky: tall sprites have already had lines>8 taken care of by getting a new pattern number above. - //so we just need the line offset for the second pattern - patternAddress += line & 7; - - //garbage nametable fetches + scroll resets - int garbage_todo = 2; - - ppubus_read(ppur.get_ntread(), true, true); - - if (PPUON) - { - if (sl == 0 && ppur.status.cycle == 304) - { - - read_value = t_oam[s].oam_y; - runppu(1); - - if (PPUON) ppur.install_latches(); - - read_value = t_oam[s].oam_ind; - runppu(1); - - - garbage_todo = 0; - } - if ((sl != 0) && ppur.status.cycle == 256) - { - - read_value = t_oam[s].oam_y; - - runppu(1); - - if (target<=61441 && target > 0 && s==0) - { - pipeline(0, target,256); - target++; - } - - //at 257: 3d world runner is ugly if we do this at 256 - if (PPUON) ppur.install_h_latches(); - read_value = t_oam[s].oam_ind; - runppu(1); - - if (target <= 61441 && target > 0 && s==0) - { - pipeline(0, target, 257); // last pipeline call option 1 of 2 - } - garbage_todo = 0; - } - } - - for (int i = 0; i < garbage_todo; i++) - { - if (i==0) - read_value = t_oam[s].oam_y; - else - read_value = t_oam[s].oam_ind; - - runppu(1); - - if (i == 0) - { - if (target <= 61441 && target > 0 && s==0) - { - pipeline(0, target,256); - target++; - } - } - else - { - if (target <= 61441 && target > 0 && s==0) - { - pipeline(0, target, 257); // last pipeline call option 2 of 2 - } - } - } - - ppubus_read(ppur.get_atread(), true, true); //at or nt? - - read_value = t_oam[s].oam_attr; - runppu(1); - - read_value = t_oam[s].oam_x; - runppu(1); - - // if the PPU is off, we don't put anything on the bus - if (junksprite) - { - ppubus_read(patternAddress, true, false); - ppubus_read(patternAddress, true, false); - runppu(kFetchTime * 2); - } - else - { - int addr = patternAddress; - t_oam[s].patterns_0 = ppubus_read(addr, true, true); - read_value = t_oam[s].oam_x; - runppu(kFetchTime); - - addr += 8; - t_oam[s].patterns_1 = ppubus_read(addr, true, true); - read_value = t_oam[s].oam_x; - runppu(kFetchTime); - - // hflip - if ((t_oam[s].oam_attr & 0x40) == 0) - { - t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; - t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; - } - - // if the sprites attribute is 0xFF, then this indicates a non-existent sprite - // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF - // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline - if (t_oam[s].oam_attr==0xFF) - { - t_oam[s].patterns_0 = 0; - t_oam[s].patterns_1 = 0; - } - - } - - } // sprite pattern fetch loop - - //now do the same for extra sprites, but without any cycles run - if (soam_index_aux>8) + switch (ppu_aux_index) { - for (int s = 8; s < soam_index_aux; s++) - { - t_oam[s].oam_y = soam[s * 4]; - t_oam[s].oam_ind = soam[s * 4 + 1]; - t_oam[s].oam_attr = soam[s * 4 + 2]; - t_oam[s].oam_x = soam[s * 4 + 3]; - - int line = yp - t_oam[s].oam_y; - if ((t_oam[s].oam_attr & 0x80) != 0) //vflip - line = spriteHeight - line - 1; - - int patternNumber = t_oam[s].oam_ind; - int patternAddress; - + case 0: //8x16 sprite handling: if (reg_2000.obj_size_16) { @@ -719,75 +606,364 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES //so we just need the line offset for the second pattern patternAddress += line & 7; - ppubus_read(ppur.get_ntread(), true, false); + ppubus_read(ppur.get_ntread(), true, true); - ppubus_read(ppur.get_atread(), true, false); //at or nt? - - int addr = patternAddress; - t_oam[s].patterns_0 = ppubus_read(addr, true, false); - - addr += 8; - t_oam[s].patterns_1 = ppubus_read(addr, true, false); - - // hflip - if ((t_oam[s].oam_attr & 0x40) == 0) + read_value = t_oam[s].oam_y; + runppu(); + break; + case 1: + if (PPUON && ppur.status.sl == 0 && ppur.status.cycle == 305) { - t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; - t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; - } + ppur.install_latches(); - // if the sprites attribute is 0xFF, then this indicates a non-existent sprite - // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF - // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline - if (t_oam[s].oam_attr == 0xFF) + read_value = t_oam[s].oam_ind; + runppu(); + + } + else if (PPUON && (ppur.status.sl != 0) && ppur.status.cycle == 257) { - t_oam[s].patterns_0 = 0; - t_oam[s].patterns_1 = 0; + + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 256); + target++; + } + + //at 257: 3d world runner is ugly if we do this at 256 + if (PPUON) ppur.install_h_latches(); + read_value = t_oam[s].oam_ind; + runppu(); + + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 257); // last pipeline call option 1 of 2 + } } + else + { + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 256); + target++; + } - } // sprite pattern fetch loop + read_value = t_oam[s].oam_ind; + runppu(); + if (target <= 61441 && target > 0 && s == 0) + { + pipeline(0, 257); // last pipeline call option 2 of 2 + } + } + break; + + case 2: + ppubus_read(ppur.get_atread(), true, true); //at or nt? + read_value = t_oam[s].oam_attr; + runppu(); + break; + + case 3: + read_value = t_oam[s].oam_x; + runppu(); + break; + + case 4: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + ppubus_read(patternAddress, true, false); + runppu(); + } + else + { + temp_addr = patternAddress; + t_oam[s].patterns_0 = ppubus_read(temp_addr, true, true); + read_value = t_oam[s].oam_x; + runppu(); + } + break; + case 5: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + runppu(); + } + else + { + runppu(); + } + break; + case 6: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + ppubus_read(patternAddress, true, false); + runppu(); + } + else + { + temp_addr += 8; + t_oam[s].patterns_1 = ppubus_read(temp_addr, true, true); + read_value = t_oam[s].oam_x; + runppu(); + } + break; + case 7: + // if the PPU is off, we don't put anything on the bus + if (junksprite) + { + runppu(); + } + else + { + runppu(); + + // hflip + if ((t_oam[s].oam_attr & 0x40) == 0) + { + t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; + t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; + } + + // if the sprites attribute is 0xFF, then this indicates a non-existent sprite + // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF + // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline + if (t_oam[s].oam_attr == 0xFF) + { + t_oam[s].patterns_0 = 0; + t_oam[s].patterns_1 = 0; + } + + } + break; } - ppuphase = PPUPHASE.BG; - - // fetch BG: two tiles for next line - for (int xt = 0; xt < 2; xt++) + ppu_aux_index++; + if (ppu_aux_index == 8) { - Read_bgdata(ref bgdata[xt]); + // now that we have a sprite, we can fill in the next scnaline's sprite pixels with it + // this saves quite a bit of processing compared to checking each pixel + + if (s < soam_index_prev) + { + int temp_x = t_oam[s].oam_x; + for (int i = 0; (temp_x + i) < 256 && i < 8; i++) + { + if (sl_sprites[256 + temp_x + i] == 0) + { + if (t_oam[s].patterns_0.Bit(i) || t_oam[s].patterns_1.Bit(i)) + { + int spixel = t_oam[s].patterns_0.Bit(i) ? 1 : 0; + spixel |= (t_oam[s].patterns_1.Bit(i) ? 2 : 0); + + sl_sprites[temp_x + i] = (byte)s; + sl_sprites[256 + temp_x + i] = (byte)spixel; + sl_sprites[512 + temp_x + i] = t_oam[s].oam_attr; + } + } + } + } + + ppu_aux_index = 0; + s++; + + if (s < 8) + { + junksprite = (!PPUON); + + t_oam[s].oam_y = soam[s * 4]; + t_oam[s].oam_ind = soam[s * 4 + 1]; + t_oam[s].oam_attr = soam[s * 4 + 2]; + t_oam[s].oam_x = soam[s * 4 + 3]; + + line = yp - t_oam[s].oam_y; + if ((t_oam[s].oam_attr & 0x80) != 0) //vflip + line = spriteHeight - line - 1; + + patternNumber = t_oam[s].oam_ind; + } + else + { + // repeat all the above steps for more then 8 sprites but don't run any cycles + if (soam_index_aux > 8) + { + for (int s = 8; s < soam_index_aux; s++) + { + t_oam[s].oam_y = soam[s * 4]; + t_oam[s].oam_ind = soam[s * 4 + 1]; + t_oam[s].oam_attr = soam[s * 4 + 2]; + t_oam[s].oam_x = soam[s * 4 + 3]; + + int line = yp - t_oam[s].oam_y; + if ((t_oam[s].oam_attr & 0x80) != 0) //vflip + line = spriteHeight - line - 1; + + int patternNumber = t_oam[s].oam_ind; + int patternAddress; + + //8x16 sprite handling: + if (reg_2000.obj_size_16) + { + int bank = (patternNumber & 1) << 12; + patternNumber = patternNumber & ~1; + patternNumber |= (line >> 3) & 1; + patternAddress = (patternNumber << 4) | bank; + } + else + patternAddress = (patternNumber << 4) | (reg_2000.obj_pattern_hi << 12); + + //offset into the pattern for the current line. + //tricky: tall sprites have already had lines>8 taken care of by getting a new pattern number above. + //so we just need the line offset for the second pattern + patternAddress += line & 7; + + ppubus_read(ppur.get_ntread(), true, false); + + ppubus_read(ppur.get_atread(), true, false); //at or nt? + + int addr = patternAddress; + t_oam[s].patterns_0 = ppubus_read(addr, true, false); + + addr += 8; + t_oam[s].patterns_1 = ppubus_read(addr, true, false); + + // hflip + if ((t_oam[s].oam_attr & 0x40) == 0) + { + t_oam[s].patterns_0 = BitReverse.Byte8[t_oam[s].patterns_0]; + t_oam[s].patterns_1 = BitReverse.Byte8[t_oam[s].patterns_1]; + } + + // if the sprites attribute is 0xFF, then this indicates a non-existent sprite + // I think the logic here is that bits 2-4 in OAM are disabled, but soam is initialized with 0xFF + // so the only way a sprite could have an 0xFF attribute is if it is not in the scope of the scanline + if (t_oam[s].oam_attr == 0xFF) + { + t_oam[s].patterns_0 = 0; + t_oam[s].patterns_1 = 0; + } + + int temp_x = t_oam[s].oam_x; + for (int i = 0; (temp_x + i) < 256 && i < 8; i++) + { + if (sl_sprites[256 + temp_x + i] == 0) + { + if (t_oam[s].patterns_0.Bit(i) || t_oam[s].patterns_1.Bit(i)) + { + int spixel = t_oam[s].patterns_0.Bit(i) ? 1 : 0; + spixel |= (t_oam[s].patterns_1.Bit(i) ? 2 : 0); + + sl_sprites[temp_x + i] = (byte)s; + sl_sprites[256 + temp_x + i] = (byte)spixel; + sl_sprites[512 + temp_x + i] = t_oam[s].oam_attr; + } + } + } + } + } + } + } + } + else + { + if (ppur.status.cycle == 320) + { + ppuphase = PPUPHASE.BG; + xt = 0; + xp = 0; } - // this sequence is tuned to pass 10-even_odd_timing.nes - runppu(4); - bool evenOddDestiny = PPUON; + if (ppur.status.cycle < 336) + { + // if scanline is the pre-render line, we just read BG data + Read_bgdata(xp, ref bgdata[xt]); - // After memory access 170, the PPU simply rests for 4 cycles (or the - // equivelant of half a memory access cycle) before repeating the whole - // pixel/scanline rendering process. If the scanline being rendered is the very - // first one on every second frame, then this delay simply doesn't exist. - if (sl == 0 && idleSynch && evenOddDestiny && chopdot) - { } + runppu(); + + if (PPUON && xp == 6) + { + ppu_was_on = true; + } + + if (PPUON && xp == 7) + { + if (!race_2006) + ppur.increment_hsc(); + + if (ppur.status.cycle == 256 && !race_2006) + ppur.increment_vs(); + + ppu_was_on = false; + } + + xp++; + + if (xp == 8) + { + xp = 0; + xt++; + } + } + else if (ppur.status.cycle < 340) + { + runppu(); + } else - runppu(1); + { + bool evenOddDestiny = PPUON; - } // scanline loop + // After memory access 170, the PPU simply rests for 4 cycles (or the + // equivelant of half a memory access cycle) before repeating the whole + // pixel/scanline rendering process. If the scanline being rendered is the very + // first one on every second frame, then this delay simply doesn't exist. + if (ppur.status.sl == 0 && idleSynch && evenOddDestiny && chopdot) + { ppur.status.cycle++; } // increment cycle without running ppu + else + { runppu(); } + } + } - ppur.status.sl = 241; + if (ppur.status.cycle == 341) + { + ppur.status.cycle = 0; + ppur.status.sl++; - //idle for pre NMI lines - runppu(preNMIlines * kLineTime); - } //FrameAdvance + if (ppur.status.sl == 241) + { + do_active_sl = false; + } + } + } - void FrameAdvance_ppudead() + public void TickPPU_preVBL() { - //not quite emulating all the NES power up behavior - //since it is known that the NES ignores writes to some - //register before around a full frame, but no games - //should write to those regs during that time, it needs - //to wait for vblank + runppu(); - runppu(241 * kLineTime-3);// -8*3); - ppudead--; + if (ppur.status.cycle == 341) + { + ppur.status.cycle = 0; + ppur.status.sl++; + if (ppur.status.sl == 241 + preNMIlines) + { + do_pre_vbl = false; + } + } + } + + //not quite emulating all the NES power up behavior + //since it is known that the NES ignores writes to some + //register before around a full frame, but no games + //should write to those regs during that time, it needs + //to wait for vblank + public void NewDeadPPU() + { + runppu(); + + if (ppur.status.cycle == 241 * 341 - 3) + { + ppudead--; + } } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IStatable.cs index 2f834515b9..b2f38791ad 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.IStatable.cs @@ -15,8 +15,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES CheckDisposed(); var temp = SaveStateBinary(); temp.SaveAsHexFast(writer); - // write extra copy of stuff we don't use - writer.WriteLine("Frame {0}", Frame); } public void LoadStateText(System.IO.TextReader reader) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs index ebb2853714..874a443f03 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.IMemoryDomains.cs @@ -71,8 +71,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES MakeMemoryDomain("SGB HRAM", LibsnesApi.SNES_MEMORY.SGB_HRAM, MemoryDomain.Endian.Little); MakeMemoryDomain("SGB CARTRAM", LibsnesApi.SNES_MEMORY.SGB_CARTRAM, MemoryDomain.Endian.Little); - - MakeMemoryDomain("WRAM", LibsnesApi.SNES_MEMORY.WRAM, MemoryDomain.Endian.Little); } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt index 128e46f9f8..122814b815 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/Compat.txt @@ -9,10 +9,6 @@ Korean games currently not booting: * Desert Strike - you can enter the map screen but cannot leave. -- Light Gun emulation -- Paddle emulation -- Sports pad emulation? - ======= Game Gear compatibility issues ======= * Outrun has raster effect on the wrong line. I've been able to modify interrupt code to diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs new file mode 100644 index 0000000000..ec0acddec1 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/EEPROM.93c46.cs @@ -0,0 +1,233 @@ +using System; +using BizHawk.Common; + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + class EEPROM93c46 + { + enum EEPROMWriteMode + { + Instruction, + WriteData, + WriteAll, + Read + } + + enum EEPROMReadMode + { + ReadNew, + ReadOld, + Hold + } + + [Flags] + enum EEPROMFlags : byte + { + Ready = 1, + Clock = 2, + ChipSelect = 4 + } + + ushort Address = 0; + ushort Value = 0; + int BitsWritten = 0; + int BitsRead = 0; + bool WriteEnable = false; + EEPROMWriteMode WriteMode = EEPROMWriteMode.Instruction; + EEPROMReadMode ReadMode = EEPROMReadMode.Hold; + EEPROMFlags Flags = 0; + + public byte Read(byte[] saveRAM) + { + switch (ReadMode) + { + case EEPROMReadMode.ReadNew: + // A new value clocking out + + ReadMode = EEPROMReadMode.ReadOld; + byte ret = Read(saveRAM); + + if (++BitsRead == 8) + { + // Increment address + BitsRead = 0; + ++Address; + + if(Address % 2 == 0) + { + WriteMode = EEPROMWriteMode.Instruction; + ReadMode = EEPROMReadMode.Hold; + BitsWritten = 0; + Value = 0; + } + } + + return ret; + case EEPROMReadMode.ReadOld: + // repeat old value + + byte bit = (byte)((saveRAM[Address % saveRAM.Length] >> (7 - BitsRead)) & 1); + + return (byte)((byte)(Flags | EEPROMFlags.Clock) | bit); + default: + // ready/busy flag is always ready in this emulation + return (byte)(Flags | EEPROMFlags.Clock | EEPROMFlags.Ready); + } + } + + public void Write(byte bit, byte[] saveRAM) + { + // new instruction? + if ((bit & 4) == 0) + { + WriteMode = EEPROMWriteMode.Instruction; + ReadMode = EEPROMReadMode.Hold; + BitsWritten = 0; + Value = 0; + + Flags = (EEPROMFlags)bit & ~EEPROMFlags.Ready; + return; + } + + // clock low to high? + if ((bit & (byte)EEPROMFlags.Clock) != 0 && (Flags & EEPROMFlags.Clock) == 0) + { + // all modes shift in a larger value + Value = (ushort)((Value << 1) | (bit & 1)); + ++BitsWritten; + + switch (WriteMode) + { + case EEPROMWriteMode.Instruction: + // Process opcode including start bit + + // check start bit + if ((Value & 0x100) == 0) + return; + + byte op = (byte)Value; + Value = 0; + BitsWritten = 0; + + switch (op & 0xC0) + { + case 0x00: + // non-addressed commands + switch (op & 0xF0) + { + case 0x00: + // EWDS: write disable + WriteEnable = false; + return; + case 0x10: + // WRAL: write to all addresses (silly) + WriteMode = EEPROMWriteMode.WriteAll; + ReadMode = EEPROMReadMode.Hold; + return; + case 0x20: + // ERAL: erase all addresses + if (WriteEnable) + { + for (int i = 0; i < saveRAM.Length; ++i) + { + saveRAM[i] = 0xFF; + } + } + ReadMode = EEPROMReadMode.Hold; + return; + case 0x30: + // EWEN: write enable + WriteEnable = true; + return; + default: + // impossible + return; + } + case 0x40: + // WRITE + Address = (ushort)((op & 0x3F) << 1); + WriteMode = EEPROMWriteMode.WriteData; + ReadMode = EEPROMReadMode.Hold; + return; + case 0x80: + // READ + Address = (ushort)((op & 0x3F) << 1); + ReadMode = EEPROMReadMode.Hold; + WriteMode = EEPROMWriteMode.Read; + BitsRead = 0; + return; + case 0xC0: + // ERASE + Address = (ushort)((op & 0x3F) << 1); + if (WriteEnable) + { + saveRAM[Address % saveRAM.Length] = 0xFF; + saveRAM[(Address + 1) % saveRAM.Length] = 0xFF; + } + ReadMode = EEPROMReadMode.Hold; + return; + default: + // impossible + return; + } + case EEPROMWriteMode.WriteData: + // Write bits + + if (BitsWritten < 16) + return; + + if (WriteEnable) + { + saveRAM[Address % saveRAM.Length] = (byte)(Value >> 8); + saveRAM[(Address + 1) % saveRAM.Length] = (byte)Value; + } + WriteMode = EEPROMWriteMode.Instruction; + + Value = 0; + BitsWritten = 0; + return; + case EEPROMWriteMode.WriteAll: + // write to ALL addresses + + if (BitsWritten < 16) + return; + + Value = 0; + BitsWritten = 0; + + if (WriteEnable) + { + for (int i = 0; i < saveRAM.Length; i += 2) + { + saveRAM[i % saveRAM.Length] = (byte)Value; + saveRAM[(i + 1) % saveRAM.Length] = (byte)(Value >> 8); + } + } + WriteMode = EEPROMWriteMode.Instruction; + return; + case EEPROMWriteMode.Read: + // Clock a new value out + ReadMode = EEPROMReadMode.ReadNew; + + return; + } + } + + Flags = (EEPROMFlags)bit & ~EEPROMFlags.Ready; + } + + public void SyncState(Serializer ser) + { + ser.BeginSection("93c46"); + ser.Sync("Address", ref Address); + ser.Sync("Value", ref Value); + ser.Sync("BitsWritten", ref BitsWritten); + ser.Sync("BitsRead", ref BitsRead); + ser.Sync("WriteEnable", ref WriteEnable); + ser.SyncEnum("WriteMode", ref WriteMode); + ser.SyncEnum("ReadMode", ref ReadMode); + ser.SyncEnum("Flags", ref Flags); + ser.EndSection(); + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.EEPROM.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.EEPROM.cs new file mode 100644 index 0000000000..2e5c544c11 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/MemoryMap.EEPROM.cs @@ -0,0 +1,136 @@ +using System; + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + public partial class SMS + { + // The 93c46-connected mapper is assumed to be equivalent to the Sega mapper except for $8000-.. + // The Sega memory mapper layout looks like so: + // $0000-$03FF - ROM (unpaged) + // $0400-$3FFF - ROM mapper slot 0 + // $4000-$7FFF - ROM mapper slot 1 + // $8000-$BFFF - ROM mapper slot 2 - OR - EEPROM + // $C000-$DFFF - System RAM + // $E000-$FFFF - System RAM (mirror) + // $FFFC - SaveRAM mapper control + // $FFFD - Mapper slot 0 control + // $FFFE - Mapper slot 1 control + // $FFFF - Mapper slot 2 control + + EEPROM93c46 EEPROM; + + byte ReadMemoryEEPROM(ushort address) + { + byte ret = 0xFF; + + if (address < 0xC000) + { + if ((Port3E & 0x48) == 0x48) // cart and bios disabled, return empty bus + ret = 0xFF; + else if (BiosMapped && BiosRom != null) + ret = BiosRom[address & 0x1FFF]; + else if (address < 1024) + ret = RomData[address]; + else if (address < 0x4000) + ret = RomData[(RomBank0 * BankSize) + address]; + else if (address < 0x8000) + ret = RomData[(RomBank1 * BankSize) + (address & BankSizeMask)]; + else + { + switch (SaveRamBank) + { + case 0: ret = RomData[(RomBank2 * BankSize) + (address & BankSizeMask)]; break; + case 1: if (SaveRAM != null && EEPROM != null) ret = EEPROM.Read(SaveRAM); break; + default: + ret = SystemRam[address & RamSizeMask]; + break; + } + } + } + else + { + ret = SystemRam[address & RamSizeMask]; + } + + return ret; + } + + CDLog_MapResults MapMemoryEEPROM(ushort address, bool write) + { + if (address < 0xC000) + { + if ((Port3E & 0x48) == 0x48) // cart and bios disabled, return empty bus + return new CDLog_MapResults(); + else if (BiosMapped && BiosRom != null) + return new CDLog_MapResults(); //bios tracking of CDL is not supported + else if (address < 1024) + return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = address }; + else if (address < 0x4000) + return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = (RomBank0 * BankSize) + address }; + else if (address < 0x8000) + return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = (RomBank1 * BankSize) + (address & BankSizeMask) }; + else + { + switch (SaveRamBank) + { + case 0: return new CDLog_MapResults() { Type = CDLog_AddrType.ROM, Address = (RomBank2 * BankSize) + (address & BankSizeMask) }; + case 1: return new CDLog_MapResults(); // a serial IO port + case 2: return new CDLog_MapResults(); // a serial IO port + default: + return new CDLog_MapResults() { Type = CDLog_AddrType.MainRAM, Address = address & RamSizeMask }; + } + } + } + else + { + return new CDLog_MapResults() { Type = CDLog_AddrType.MainRAM, Address = address & RamSizeMask }; + } + } + + void WriteMemoryEEPROM(ushort address, byte value) + { + if (address >= 0xC000) + SystemRam[address & RamSizeMask] = value; + + else if (address >= 0x8000) + { + if (SaveRAM != null) + { + SaveRamModified = true; + EEPROM.Write(value, SaveRAM); + return; + } + else System.Console.WriteLine("Game attempt to use SRAM but SRAM not present"); + } + + if (address >= 0xFFFC) + { + if (address == 0xFFFC) + { + if ((value & 8) != 0) + SaveRamBank = (byte)((value & 4) == 0 ? 1 : 2); // SaveRAM selected + else + SaveRamBank = 0; // ROM bank selected + + } + else if (address == 0xFFFD) RomBank0 = (byte)(value % RomBanks); + else if (address == 0xFFFE) RomBank1 = (byte)(value % RomBanks); + else if (address == 0xFFFF) RomBank2 = (byte)(value % RomBanks); + return; + } + } + + void InitEEPROMMapper() + { + ReadMemory = ReadMemoryEEPROM; + WriteMemory = WriteMemoryEEPROM; + MapMemory = MapMemoryEEPROM; + WriteMemoryEEPROM(0xFFFC, 0); + WriteMemoryEEPROM(0xFFFD, 0); + WriteMemoryEEPROM(0xFFFE, 1); + WriteMemoryEEPROM(0xFFFF, 2); + + EEPROM = new EEPROM93c46(); + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs index 3c5d438faf..888b0a3a2a 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ICodeDataLogger.cs @@ -94,9 +94,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem /// /// A wrapper for FetchMemory which inserts CDL logic /// - private byte FetchMemory_CDL(ushort address, bool first) + private byte FetchMemory_CDL(ushort address) { - RunCDL(address, first ? CDLog_Flags.ExecFirst : CDLog_Flags.ExecOperand); + RunCDL(address, CDLog_Flags.ExecFirst); return ReadMemory(address); } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs index 973f3e78b7..009cd5fd4c 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IDebuggable.cs @@ -12,36 +12,36 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { return new Dictionary { - ["A"] = Cpu.RegisterA, - ["AF"] = Cpu.RegisterAF, - ["B"] = Cpu.RegisterB, - ["BC"] = Cpu.RegisterBC, - ["C"] = Cpu.RegisterC, - ["D"] = Cpu.RegisterD, - ["DE"] = Cpu.RegisterDE, - ["E"] = Cpu.RegisterE, - ["F"] = Cpu.RegisterF, - ["H"] = Cpu.RegisterH, - ["HL"] = Cpu.RegisterHL, - ["I"] = Cpu.RegisterI, - ["IX"] = Cpu.RegisterIX, - ["IY"] = Cpu.RegisterIY, - ["L"] = Cpu.RegisterL, - ["PC"] = Cpu.RegisterPC, - ["R"] = Cpu.RegisterR, - ["Shadow AF"] = Cpu.RegisterShadowAF, - ["Shadow BC"] = Cpu.RegisterShadowBC, - ["Shadow DE"] = Cpu.RegisterShadowDE, - ["Shadow HL"] = Cpu.RegisterShadowHL, - ["SP"] = Cpu.RegisterSP, - ["Flag C"] = Cpu.RegisterF.Bit(0), - ["Flag N"] = Cpu.RegisterF.Bit(1), - ["Flag P/V"] = Cpu.RegisterF.Bit(2), - ["Flag 3rd"] = Cpu.RegisterF.Bit(3), - ["Flag H"] = Cpu.RegisterF.Bit(4), - ["Flag 5th"] = Cpu.RegisterF.Bit(5), - ["Flag Z"] = Cpu.RegisterF.Bit(6), - ["Flag S"] = Cpu.RegisterF.Bit(7) + ["A"] = Cpu.Regs[Cpu.A], + ["AF"] = Cpu.Regs[Cpu.F] + (Cpu.Regs[Cpu.A] << 8), + ["B"] = Cpu.Regs[Cpu.B], + ["BC"] = Cpu.Regs[Cpu.C] + (Cpu.Regs[Cpu.B] << 8), + ["C"] = Cpu.Regs[Cpu.C], + ["D"] = Cpu.Regs[Cpu.D], + ["DE"] = Cpu.Regs[Cpu.E] + (Cpu.Regs[Cpu.D] << 8), + ["E"] = Cpu.Regs[Cpu.E], + ["F"] = Cpu.Regs[Cpu.F], + ["H"] = Cpu.Regs[Cpu.H], + ["HL"] = Cpu.Regs[Cpu.L] + (Cpu.Regs[Cpu.H] << 8), + ["I"] = Cpu.Regs[Cpu.I], + ["IX"] = Cpu.Regs[Cpu.Ixl] + (Cpu.Regs[Cpu.Ixh] << 8), + ["IY"] = Cpu.Regs[Cpu.Iyl] + (Cpu.Regs[Cpu.Iyh] << 8), + ["L"] = Cpu.Regs[Cpu.L], + ["PC"] = Cpu.Regs[Cpu.PCl] + (Cpu.Regs[Cpu.PCh] << 8), + ["R"] = Cpu.Regs[Cpu.R], + ["Shadow AF"] = Cpu.Regs[Cpu.F_s] + (Cpu.Regs[Cpu.A_s] << 8), + ["Shadow BC"] = Cpu.Regs[Cpu.C_s] + (Cpu.Regs[Cpu.B_s] << 8), + ["Shadow DE"] = Cpu.Regs[Cpu.E_s] + (Cpu.Regs[Cpu.D_s] << 8), + ["Shadow HL"] = Cpu.Regs[Cpu.L_s] + (Cpu.Regs[Cpu.H_s] << 8), + ["SP"] = Cpu.Regs[Cpu.Iyl] + (Cpu.Regs[Cpu.Iyh] << 8), + ["Flag C"] = Cpu.FlagC, + ["Flag N"] = Cpu.FlagN, + ["Flag P/V"] = Cpu.FlagP, + ["Flag 3rd"] = Cpu.Flag3, + ["Flag H"] = Cpu.FlagH, + ["Flag 5th"] = Cpu.Flag5, + ["Flag Z"] = Cpu.FlagZ, + ["Flag S"] = Cpu.FlagS }; } @@ -52,70 +52,82 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem default: throw new InvalidOperationException(); case "A": - Cpu.RegisterA = (byte)value; + Cpu.Regs[Cpu.A] = (ushort)value; break; case "AF": - Cpu.RegisterAF = (byte)value; + Cpu.Regs[Cpu.F] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.A] = (ushort)(value & 0xFF00); break; case "B": - Cpu.RegisterB = (byte)value; + Cpu.Regs[Cpu.B] = (ushort)value; break; case "BC": - Cpu.RegisterBC = (byte)value; + Cpu.Regs[Cpu.C] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.B] = (ushort)(value & 0xFF00); break; case "C": - Cpu.RegisterC = (byte)value; + Cpu.Regs[Cpu.C] = (ushort)value; break; case "D": - Cpu.RegisterD = (byte)value; + Cpu.Regs[Cpu.D] = (ushort)value; break; case "DE": - Cpu.RegisterDE = (byte)value; + Cpu.Regs[Cpu.E] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.D] = (ushort)(value & 0xFF00); break; case "E": - Cpu.RegisterE = (byte)value; + Cpu.Regs[Cpu.E] = (ushort)value; break; case "F": - Cpu.RegisterF = (byte)value; + Cpu.Regs[Cpu.F] = (ushort)value; break; case "H": - Cpu.RegisterH = (byte)value; + Cpu.Regs[Cpu.H] = (ushort)value; break; case "HL": - Cpu.RegisterHL = (byte)value; + Cpu.Regs[Cpu.L] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.H] = (ushort)(value & 0xFF00); break; case "I": - Cpu.RegisterI = (byte)value; + Cpu.Regs[Cpu.I] = (ushort)value; break; case "IX": - Cpu.RegisterIX = (byte)value; + Cpu.Regs[Cpu.Ixl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.Ixh] = (ushort)(value & 0xFF00); break; case "IY": - Cpu.RegisterIY = (byte)value; + Cpu.Regs[Cpu.Iyl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.Iyh] = (ushort)(value & 0xFF00); break; case "L": - Cpu.RegisterL = (byte)value; + Cpu.Regs[Cpu.L] = (ushort)value; break; case "PC": - Cpu.RegisterPC = (ushort)value; + Cpu.Regs[Cpu.PCl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.PCh] = (ushort)(value & 0xFF00); break; case "R": - Cpu.RegisterR = (byte)value; + Cpu.Regs[Cpu.R] = (ushort)value; break; case "Shadow AF": - Cpu.RegisterShadowAF = (byte)value; + Cpu.Regs[Cpu.F_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.A_s] = (ushort)(value & 0xFF00); break; case "Shadow BC": - Cpu.RegisterShadowBC = (byte)value; + Cpu.Regs[Cpu.C_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.B_s] = (ushort)(value & 0xFF00); break; case "Shadow DE": - Cpu.RegisterShadowDE = (byte)value; + Cpu.Regs[Cpu.E_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.D_s] = (ushort)(value & 0xFF00); break; case "Shadow HL": - Cpu.RegisterShadowHL = (byte)value; + Cpu.Regs[Cpu.L_s] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.H_s] = (ushort)(value & 0xFF00); break; case "SP": - Cpu.RegisterSP = (byte)value; + Cpu.Regs[Cpu.SPl] = (ushort)(value & 0xFF); + Cpu.Regs[Cpu.SPh] = (ushort)(value & 0xFF00); break; } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs index ae2dd35788..e49a75ddad 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IEmulator.cs @@ -1,84 +1,101 @@ -using BizHawk.Emulation.Common; - -namespace BizHawk.Emulation.Cores.Sega.MasterSystem -{ - public sealed partial class SMS : IEmulator - { - public IEmulatorServiceProvider ServiceProvider { get; } - - public ControllerDefinition ControllerDefinition - { - get - { - if (IsGameGear) - { - return GGController; - } - - return SmsController; - } - } - - public void FrameAdvance(IController controller, bool render, bool rendersound) - { - _controller = controller; - _lagged = true; - _frame++; - PSG.BeginFrame(Cpu.TotalExecutedCycles); - Cpu.Debug = Tracer.Enabled; - if (!IsGameGear) - { - PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF; - } - - if (Cpu.Debug && Cpu.Logger == null) // TODO, lets not do this on each frame. But lets refactor CoreComm/CoreComm first - { - Cpu.Logger = s => Tracer.Put(s); - } - - if (IsGameGear == false) - { - Cpu.NonMaskableInterrupt = controller.IsPressed("Pause"); - } - - if (IsGame3D && Settings.Fix3D) - { - Vdp.ExecFrame((Frame & 1) == 0); - } - else - { - Vdp.ExecFrame(render); - } - - PSG.EndFrame(Cpu.TotalExecutedCycles); - if (_lagged) - { - _lagCount++; - _isLag = true; - } - else - { - _isLag = false; - } - } - - public int Frame => _frame; - - public string SystemId => "SMS"; - - public bool DeterministicEmulation => true; - - public void ResetCounters() - { - _frame = 0; - _lagCount = 0; - _isLag = false; - } - - public CoreComm CoreComm { get; } - - public void Dispose() - { - } - } -} +using BizHawk.Emulation.Common; + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + public sealed partial class SMS : IEmulator + { + public IEmulatorServiceProvider ServiceProvider { get; } + + public ControllerDefinition ControllerDefinition + { + get + { + if (IsGameGear) + { + return GGController; + } + + switch(SyncSettings.ControllerType) + { + case "Paddle": + return SMSPaddleController; + case "Light Phaser": + // scale the vertical to the display mode + SMSLightPhaserController.FloatRanges[1] = new ControllerDefinition.FloatRange(0, Vdp.FrameHeight / 2, Vdp.FrameHeight - 1); + + return SMSLightPhaserController; + case "Sports Pad": + return SMSSportsPadController; + default: + return SmsController; + } + } + } + + public void FrameAdvance(IController controller, bool render, bool rendersound) + { + _controller = controller; + _lagged = true; + _frame++; + PSG.BeginFrame(Cpu.TotalExecutedCycles); + + if (!IsGameGear) + { + PSG.StereoPanning = Settings.ForceStereoSeparation ? ForceStereoByte : (byte)0xFF; + } + + if (Tracer.Enabled) + { + Cpu.TraceCallback = s => Tracer.Put(s); + } + else + { + Cpu.TraceCallback = null; + } + + if (IsGameGear == false) + { + Cpu.NonMaskableInterrupt = controller.IsPressed("Pause"); + } + + if (IsGame3D && Settings.Fix3D) + { + Vdp.ExecFrame((Frame & 1) == 0); + } + else + { + Vdp.ExecFrame(render); + } + + PSG.EndFrame(Cpu.TotalExecutedCycles); + if (_lagged) + { + _lagCount++; + _isLag = true; + } + else + { + _isLag = false; + } + } + + public int Frame => _frame; + + public string SystemId => "SMS"; + + public bool DeterministicEmulation => true; + + public void ResetCounters() + { + _frame = 0; + _lagCount = 0; + _isLag = false; + } + + public CoreComm CoreComm { get; } + + public void Dispose() + { + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs index 90331a7528..d2112e2dab 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISettable.cs @@ -65,6 +65,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public bool UseBIOS = true; public string ConsoleRegion = "Export"; public string DisplayType = "NTSC"; + public string ControllerType = "Standard"; public SMSSyncSettings Clone() { @@ -78,7 +79,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem x.AllowOverlock != y.AllowOverlock || x.UseBIOS != y.UseBIOS || x.ConsoleRegion != y.ConsoleRegion || - x.DisplayType != y.DisplayType; + x.DisplayType != y.DisplayType || + x.ControllerType != y.ControllerType; } } } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs index 961daa444b..87564dfe64 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.IStatable.cs @@ -1,103 +1,105 @@ -using System.IO; - -using BizHawk.Common; -using BizHawk.Emulation.Common; - - -namespace BizHawk.Emulation.Cores.Sega.MasterSystem -{ - public sealed partial class SMS : IStatable - { - public bool BinarySaveStatesPreferred - { - get { return false; } - } - - public void SaveStateBinary(BinaryWriter bw) - { - SyncState(Serializer.CreateBinaryWriter(bw)); - } - - public void LoadStateBinary(BinaryReader br) - { - SyncState(Serializer.CreateBinaryReader(br)); - } - - public void SaveStateText(TextWriter tw) - { - SyncState(Serializer.CreateTextWriter(tw)); - } - - public void LoadStateText(TextReader tr) - { - SyncState(Serializer.CreateTextReader(tr)); - } - - public byte[] SaveStateBinary() - { - if (_stateBuffer == null) - { - var stream = new MemoryStream(); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - _stateBuffer = stream.ToArray(); - writer.Close(); - return _stateBuffer; - } - else - { - var stream = new MemoryStream(_stateBuffer); - var writer = new BinaryWriter(stream); - SaveStateBinary(writer); - writer.Close(); - return _stateBuffer; - } - } - - private byte[] _stateBuffer; - - private void SyncState(Serializer ser) - { - ser.BeginSection("SMS"); - Cpu.SyncState(ser); - Vdp.SyncState(ser); - PSG.SyncState(ser); - ser.Sync("RAM", ref SystemRam, false); - ser.Sync("RomBank0", ref RomBank0); - ser.Sync("RomBank1", ref RomBank1); - ser.Sync("RomBank2", ref RomBank2); - ser.Sync("RomBank3", ref RomBank3); - ser.Sync("Port01", ref Port01); - ser.Sync("Port02", ref Port02); - ser.Sync("Port3E", ref Port3E); - ser.Sync("Port3F", ref Port3F); - - if (SaveRAM != null) - { - ser.Sync("SaveRAM", ref SaveRAM, false); - ser.Sync("SaveRamBank", ref SaveRamBank); - } - - if (ExtRam != null) - { - ser.Sync("ExtRAM", ref ExtRam, true); - } - - if (HasYM2413) - { - YM2413.SyncState(ser); - } - - ser.Sync("Frame", ref _frame); - ser.Sync("LagCount", ref _lagCount); - ser.Sync("IsLag", ref _isLag); - - ser.EndSection(); - - if (ser.IsReader) - { - SyncAllByteArrayDomains(); - } - } - } -} +using System.IO; + +using BizHawk.Common; +using BizHawk.Emulation.Common; + + +namespace BizHawk.Emulation.Cores.Sega.MasterSystem +{ + public sealed partial class SMS : IStatable + { + public bool BinarySaveStatesPreferred + { + get { return 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(); + } + Cpu.SyncState(ser); + + ser.BeginSection("SMS"); + Vdp.SyncState(ser); + PSG.SyncState(ser); + ser.Sync("RAM", ref SystemRam, false); + ser.Sync("RomBank0", ref RomBank0); + ser.Sync("RomBank1", ref RomBank1); + ser.Sync("RomBank2", ref RomBank2); + ser.Sync("RomBank3", ref RomBank3); + ser.Sync("Port01", ref Port01); + ser.Sync("Port02", ref Port02); + ser.Sync("Port3E", ref Port3E); + ser.Sync("Port3F", ref Port3F); + ser.Sync("Controller1SelectHigh", ref Controller1SelectHigh); + ser.Sync("ControllerSelect2High", ref Controller2SelectHigh); + ser.Sync("LatchLightPhaser", ref LatchLightPhaser); + + if (SaveRAM != null) + { + ser.Sync("SaveRAM", ref SaveRAM, false); + ser.Sync("SaveRamBank", ref SaveRamBank); + } + + if (ExtRam != null) + { + ser.Sync("ExtRAM", ref ExtRam, true); + } + + if (HasYM2413) + { + YM2413.SyncState(ser); + } + + if (EEPROM != null) + { + EEPROM.SyncState(ser); + } + + ser.Sync("Frame", ref _frame); + ser.Sync("LagCount", ref _lagCount); + ser.Sync("IsLag", ref _isLag); + + ser.EndSection(); + + if (ser.IsReader) + { + SyncAllByteArrayDomains(); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs index 06fa88e9ea..c76dab5789 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.Input.cs @@ -1,19 +1,21 @@ -using BizHawk.Emulation.Common; +using System; + +using BizHawk.Emulation.Common; namespace BizHawk.Emulation.Cores.Sega.MasterSystem { public partial class SMS { public static readonly ControllerDefinition SmsController = new ControllerDefinition - { - Name = "SMS Controller", - BoolButtons = + { + Name = "SMS Controller", + BoolButtons = { "Reset", "Pause", "P1 Up", "P1 Down", "P1 Left", "P1 Right", "P1 B1", "P1 B2", "P2 Up", "P2 Down", "P2 Left", "P2 Right", "P2 B1", "P2 B2" } - }; + }; public static readonly ControllerDefinition GGController = new ControllerDefinition { @@ -25,21 +27,316 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } }; + public static readonly ControllerDefinition SMSPaddleController = new ControllerDefinition + { + Name = "SMS Paddle Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Left", "P1 Right", "P1 B1", + "P2 Left", "P2 Right", "P2 B1", + }, + FloatControls = + { + "P1 Paddle", + "P2 Paddle" + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(0, 128, 255), + new ControllerDefinition.FloatRange(0, 128, 255) + } + }; + + public static readonly ControllerDefinition SMSLightPhaserController = new ControllerDefinition + { + Name = "SMS Light Phaser Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Trigger", + }, + FloatControls = + { + "P1 X", "P1 Y", + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(0, 64, 127), + new ControllerDefinition.FloatRange(0, 500, 1000) + } + }; + + public static readonly ControllerDefinition SMSSportsPadController = new ControllerDefinition + { + Name = "SMS Sports Pad Controller", + BoolButtons = + { + "Reset", "Pause", + "P1 Left", "P1 Right", "P1 Up", "P1 Down", "P1 B1", "P1 B2", + "P2 Left", "P2 Right", "P2 Up", "P2 Down", "P2 B1", "P2 B2" + }, + FloatControls = + { + "P1 X", "P1 Y", + "P2 X", "P2 Y" + }, + FloatRanges = + { + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63), + new ControllerDefinition.FloatRange(-64, 0, 63) + } + }; + + const int PaddleMin = 0; + const int PaddleMax = 255; + const int SportsPadMin = -64; + const int SportsPadMax = 63; + + // The paddles and sports pads have data select states + bool Controller1SelectHigh = true; + bool Controller2SelectHigh = true; + + bool LatchLightPhaser = false; + + // further state value for sports pad, may be useful for other controllers in future + int Controller1State = 3; + int Controller2State = 3; + int ControllerTick = 0; // for timing in japan + private byte ReadControls1() { InputCallbacks.Call(); _lagged = false; byte value = 0xFF; - if (_controller.IsPressed("P1 Up")) value &= 0xFE; - if (_controller.IsPressed("P1 Down")) value &= 0xFD; - if (_controller.IsPressed("P1 Left")) value &= 0xFB; - if (_controller.IsPressed("P1 Right")) value &= 0xF7; - if (_controller.IsPressed("P1 B1")) value &= 0xEF; - if (_controller.IsPressed("P1 B2")) value &= 0xDF; + switch (SyncSettings.ControllerType) + { + case "Paddle": + { + // use analog values from a controller, see http://www.smspower.org/Development/Paddle - if (_controller.IsPressed("P2 Up")) value &= 0xBF; - if (_controller.IsPressed("P2 Down")) value &= 0x7F; + int paddle1Pos; + if (_controller.IsPressed("P1 Left")) + paddle1Pos = PaddleMin; + else if (_controller.IsPressed("P1 Right")) + paddle1Pos = PaddleMax; + else + paddle1Pos = (int)_controller.GetFloat("P1 Paddle"); + + int paddle2Pos; + if (_controller.IsPressed("P2 Left")) + paddle2Pos = PaddleMin; + else if (_controller.IsPressed("P2 Right")) + paddle2Pos = PaddleMax; + else + paddle2Pos = (int)_controller.GetFloat("P2 Paddle"); + + PresetControllerState(1); + // Hard-wired together? + Controller2SelectHigh = Controller1SelectHigh; + + if (Controller1SelectHigh) + { + if ((paddle1Pos & 0x10) == 0) value &= 0xFE; + if ((paddle1Pos & 0x20) == 0) value &= 0xFD; + if ((paddle1Pos & 0x40) == 0) value &= 0xFB; + if ((paddle1Pos & 0x80) == 0) value &= 0xF7; + } + else + { + if ((paddle1Pos & 0x01) == 0) value &= 0xFE; + if ((paddle1Pos & 0x02) == 0) value &= 0xFD; + if ((paddle1Pos & 0x04) == 0) value &= 0xFB; + if ((paddle1Pos & 0x08) == 0) value &= 0xF7; + } + + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (!Controller1SelectHigh) value &= 0xDF; + + if (Controller2SelectHigh) + { + if ((paddle2Pos & 0x10) == 0) value &= 0xBF; + if ((paddle2Pos & 0x20) == 0) value &= 0x7F; + } + else + { + if ((paddle2Pos & 0x01) == 0) value &= 0xBF; + if ((paddle2Pos & 0x02) == 0) value &= 0x7F; + } + + PostsetControllerState(1); + } + break; + + case "Light Phaser": + if (_controller.IsPressed("P1 Trigger")) value &= 0xEF; + break; + + case "Sports Pad": + { + int p1X; + if (_controller.IsPressed("P1 Left")) + p1X = SportsPadMin; + else if (_controller.IsPressed("P1 Right")) + p1X = SportsPadMax; + else + p1X = (int)_controller.GetFloat("P1 X"); + + int p1Y; + if (_controller.IsPressed("P1 Up")) + p1Y = SportsPadMin; + else if (_controller.IsPressed("P1 Down")) + p1Y = SportsPadMax; + else + p1Y = (int)_controller.GetFloat("P1 Y"); + + int p2X; + if (_controller.IsPressed("P2 Left")) + p2X = SportsPadMin; + else if (_controller.IsPressed("P2 Right")) + p2X = SportsPadMax; + else + p2X = (int)_controller.GetFloat("P2 X"); + + int p2Y; + if (_controller.IsPressed("P2 Up")) + p2Y = SportsPadMin; + else if (_controller.IsPressed("P2 Down")) + p2Y = SportsPadMax; + else + p2Y = (int)_controller.GetFloat("P2 Y"); + + if(_region == "Japan") + { + p1X += 128; + p1Y += 128; + p2X += 128; + p2Y += 128; + } else + { + p1X *= -1; + p1Y *= -1; + p2X *= -1; + p2Y *= -1; + } + + PresetControllerState(1); + + // advance state + if (Controller1SelectHigh && (Controller1State % 2 == 0)) + { + ++Controller1State; + } + else if (!Controller1SelectHigh && (Controller1State % 2 == 1)) + { + if (++Controller1State == (_region == "Japan" ? 6 : 4)) + Controller1State = 0; + } + if (Controller2SelectHigh && (Controller2State % 2 == 0)) + { + ++Controller2State; + } + else if (!Controller2SelectHigh && (Controller2State % 2 == 1)) + { + if (++Controller2State == (_region == "Japan" ? 6 : 4)) + Controller2State = 0; + } + + switch (Controller1State) + { + case 0: + if ((p1X & 0x10) == 0) value &= 0xFE; + if ((p1X & 0x20) == 0) value &= 0xFD; + if ((p1X & 0x40) == 0) value &= 0xFB; + if ((p1X & 0x80) == 0) value &= 0xF7; + break; + case 1: + if ((p1X & 0x01) == 0) value &= 0xFE; + if ((p1X & 0x02) == 0) value &= 0xFD; + if ((p1X & 0x04) == 0) value &= 0xFB; + if ((p1X & 0x08) == 0) value &= 0xF7; + break; + case 2: + if ((p1Y & 0x10) == 0) value &= 0xFE; + if ((p1Y & 0x20) == 0) value &= 0xFD; + if ((p1Y & 0x40) == 0) value &= 0xFB; + if ((p1Y & 0x80) == 0) value &= 0xF7; + break; + case 3: + if ((p1Y & 0x01) == 0) value &= 0xFE; + if ((p1Y & 0x02) == 0) value &= 0xFD; + if ((p1Y & 0x04) == 0) value &= 0xFB; + if ((p1Y & 0x08) == 0) value &= 0xF7; + break; + case 4: + // specific to Japan: sync via TR + value &= 0xDF; + break; + case 5: + // specific to Japan: buttons + if (_controller.IsPressed("P1 B1")) value &= 0xFE; + if (_controller.IsPressed("P1 B2")) value &= 0xFD; + break; + } + + if (_region != "Japan") + { + // Buttons like normal in Export + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (_controller.IsPressed("P1 B2")) value &= 0xDF; + } + else + { + // In Japan, it contains selectHigh + if (!Controller1SelectHigh) value &= 0xEF; + } + + switch (Controller2State) + { + case 0: + if ((p2X & 0x10) == 0) value &= 0xBF; + if ((p2X & 0x20) == 0) value &= 0x7F; + break; + case 1: + if ((p2X & 0x01) == 0) value &= 0xBF; + if ((p2X & 0x02) == 0) value &= 0x7F; + break; + case 2: + if ((p2Y & 0x10) == 0) value &= 0xBF; + if ((p2Y & 0x20) == 0) value &= 0x7F; + break; + case 3: + if ((p2Y & 0x01) == 0) value &= 0xBF; + if ((p2Y & 0x02) == 0) value &= 0x7F; + break; + case 5: + // specific to Japan: buttons + if (_controller.IsPressed("P2 B1")) value &= 0xBF; + if (_controller.IsPressed("P2 B2")) value &= 0x7F; + break; + } + + PostsetControllerState(1); + } + break; + + default: + // Normal controller + + if (_controller.IsPressed("P1 Up")) value &= 0xFE; + if (_controller.IsPressed("P1 Down")) value &= 0xFD; + if (_controller.IsPressed("P1 Left")) value &= 0xFB; + if (_controller.IsPressed("P1 Right")) value &= 0xF7; + if (_controller.IsPressed("P1 B1")) value &= 0xEF; + if (_controller.IsPressed("P1 B2")) value &= 0xDF; + + if (_controller.IsPressed("P2 Up")) value &= 0xBF; + if (_controller.IsPressed("P2 Down")) value &= 0x7F; + break; + } return value; } @@ -50,10 +347,132 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem _lagged = false; byte value = 0xFF; - if (_controller.IsPressed("P2 Left")) value &= 0xFE; - if (_controller.IsPressed("P2 Right")) value &= 0xFD; - if (_controller.IsPressed("P2 B1")) value &= 0xFB; - if (_controller.IsPressed("P2 B2")) value &= 0xF7; + switch (SyncSettings.ControllerType) + { + case "Paddle": + { + // use analog values from a controller, see http://www.smspower.org/Development/Paddle + + int paddle2Pos; + if (_controller.IsPressed("P2 Left")) + paddle2Pos = PaddleMin; + else if (_controller.IsPressed("P2 Right")) + paddle2Pos = PaddleMax; + else + paddle2Pos = (int)_controller.GetFloat("P2 Paddle"); + + PresetControllerState(2); + + if (Controller2SelectHigh) + { + if ((paddle2Pos & 0x40) == 0) value &= 0xFE; + if ((paddle2Pos & 0x80) == 0) value &= 0xFD; + } + else + { + if ((paddle2Pos & 0x04) == 0) value &= 0xFE; + if ((paddle2Pos & 0x08) == 0) value &= 0xFD; + } + + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (!Controller2SelectHigh) value &= 0xF7; + + PostsetControllerState(2); + } + break; + + case "Light Phaser": + if (LatchLightPhaser) + { + value &= 0xBF; + LatchLightPhaser = false; + } + break; + + case "Sports Pad": + { + int p2X; + if (_controller.IsPressed("P2 Left")) + p2X = SportsPadMin; + else if (_controller.IsPressed("P2 Right")) + p2X = SportsPadMax; + else + p2X = (int)_controller.GetFloat("P2 X"); + + int p2Y; + if (_controller.IsPressed("P2 Down")) + p2Y = SportsPadMin; + else if (_controller.IsPressed("P2 Up")) + p2Y = SportsPadMax; + else + p2Y = (int)_controller.GetFloat("P2 Y"); + + if (_region == "Japan") + { + p2X += 128; + p2Y += 128; + } + else + { + p2X *= -1; + p2Y *= -1; + } + + PresetControllerState(2); + + if (Controller2SelectHigh && (Controller2State % 2 == 0)) + { + ++Controller2State; + } + else if (!Controller2SelectHigh && (Controller2State % 2 == 1)) + { + if (++Controller2State == (_region == "Japan" ? 6 : 4)) + Controller2State = 0; + } + + switch (Controller2State) + { + case 0: + if ((p2X & 0x40) == 0) value &= 0xFE; + if ((p2X & 0x80) == 0) value &= 0xFD; + break; + case 1: + if ((p2X & 0x04) == 0) value &= 0xFE; + if ((p2X & 0x08) == 0) value &= 0xFD; + break; + case 2: + if ((p2Y & 0x40) == 0) value &= 0xFE; + if ((p2Y & 0x80) == 0) value &= 0xFD; + break; + case 3: + if ((p2Y & 0x04) == 0) value &= 0xFE; + if ((p2Y & 0x08) == 0) value &= 0xFD; + break; + } + if (_region != "Japan") + { + // Buttons like normal in Export + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (_controller.IsPressed("P2 B2")) value &= 0xF7; + } + else + { + if (!Controller2SelectHigh) value &= 0xF7; + } + + PostsetControllerState(2); + } + break; + + default: + // Normal controller + + if (_controller.IsPressed("P2 Left")) value &= 0xFE; + if (_controller.IsPressed("P2 Right")) value &= 0xFD; + if (_controller.IsPressed("P2 B1")) value &= 0xFB; + if (_controller.IsPressed("P2 B2")) value &= 0xF7; + break; + } if (_controller.IsPressed("Reset")) value &= 0xEF; @@ -75,6 +494,33 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return value; } + internal void ProcessLineControls() + { + const int phaserRadius = 4; + + // specifically lightgun needs to do things on a per-line basis + if (SyncSettings.ControllerType == "Light Phaser") + { + byte phaserX = (byte)(_controller.GetFloat("P1 X") + 20); + int phaserY = (int)_controller.GetFloat("P1 Y"); + int scanline = Vdp.ScanLine; + + if (!LatchLightPhaser && phaserY >= scanline - phaserRadius && phaserY <= scanline + phaserRadius) + { + if (scanline >= Vdp.FrameHeight) + return; + + // latch HCounter via TH + Vdp.HCounter = phaserX; + LatchLightPhaser = true; + } + else + { + LatchLightPhaser = false; + } + } + } + byte ReadPort0() { if (IsGameGear == false) @@ -96,5 +542,49 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem return value; } + + private void PresetControllerState(int pin) + { + // The 3F port's TH slot is also used on games in some games in Export BIOS to clock the paddle state + // Re: the paddle: Yes it's silly considering the paddle was never released outside Japan but the games think otherwise + + if (_region != "Japan") + { + if ((Port3F & 0x02) == 0x00) + { + Controller1SelectHigh = (Port3F & 0x20) != 0; + + // resync + Controller2State = 3; + } + + if ((Port3F & 0x08) == 0x00) + { + Controller2SelectHigh = (Port3F & 0x80) != 0; + + // resync + Controller1State = 3; + } + } + } + + private void PostsetControllerState(int pin) + { + // for the benefit of the Japan region + if (_region == "Japan" && (++ControllerTick) == 2) + { + ControllerTick = 0; + + if (pin == 1) + { + Controller1SelectHigh ^= true; + } + else + { + Controller1SelectHigh = false; + Controller2SelectHigh ^= true; + } + } + } } } \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs index 3739b8ec25..b2ee955288 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.cs @@ -4,13 +4,12 @@ using BizHawk.Common.StringExtensions; using BizHawk.Emulation.Common; using BizHawk.Emulation.Common.Components; using BizHawk.Emulation.Cores.Components; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; /***************************************************** TODO: - + HCounter + + HCounter (Manually set for light phaser emulation... should be only case it's polled) + Try to clean up the organization of the source code. - + Lightgun/Paddle/etc if I get really bored + Mode 1 not implemented in VDP TMS modes. (I dont have a test case in SG1000 or Coleco) **********************************************************/ @@ -75,11 +74,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem HasYM2413 = true; } - Cpu = new Z80A + Cpu = new Z80A() { - RegisterSP = 0xDFF0, ReadHardware = ReadPort, WriteHardware = WritePort, + FetchMemory = ReadMemory, + ReadMemory = ReadMemory, + WriteMemory = WriteMemory, MemoryCallbacks = MemoryCallbacks }; @@ -113,6 +114,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem InitNemesisMapper(); else if (game["TerebiOekaki"]) InitTerebiOekaki(); + else if (game["EEPROM"]) + InitEEPROMMapper(); else InitSegaMapper(); @@ -160,7 +163,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } if (game["SRAM"]) + { SaveRAM = new byte[int.Parse(game.OptionValue("SRAM"))]; + Console.WriteLine(SaveRAM.Length); + } else if (game.NotInDatabase) SaveRAM = new byte[0x8000]; @@ -175,8 +181,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem var serviceProvider = ServiceProvider as BasicServiceProvider; serviceProvider.Register(Tracer); - serviceProvider.Register(new Disassembler()); + serviceProvider.Register(Cpu); Vdp.ProcessOverscan(); + + Cpu.ReadMemory = ReadMemory; + Cpu.WriteMemory = WriteMemory; } // Constants @@ -253,7 +262,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem /// /// A dummy FetchMemory that simply reads the memory /// - private byte FetchMemory_StubThunk(ushort address, bool first) + private byte FetchMemory_StubThunk(ushort address) { return ReadMemory(address); } @@ -281,7 +290,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem if ((port & 1) == 0) return Vdp.ReadVLineCounter(); else - return 0x50; // TODO Vdp.ReadHLineCounter(); + return Vdp.ReadHLineCounter(); } if (port < 0xC0) // VDP data/control ports { @@ -346,4 +355,4 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem private readonly string[] validRegions = { "Export", "Japan", "Auto" }; } -} \ No newline at end of file +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs index 75d6d33625..adccda7fd3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/SMS/VDP.cs @@ -4,7 +4,7 @@ using System.IO; using BizHawk.Common; using BizHawk.Emulation.Common; -using BizHawk.Emulation.Cores.Components.Z80; +using BizHawk.Emulation.Cores.Components.Z80A; namespace BizHawk.Emulation.Cores.Sega.MasterSystem @@ -47,6 +47,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem public int FrameHeight = 192; public int ScanLine; + public byte HCounter = 0x90; public int[] FrameBuffer = new int[256 * 192]; public int[] GameGearFrameBuffer = new int[160 * 144]; public int[] OverscanFrameBuffer = null; @@ -112,7 +113,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem StatusByte &= 0x1F; HIntPending = false; VIntPending = false; - Cpu.Interrupt = false; + Cpu.FlagI = false; return returnValue; } @@ -136,6 +137,11 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem } } + public byte ReadHLineCounter() + { + return HCounter; + } + public void WriteVdpControl(byte value) { if (VdpWaitingForLatchByte) @@ -285,13 +291,13 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { case 0: // Mode Control Register 1 CheckVideoMode(); - Cpu.Interrupt = (EnableLineInterrupts && HIntPending); - Cpu.Interrupt |= (EnableFrameInterrupts && VIntPending); + Cpu.FlagI = (EnableLineInterrupts && HIntPending); + Cpu.FlagI |= (EnableFrameInterrupts && VIntPending); break; case 1: // Mode Control Register 2 CheckVideoMode(); - Cpu.Interrupt = (EnableFrameInterrupts && VIntPending); - Cpu.Interrupt |= (EnableLineInterrupts && HIntPending); + Cpu.FlagI = (EnableFrameInterrupts && VIntPending); + Cpu.FlagI |= (EnableLineInterrupts && HIntPending); break; case 2: // Name Table Base Address NameTableBase = CalcNameTableBase(); @@ -341,7 +347,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem if (VIntPending && EnableFrameInterrupts) { - Cpu.Interrupt = true; + Cpu.FlagI = true; } } @@ -355,7 +361,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem HIntPending = true; if (EnableLineInterrupts) {; - Cpu.Interrupt = true; + Cpu.FlagI = true; } lineIntLinesRemaining = Registers[0x0A]; } @@ -375,8 +381,16 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ProcessFrameInterrupt(); ProcessLineInterrupt(); + Sms.ProcessLineControls(); - Cpu.ExecuteCycles(IPeriod); + //Console.Write(Cpu.cur_instr.Length); + //Console.Write(" "); + //Console.WriteLine(Cpu.instr_pntr); + for (int j = 0; j < IPeriod; j++) + { + Cpu.ExecuteOne(); + } + if (ScanLine == scanlinesPerFrame - 1) { @@ -428,6 +442,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem ser.Sync("Registers", ref Registers, false); ser.Sync("CRAM", ref CRAM, false); ser.Sync("VRAM", ref VRAM, false); + ser.Sync("HCounter", ref HCounter); ser.EndSection(); if (ser.IsReader) diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs index c44199e244..261a4418a3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISettable.cs @@ -1,210 +1,325 @@ -using System.ComponentModel; - -using BizHawk.Common; -using BizHawk.Emulation.Common; -using Newtonsoft.Json; - - -namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx -{ - public partial class GPGX : ISettable - { - public GPGXSettings GetSettings() - { - return _settings.Clone(); - } - - public GPGXSyncSettings GetSyncSettings() - { - return _syncSettings.Clone(); - } - - public bool PutSettings(GPGXSettings o) - { - bool ret = GPGXSettings.NeedsReboot(_settings, o); - _settings = o; - Core.gpgx_set_draw_mask(_settings.GetDrawMask()); - return ret; - } - - public bool PutSyncSettings(GPGXSyncSettings o) - { - bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o); - _syncSettings = o; - return ret; - } - - private GPGXSyncSettings _syncSettings; - private GPGXSettings _settings; - - public class GPGXSettings - { - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGA; - - [DisplayName("Background Layer A")] - [Description("True to draw BG layer A")] - [DefaultValue(true)] - public bool DrawBGA { get { return _DrawBGA; } set { _DrawBGA = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGB; - - [DisplayName("Background Layer B")] - [Description("True to draw BG layer B")] - [DefaultValue(true)] - public bool DrawBGB { get { return _DrawBGB; } set { _DrawBGB = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawBGW; - - [DisplayName("Background Layer W")] - [Description("True to draw BG layer W")] - [DefaultValue(true)] - public bool DrawBGW { get { return _DrawBGW; } set { _DrawBGW = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _DrawObj; - - [DisplayName("Sprite Layer")] - [Description("True to draw sprite layer")] - [DefaultValue(true)] - public bool DrawObj { get { return _DrawObj; } set { _DrawObj = value; } } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _PadScreen320; - - [DisplayName("Pad screen to 320")] - [Description("When using 1:1 aspect ratio, enable to make screen width constant (320) between game modes")] - [DefaultValue(false)] - public bool PadScreen320 { get { return _PadScreen320; } set { _PadScreen320 = value; } } - - [DisplayName("Audio Filter")] - [DefaultValue(LibGPGX.InitSettings.FilterType.LowPass)] - public LibGPGX.InitSettings.FilterType Filter { get; set; } - - [DisplayName("Low Pass Range")] - [Description("Only active when filter type is lowpass")] - [DefaultValue((ushort)39321)] - public ushort LowPassRange { get; set; } - - [DisplayName("Three band low cutoff")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)880)] - public short LowFreq { get; set; } - - [DisplayName("Three band high cutoff")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)5000)] - public short HighFreq { get; set; } - - [DisplayName("Three band low gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short LowGain { get; set; } - - [DisplayName("Three band mid gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short MidGain { get; set; } - - [DisplayName("Three band high gain")] - [Description("Only active when filter type is three band")] - [DefaultValue((short)1)] - public short HighGain { get; set; } - - [DeepEqualsIgnore] - [JsonIgnore] - private bool _Backdrop; - - [DisplayName("Use custom backdrop color")] - [Description("Filler when layers are off")] - [DefaultValue((bool)false)] - public bool Backdrop { get { return _Backdrop; } set { _Backdrop = value; } } - - [DisplayName("Custom backdrop color")] - [Description("Magic pink (0xffff00ff) by default")] - [DefaultValue((uint)0xffff00ff)] - public uint BackdropColor { get; set; } - - public GPGXSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public GPGXSettings Clone() - { - return (GPGXSettings)MemberwiseClone(); - } - - public LibGPGX.DrawMask GetDrawMask() - { - LibGPGX.DrawMask ret = 0; - if (DrawBGA) ret |= LibGPGX.DrawMask.BGA; - if (DrawBGB) ret |= LibGPGX.DrawMask.BGB; - if (DrawBGW) ret |= LibGPGX.DrawMask.BGW; - if (DrawObj) ret |= LibGPGX.DrawMask.Obj; - if (Backdrop) ret |= LibGPGX.DrawMask.Backdrop; - return ret; - } - - public static bool NeedsReboot(GPGXSettings x, GPGXSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - - public LibGPGX.InitSettings GetNativeSettings() - { - return new LibGPGX.InitSettings - { - Filter = Filter, - LowPassRange = LowPassRange, - LowFreq = LowFreq, - HighFreq = HighFreq, - LowGain = LowGain, - MidGain = MidGain, - HighGain = HighGain, - BackdropColor = BackdropColor - }; - } - } - - public class GPGXSyncSettings - { - [DisplayName("Use Six Button Controllers")] - [Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")] - [DefaultValue(true)] - public bool UseSixButton { get; set; } - - [DisplayName("Control Type")] - [Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")] - [DefaultValue(ControlType.Normal)] - public ControlType ControlType { get; set; } - - [DisplayName("Autodetect Region")] - [Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")] - [DefaultValue(LibGPGX.Region.Autodetect)] - public LibGPGX.Region Region { get; set; } - - public GPGXSyncSettings() - { - SettingsUtil.SetDefaultValues(this); - } - - public GPGXSyncSettings Clone() - { - return (GPGXSyncSettings)MemberwiseClone(); - } - - public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y) - { - return !DeepEquality.DeepEquals(x, y); - } - } - } -} +using System; +using System.ComponentModel; +using System.Globalization; + +using BizHawk.Common; +using BizHawk.Emulation.Common; +using Newtonsoft.Json; + + +namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx +{ + public partial class GPGX : ISettable + { + public GPGXSettings GetSettings() + { + return _settings.Clone(); + } + + public GPGXSyncSettings GetSyncSettings() + { + return _syncSettings.Clone(); + } + + public bool PutSettings(GPGXSettings o) + { + bool ret = GPGXSettings.NeedsReboot(_settings, o); + _settings = o; + Core.gpgx_set_draw_mask(_settings.GetDrawMask()); + return ret; + } + + public bool PutSyncSettings(GPGXSyncSettings o) + { + bool ret = GPGXSyncSettings.NeedsReboot(_syncSettings, o); + _syncSettings = o; + return ret; + } + + private class UintToHexConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertFrom(context, sourceType); + } + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertTo(context, destinationType); + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(uint)) + { + return string.Format("0x{0:x8}", value); + } + else + { + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value.GetType() == typeof(string)) + { + string input = (string)value; + if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + input = input.Substring(2); + } + return uint.Parse(input, NumberStyles.HexNumber, culture); + } + else + { + return base.ConvertFrom(context, culture, value); + } + } + } + + private class UshortToHexConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertFrom(context, sourceType); + } + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + { + return true; + } + else + { + return base.CanConvertTo(context, destinationType); + } + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType == typeof(string) && value.GetType() == typeof(ushort)) + { + return string.Format("0x{0:x4}", value); + } + else + { + return base.ConvertTo(context, culture, value, destinationType); + } + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value.GetType() == typeof(string)) + { + string input = (string)value; + if (input.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + input = input.Substring(2); + } + return ushort.Parse(input, NumberStyles.HexNumber, culture); + } + else + { + return base.ConvertFrom(context, culture, value); + } + } + } + + private GPGXSyncSettings _syncSettings; + private GPGXSettings _settings; + + public class GPGXSettings + { + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGA; + + [DisplayName("Background Layer A")] + [Description("True to draw BG layer A")] + [DefaultValue(true)] + public bool DrawBGA { get { return _DrawBGA; } set { _DrawBGA = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGB; + + [DisplayName("Background Layer B")] + [Description("True to draw BG layer B")] + [DefaultValue(true)] + public bool DrawBGB { get { return _DrawBGB; } set { _DrawBGB = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawBGW; + + [DisplayName("Background Layer W")] + [Description("True to draw BG layer W")] + [DefaultValue(true)] + public bool DrawBGW { get { return _DrawBGW; } set { _DrawBGW = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _DrawObj; + + [DisplayName("Sprite Layer")] + [Description("True to draw sprite layer")] + [DefaultValue(true)] + public bool DrawObj { get { return _DrawObj; } set { _DrawObj = value; } } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _PadScreen320; + + [DisplayName("Pad screen to 320")] + [Description("When using 1:1 aspect ratio, enable to make screen width constant (320) between game modes")] + [DefaultValue(false)] + public bool PadScreen320 { get { return _PadScreen320; } set { _PadScreen320 = value; } } + + [DisplayName("Audio Filter")] + [DefaultValue(LibGPGX.InitSettings.FilterType.LowPass)] + public LibGPGX.InitSettings.FilterType Filter { get; set; } + + [DisplayName("Low Pass Range")] + [Description("Only active when filter type is lowpass. Range is 0 - 0xffff. Default value is 40%")] + [TypeConverter(typeof(UshortToHexConverter))] + [DefaultValue((ushort)0x6666)] + public ushort LowPassRange { get; set; } + + [DisplayName("Three band low cutoff")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)880)] + public short LowFreq { get; set; } + + [DisplayName("Three band high cutoff")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)5000)] + public short HighFreq { get; set; } + + [DisplayName("Three band low gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short LowGain { get; set; } + + [DisplayName("Three band mid gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short MidGain { get; set; } + + [DisplayName("Three band high gain")] + [Description("Only active when filter type is three band")] + [DefaultValue((short)1)] + public short HighGain { get; set; } + + [DeepEqualsIgnore] + [JsonIgnore] + private bool _Backdrop; + + [DisplayName("Use custom backdrop color")] + [Description("Filler when layers are off")] + [DefaultValue((bool)false)] + public bool Backdrop { get { return _Backdrop; } set { _Backdrop = value; } } + + [Description("Magic pink by default. Requires core reboot")] + [TypeConverter(typeof(UintToHexConverter))] + [DefaultValue((uint)0xffff00ff)] + public uint BackdropColor { get; set; } + + public GPGXSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public GPGXSettings Clone() + { + return (GPGXSettings)MemberwiseClone(); + } + + public LibGPGX.DrawMask GetDrawMask() + { + LibGPGX.DrawMask ret = 0; + if (DrawBGA) ret |= LibGPGX.DrawMask.BGA; + if (DrawBGB) ret |= LibGPGX.DrawMask.BGB; + if (DrawBGW) ret |= LibGPGX.DrawMask.BGW; + if (DrawObj) ret |= LibGPGX.DrawMask.Obj; + if (Backdrop) ret |= LibGPGX.DrawMask.Backdrop; + return ret; + } + + public static bool NeedsReboot(GPGXSettings x, GPGXSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + + public LibGPGX.InitSettings GetNativeSettings() + { + return new LibGPGX.InitSettings + { + Filter = Filter, + LowPassRange = LowPassRange, + LowFreq = LowFreq, + HighFreq = HighFreq, + LowGain = LowGain, + MidGain = MidGain, + HighGain = HighGain, + BackdropColor = BackdropColor + }; + } + } + + public class GPGXSyncSettings + { + [DisplayName("Use Six Button Controllers")] + [Description("Controls the type of any attached normal controllers; six button controllers are used if true, otherwise three button controllers. Some games don't work correctly with six button controllers. Not relevant if other controller types are connected.")] + [DefaultValue(true)] + public bool UseSixButton { get; set; } + + [DisplayName("Control Type")] + [Description("Sets the type of controls that are plugged into the console. Some games will automatically load with a different control type.")] + [DefaultValue(ControlType.Normal)] + public ControlType ControlType { get; set; } + + [DisplayName("Autodetect Region")] + [Description("Sets the region of the emulated console. Many games can run on multiple regions and will behave differently on different ones. Some games may require a particular region.")] + [DefaultValue(LibGPGX.Region.Autodetect)] + public LibGPGX.Region Region { get; set; } + + public GPGXSyncSettings() + { + SettingsUtil.SetDefaultValues(this); + } + + public GPGXSyncSettings Clone() + { + return (GPGXSyncSettings)MemberwiseClone(); + } + + public static bool NeedsReboot(GPGXSyncSettings x, GPGXSyncSettings y) + { + return !DeepEquality.DeepEquals(x, y); + } + } + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs index 312bc3e69c..7ea082d563 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.IStatable.cs @@ -17,8 +17,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { var temp = SaveStateBinary(); temp.SaveAsHexFast(writer); - // write extra copy of stuff we don't use - writer.WriteLine("Frame {0}", Frame); } public void LoadStateText(TextReader reader) diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index 1352035a7b..807558d6b3 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -1083,7 +1083,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSX s.ExtraData.CurrentDiscIndexMounted = CurrentDiscIndexMounted; ser.Serialize(writer, s); - // TODO write extra copy of stuff we don't use (WHY?) } public void LoadStateText(TextReader reader) diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs b/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs index 28875d5d47..db2286cd84 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs @@ -151,8 +151,8 @@ namespace BizHawk.Emulation.Cores.Libretro public retro_system_info retro_system_info; public retro_system_av_info retro_system_av_info; - public uint retro_serialize_size_initial; //size_t :( - public uint retro_serialize_size; //size_t :( + public ulong retro_serialize_size_initial; //size_t :( + public ulong retro_serialize_size; //size_t :( public uint retro_region; public uint retro_api_version; diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroApi_CMD.cs b/BizHawk.Emulation.Cores/Libretro/LibretroApi_CMD.cs index 9bb5b6540c..21ceffb8b6 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroApi_CMD.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroApi_CMD.cs @@ -62,7 +62,7 @@ namespace BizHawk.Emulation.Cores.Libretro { Message(eMessage.CMD_UpdateSerializeSize); WaitForCMD(); - return comm->env.retro_serialize_size; + return (uint)comm->env.retro_serialize_size; } public bool CMD_Serialize(byte[] data) diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroApi_Structs.cs b/BizHawk.Emulation.Cores/Libretro/LibretroApi_Structs.cs index 24cfaea56c..0c50eeaa39 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroApi_Structs.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroApi_Structs.cs @@ -30,7 +30,7 @@ namespace BizHawk.Emulation.Cores.Libretro public sbyte* valid_extensions; public bool need_fullpath; public bool block_extract; - public short pad; + short _pad; } public struct retro_system_timing diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs b/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs index 623c1ef01e..243688c6f0 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroCore.cs @@ -375,7 +375,7 @@ namespace BizHawk.Emulation.Cores.Libretro public void SaveStateBinary(System.IO.BinaryWriter writer) { api.CMD_UpdateSerializeSize(); - if (savebuff == null || savebuff.Length != api.comm->env.retro_serialize_size) + if (savebuff == null || savebuff.Length != (int)api.comm->env.retro_serialize_size) { savebuff = new byte[api.comm->env.retro_serialize_size]; savebuff2 = new byte[savebuff.Length + 13]; @@ -406,7 +406,7 @@ namespace BizHawk.Emulation.Cores.Libretro public byte[] SaveStateBinary() { api.CMD_UpdateSerializeSize(); - if (savebuff == null || savebuff.Length != api.comm->env.retro_serialize_size) + if (savebuff == null || savebuff.Length != (int)api.comm->env.retro_serialize_size) { savebuff = new byte[api.comm->env.retro_serialize_size]; savebuff2 = new byte[savebuff.Length + 13]; diff --git a/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs b/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs index b1fd9ee0d6..0cacab7e64 100644 --- a/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs +++ b/BizHawk.Emulation.Cores/Waterbox/LibWaterboxCore.cs @@ -48,7 +48,7 @@ namespace BizHawk.Emulation.Cores.Waterbox } [Flags] - public enum MemoryDomainFlags : int + public enum MemoryDomainFlags : long { None = 0, /// diff --git a/BizHawk.Emulation.Cores/Waterbox/Swappable.cs b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs index 32bc1bf0f5..9b76314bc7 100644 --- a/BizHawk.Emulation.Cores/Waterbox/Swappable.cs +++ b/BizHawk.Emulation.Cores/Waterbox/Swappable.cs @@ -126,14 +126,12 @@ namespace BizHawk.Emulation.Cores.Waterbox private void DeactivateInternal() { - Console.WriteLine("Swappable DeactivateInternal {0}", GetHashCode()); foreach (var m in _memoryBlocks) m.Deactivate(); } private void ActivateInternal() { - Console.WriteLine("Swappable ActivateInternal {0}", GetHashCode()); foreach (var m in _memoryBlocks) m.Activate(); } diff --git a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj index 4f34ffd071..9ad6e73985 100644 --- a/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj +++ b/BizHawk.Emulation.DiscSystem/BizHawk.Emulation.DiscSystem.csproj @@ -70,6 +70,7 @@ + diff --git a/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs b/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs index 382cd7c39a..3ecee543b6 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/EndianBitConverter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace BizHawk.Emulation.DiscSystem @@ -114,5 +115,49 @@ namespace BizHawk.Emulation.DiscSystem } #endregion + + // (asni 20171013) - Some methods I wrote that have been shoehorned in from another project to speed up development time + // If these are offensive in any way, tell me I suck and that I need to do more work with existing methods + #region Misc + + /// + /// Returns a byte array of any length + /// Not really anything endian going on, but I struggled to find a better place for it + /// + /// + /// + /// + /// + public byte[] ReadBytes(byte[] buffer, int offset, int length) + { + return buffer.Skip(offset).Take(length).ToArray(); + } + + /// + /// Returns an int32 value from any size byte array + /// (careful, data may/will be truncated) + /// + /// + /// + /// + /// + public int ReadIntValue(byte[] buffer, int offset, int length) + { + var bytes = buffer.Skip(offset).Take(length).ToArray(); + + if (swap) + Array.Reverse(bytes); + + if (length == 1) + return bytes.FirstOrDefault(); + + if (length == 2) + return BitConverter.ToInt16(bytes, 0); + + int result = BitConverter.ToInt32(bytes, 0); + return result; + } + + #endregion } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs index 53cd7f09b1..2b40ebb9a0 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISODirectoryNode.cs @@ -48,21 +48,24 @@ namespace BizHawk.Emulation.DiscSystem s.Seek(this.Offset * ISOFile.SECTOR_SIZE, SeekOrigin.Begin); List records = new List(); - - // Read the directory entries - while (s.Position < ((this.Offset * ISOFile.SECTOR_SIZE) + this.Length)) + + // Read the directory entries + while (s.Position < ((this.Offset * ISOFile.SECTOR_SIZE) + this.Length)) { ISONode node; ISONodeRecord record; - + // Read the record record = new ISONodeRecord(); - record.Parse(s); + if (ISOFile.Format == ISOFile.ISOFormat.CDInteractive) + record.ParseCDInteractive(s); + if (ISOFile.Format == ISOFile.ISOFormat.ISO9660) + record.ParseISO9660(s); - //zero 24-jun-2013 - improved validity checks - //theres nothing here! - if (record.Length == 0) + //zero 24-jun-2013 - improved validity checks + //theres nothing here! + if (record.Length == 0) { break; } @@ -95,7 +98,8 @@ namespace BizHawk.Emulation.DiscSystem } // Add the node as a child - this.Children.Add(record.Name, node); + if (!this.Children.ContainsKey(record.Name)) + this.Children.Add(record.Name, node); } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs index fb848fa2fe..e81d6316a4 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISOFile.cs @@ -2,27 +2,51 @@ using System.Collections.Generic; using System.Text; using System.IO; +using System.Linq; namespace BizHawk.Emulation.DiscSystem { - /// - /// This class is meant to parse disk images as specified by ISO9660. - /// Specifically, it should work for most disk images that are created - /// by the stanard disk imaging software. This class is by no means - /// robust to all variations of ISO9660. - /// Also, this class does not currently support the UDF file system. - /// - /// TODO: Add functions to enumerate a directory or visit a file... - /// - /// The information for building class came from three primary sources: - /// 1. The ISO9660 wikipedia article: - /// http://en.wikipedia.org/wiki/ISO_9660 - /// 2. ISO9660 Simplified for DOS/Windows - /// http://alumnus.caltech.edu/~pje/iso9660.html - /// 3. The ISO 9660 File System - /// http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html - /// - public class ISOFile + /// + /// This class is meant to parse disk images as specified by: + /// + /// ISO9660 + /// ------- + /// It should work for most disk images that are created + /// by the stanard disk imaging software. This class is by no means + /// robust to all variations of ISO9660. + /// Also, this class does not currently support the UDF file system. + /// + /// The information for building class came from three primary sources: + /// 1. The ISO9660 wikipedia article: + /// http://en.wikipedia.org/wiki/ISO_9660 + /// 2. ISO9660 Simplified for DOS/Windows + /// http://alumnus.caltech.edu/~pje/iso9660.html + /// 3. The ISO 9660 File System + /// http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html + /// + /// + /// CD-I + /// ---- + /// (asni - 20171013) - Class modified to be able to detect and consume Green + /// Book disc images. + /// + /// The implemtation of CD-I in this class adds some (but not all) additional + /// properties to the class structures that CD-I brings. This means that + /// the same ISO class structures can be returned for both standards. + /// These small additions are readily found in ISOVolumeDescriptor.cs + /// + /// ISOFile.cs also now contains a public 'ISOFormat' enum that is set + /// during disc parsing. + /// + /// The main reference source for this implementation: + /// 1. The CD-I Full Functional Specification (aka Green Book) + /// https://www.lscdweb.com/data/downloadables/2/8/cdi_may94_r2.pdf + /// + /// + /// TODO: Add functions to enumerate a directory or visit a file... + /// + /// + public class ISOFile { #region Constants @@ -31,21 +55,37 @@ namespace BizHawk.Emulation.DiscSystem /// public const int SECTOR_SIZE = 2048; - #endregion + #endregion - #region Public Members + #region Static Members - /// - /// This is a list of all the volume descriptors in the disk image. - /// NOTE: The first entry should be the primary volume. - /// - public List VolumeDescriptors; + /// + /// Making this a static for now. Every other way I tried was fairly ineligant (asni) + /// + public static ISOFormat Format; + + public static List CDIPathTable; + + #endregion + + #region Public Members + + /// + /// This is a list of all the volume descriptors in the disk image. + /// NOTE: The first entry should be the primary volume. + /// + public List VolumeDescriptors; /// /// The Directory that is the root of this file system /// public ISODirectoryNode Root; + /// + /// The type of CDFS format detected + /// + public ISOFormat CDFSType; + #endregion #region Construction @@ -77,9 +117,9 @@ namespace BizHawk.Emulation.DiscSystem // Seek through the first volume descriptor s.Seek(startPosition + (SECTOR_SIZE * startSector), SeekOrigin.Begin); - - // Read one of more volume descriptors - do + + // Read one of more volume descriptors + do { //zero 24-jun-2013 - improved validity checks @@ -87,6 +127,8 @@ namespace BizHawk.Emulation.DiscSystem bool isValid = desc.Parse(s); if (!isValid) return false; + this.CDFSType = Format; + if (desc.IsTerminator()) break; else if (desc.Type < 4) @@ -98,16 +140,17 @@ namespace BizHawk.Emulation.DiscSystem } while (true); - //zero 24-jun-2013 - well, my very first test iso had 2 volume descriptors. - // Check to make sure we only read one volume descriptor - // Finding more could be an error with the disk. - //if (this.VolumeDescriptors.Count != 1) { - // Console.WriteLine("Strange ISO format..."); - // return; - //} + //zero 24-jun-2013 - well, my very first test iso had 2 volume descriptors. + // Check to make sure we only read one volume descriptor + // Finding more could be an error with the disk. + //if (this.VolumeDescriptors.Count != 1) { + // Console.WriteLine("Strange ISO format..."); + // return; + //} - //zero 24-jun-2013 - if theres no volume descriptors, we're gonna call this not a cdfs - if (VolumeDescriptors.Count == 0) return false; + + //zero 24-jun-2013 - if theres no volume descriptors, we're gonna call this not a cdfs + if (VolumeDescriptors.Count == 0) return false; // Visit all the directories and get the offset of each directory/file @@ -116,12 +159,68 @@ namespace BizHawk.Emulation.DiscSystem // Create (and visit) the root node this.Root = new ISODirectoryNode(this.VolumeDescriptors[0].RootDirectoryRecord); - visitedNodes.Add(this.Root.Offset, this.Root); - this.Root.Parse(s, visitedNodes); + + visitedNodes.Add(this.Root.Offset, this.Root); + this.Root.Parse(s, visitedNodes); return true; } + + private List> fileNodes; + private List dirsParsed; + + /// + /// Returns a flat list of all recursed files + /// + /// + public List> EnumerateAllFilesRecursively() + { + fileNodes = new List>(); + dirsParsed = new List(); + + if (Root.Children == null) + return fileNodes; + + // get all folders + List> dirs = (from a in Root.Children + where a.Value.GetType() == typeof(ISODirectoryNode) + select a).ToList(); + // iterate through each folder + foreach (var d in dirs) + { + // process all files in this directory (and recursively process files in sub folders + ISODirectoryNode idn = d.Value as ISODirectoryNode; + if (dirsParsed.Where(a => a == idn).Count() > 0) + continue; + + dirsParsed.Add(idn); + ProcessDirectoryFiles(idn.Children); + } + + return fileNodes.Distinct().ToList(); + } + + private void ProcessDirectoryFiles(Dictionary idn) + { + foreach (var n in idn) + { + if (n.Value.GetType() == typeof(ISODirectoryNode)) + { + if (dirsParsed.Where(a => a == n.Value).Count() > 0) + continue; + + dirsParsed.Add(n.Value as ISODirectoryNode); + ProcessDirectoryFiles((n.Value as ISODirectoryNode).Children); + } + else + { + KeyValuePair f = new KeyValuePair(n.Key, n.Value as ISOFileNode); + fileNodes.Add(f); + } + } + } + #endregion #region Printing @@ -135,6 +234,17 @@ namespace BizHawk.Emulation.DiscSystem this.Root.Print(0); } - #endregion - } + #endregion + + #region Misc + + public enum ISOFormat + { + Unknown, + ISO9660, + CDInteractive + } + + #endregion + } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs index 1913f3d897..72bb82cfff 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISONodeRecord.cs @@ -31,10 +31,16 @@ namespace BizHawk.Emulation.DiscSystem /// public byte Length; - /// - /// The file offset of the data for this file/directory (in sectors). - /// - public long OffsetOfData; + /// + /// This is the number of blocks at the beginning of the file reserved for extended attribute information + /// The format of the extended attribute record is not defined and is reserved for application use + /// + public byte ExtendedAttribRecordLength; + + /// + /// The file offset of the data for this file/directory (in sectors). + /// + public long OffsetOfData; /// /// The length of the data for this file/directory (in bytes). /// @@ -148,14 +154,19 @@ namespace BizHawk.Emulation.DiscSystem // Put the array into a memory stream and pass to the main parsing function MemoryStream s = new MemoryStream(data); s.Seek(cursor, SeekOrigin.Begin); - this.Parse(s); + + if (ISOFile.Format == ISOFile.ISOFormat.ISO9660) + this.ParseISO9660(s); + + if (ISOFile.Format == ISOFile.ISOFormat.CDInteractive) + this.ParseCDInteractive(s); } /// - /// Parse the node record from the given stream. + /// Parse the node record from the given ISO9660 stream. /// /// The stream to parse from. - public void Parse(Stream s) + public void ParseISO9660(Stream s) { EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); long startPosition = s.Position; @@ -212,6 +223,100 @@ namespace BizHawk.Emulation.DiscSystem s.Seek(startPosition + this.Length, SeekOrigin.Begin); } - #endregion - } + /// + /// Parse the node record from the given CD-I stream. + /// + /// The stream to parse from. + public void ParseCDInteractive(Stream s) + { + /* + BP Size in bytes Description + 1 1 Record length + 2 1 Extended Attribute record length + 3 4 Reserved + 7 4 File beginning LBN + 11 4 Reserved + 15 4 File size + 19 6 Creation date + 25 1 Reserved + 26 1 File flags + 27 2 Interleave + 29 2 Reserved + 31 2 Album Set Sequence number + 33 1 File name size + 34 (n) File name + 34+n 4 Owner ID + 38+n 2 Attributes + 40+n 2 Reserved + 42+n 1 File number + 43+n 1 Reserved + 43+n Total + */ + + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + long startPosition = s.Position; + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + s.Position -= ISOFile.SECTOR_SIZE; + + // Get the record length + this.Length = buffer[0]; + + // extended attribute record length + this.ExtendedAttribRecordLength = buffer[1]; + + // Read Data Offset + this.OffsetOfData = bcBig.ReadIntValue(buffer, 6, 4); + + // Read Data Length + this.LengthOfData = bcBig.ReadIntValue(buffer, 14, 4); + + // Read the time + var ti = bc.ReadBytes(buffer, 18, 6); + this.Year = ti[0]; + this.Month = ti[1]; + this.Day = ti[2]; + this.Hour = ti[3]; + this.Minute = ti[4]; + this.Second = ti[5]; + + // read interleave - still to do + + // read album (volume) set sequence number (we are ignoring this) + + // Read the name length + this.NameLength = buffer[32]; + + // Read the file/directory name + var name = bc.ReadBytes(buffer, 33, this.NameLength); + if (this.NameLength == 1 && (name[0] == 0 || name[0] == 1)) + { + if (name[0] == 0) + this.Name = ISONodeRecord.CURRENT_DIRECTORY; + else + this.Name = ISONodeRecord.PARENT_DIRECTORY; + } + else + { + this.Name = ASCIIEncoding.ASCII.GetString(name, 0, this.NameLength); + } + + // skip ownerID for now + + // read the flags - only really interested in the directory attribute (bit 15) + // (confusingly these are called 'attributes' in CD-I. the CD-I 'File Flags' entry is something else entirely) + this.Flags = buffer[37 + this.NameLength]; + + // skip filenumber + //this.FileNumber = buffer[41 + this.NameLength]; + + // Seek to end + s.Seek(startPosition + this.Length, SeekOrigin.Begin); + } + + #endregion + } } diff --git a/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs b/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs index 4dda3f59e4..e8b271e10f 100644 --- a/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs +++ b/BizHawk.Emulation.DiscSystem/CDFS/ISOVolumeDescriptor.cs @@ -25,14 +25,21 @@ namespace BizHawk.Emulation.DiscSystem private const int LENGTH_TIME = 17; private const int LENGTH_RESERVED = 512; - #endregion + #endregion - #region Public Properties + #region Private Properties - /// - /// The type of this volume description, only 1 and 255 are supported - /// - public byte Type; + private EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + private EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + + #endregion + + #region Public Properties + + /// + /// The type of this volume description, only 1 and 255 are supported + /// + public byte Type; /// /// The system identifier @@ -66,21 +73,21 @@ namespace BizHawk.Emulation.DiscSystem /// public int PathTableSize; /// - /// Sector offset of the first path table + /// (ISO9660 only) Sector offset of the first path table /// public int OffsetOfFirstLittleEndianPathTable; - /// - /// Sector offset of the second path table - /// - public int OffsetOfSecondLittleEndianPathTable; - /// - /// Sector offset of the first path table - /// - public int OffsetOfFirstBigEndianPathTable; - /// - /// Sector offset of the second path table - /// - public int OffsetOfSecondBigEndianPathTable; + /// + /// (ISO9660 only) Sector offset of the second path table + /// + public int OffsetOfSecondLittleEndianPathTable; + /// + /// (ISO9660 only) Sector offset of the first path table + /// + public int OffsetOfFirstBigEndianPathTable; + /// + /// (ISO9660 only) Sector offset of the second path table + /// + public int OffsetOfSecondBigEndianPathTable; /// /// The root directory record @@ -134,19 +141,43 @@ namespace BizHawk.Emulation.DiscSystem /// public byte[] EffectiveDateTime; - /// - /// Extra reserved data - /// - public byte[] Reserved; + /// + /// (ISO9660 only) Extra reserved data + /// + public byte[] Reserved; - #endregion - #region Construction + // CD-Interactive only + + /// + /// The bits of this field are numbered from 0 to 7 starting with the least significant bit + /// BitPosition 0: A value of 0 = the coded character set identifier field specifies only an escape sequence registered according to ISO 2375 + /// A value of 1 = the coded character set identifier field specifies only an escape sequence NOT registered according to ISO 2375 + /// BitPostion 1-7: All bits are 0 (reserved for future standardization) + /// + public byte VolumeFlags; + /// + /// This field specifies one escape sequence according to the International Register of Coded Character Sets to be used with escape + /// sequence standards for recording.The ESC character, which is the first character of all sequences, shall be omitted when recording this field + /// + public byte[] CodedCharSetIdent; + /// + /// The block address of the first block of the system Path Table is kept in this field + /// + public int AddressOfPathTable; + /// + /// This number is used to indicate the revision number of the file structure standard to which the + /// directory search files conform. It is set to one + /// - /// - /// Constructor. - /// - public ISOVolumeDescriptor() + #endregion + + #region Construction + + /// + /// Constructor. + /// + public ISOVolumeDescriptor() { // Set everything to the default value this.Type = 0; @@ -183,6 +214,11 @@ namespace BizHawk.Emulation.DiscSystem this.EffectiveDateTime = new byte[LENGTH_TIME]; this.Reserved = new byte[LENGTH_RESERVED]; + + // CD-I specific + this.VolumeFlags = 0; + this.CodedCharSetIdent = new byte[LENGTH_SHORT_IDENTIFIER]; + this.AddressOfPathTable = 0; } #endregion @@ -190,137 +226,391 @@ namespace BizHawk.Emulation.DiscSystem #region Parsing /// - /// Parse the volume descriptor header. + /// Start parsing the volume descriptor header. /// /// The stream to parse from. public bool Parse(Stream s) { - EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); - EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); long startPosition = s.Position; byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; // Read the entire structure s.Read(buffer, 0, ISOFile.SECTOR_SIZE); - // Get the type - this.Type = buffer[0]; + // Parse based on format + byte[] header = bc.ReadBytes(buffer, 0, ISOFile.SECTOR_SIZE); + if (GetISO9660(header)) + { + ParseISO9660(s); + return true; + } + if (GetCDI(header)) + { + ParseCDInteractive(s); + return true; + } - //zero 24-jun-2013 - validate - // "CD001" + 0x01 - if (buffer[1] == 'C' && buffer[2] == 'D' && buffer[3] == '0' && buffer[4] == '0' && buffer[5] == '1' && buffer[6] == 0x01) - { - //it seems to be a valid volume descriptor - } - else - { - return false; - } - - // Handle the primary volume information - if (this.Type == 1) - { - int cursor = 8; - // Get the system identifier - Array.Copy(buffer, cursor, - this.SystemIdentifier, 0, LENGTH_SHORT_IDENTIFIER); - cursor += LENGTH_SHORT_IDENTIFIER; - - // Get the volume identifier - Array.Copy(buffer, cursor, - this.VolumeIdentifier, 0, LENGTH_SHORT_IDENTIFIER); - cursor += LENGTH_SHORT_IDENTIFIER; - - cursor += 8; - - // Get the total number of sectors - this.NumberOfSectors = bc.ToInt32(buffer, cursor); - cursor += 8; - - cursor += 32; - - this.VolumeSetSize = bc.ToInt16(buffer, cursor); - cursor += 4; - this.VolumeSequenceNumber = bc.ToInt16(buffer, cursor); - cursor += 4; - this.SectorSize = bc.ToInt16(buffer, cursor); - cursor += 4; - - this.PathTableSize = bc.ToInt32(buffer, cursor); - cursor += 8; - this.OffsetOfFirstLittleEndianPathTable = bc.ToInt32(buffer, cursor); - cursor += 4; - this.OffsetOfSecondLittleEndianPathTable = bc.ToInt32(buffer, cursor); - cursor += 4; - this.OffsetOfFirstLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); - cursor += 4; - this.OffsetOfSecondLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); - cursor += 4; - - this.RootDirectoryRecord.Parse(buffer, cursor); - cursor += LENGTH_ROOT_DIRECTORY_RECORD; - - Array.Copy(buffer, cursor, - this.VolumeSetIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - Array.Copy(buffer, cursor, - this.PublisherIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - Array.Copy(buffer, cursor, - this.DataPreparerIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - Array.Copy(buffer, cursor, - this.ApplicationIdentifier, 0, LENGTH_LONG_IDENTIFIER); - cursor += LENGTH_LONG_IDENTIFIER; - - Array.Copy(buffer, cursor, - this.CopyrightFileIdentifier, 0, LENGTH_IDENTIFIER); - cursor += LENGTH_IDENTIFIER; - Array.Copy(buffer, cursor, - this.AbstractFileIdentifier, 0, LENGTH_IDENTIFIER); - cursor += LENGTH_IDENTIFIER; - Array.Copy(buffer, cursor, - this.BibliographicalFileIdentifier, 0, LENGTH_IDENTIFIER); - cursor += LENGTH_IDENTIFIER; - - Array.Copy(buffer, cursor, - this.VolumeCreationDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - Array.Copy(buffer, cursor, - this.LastModifiedDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - Array.Copy(buffer, cursor, - this.ExpirationDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - Array.Copy(buffer, cursor, - this.EffectiveDateTime, 0, LENGTH_TIME); - cursor += LENGTH_TIME; - - cursor += 1; - - cursor += 1; - - Array.Copy(buffer, cursor, - this.Reserved, 0, LENGTH_RESERVED); - cursor += LENGTH_RESERVED; - } - - return true; + return false; } - #endregion + public void ParseISO9660(Stream s) + { + long startPosition = s.Position; + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + s.Position = startPosition - ISOFile.SECTOR_SIZE; - #region Type Information + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); - /// - /// Returns true if this is the terminator volume descriptor. - /// - /// True if the terminator. - public bool IsTerminator() + // Get the type + this.Type = buffer[0]; + + // Handle the primary volume information + if (this.Type == 1) + { + int cursor = 8; + // Get the system identifier + Array.Copy(buffer, cursor, + this.SystemIdentifier, 0, LENGTH_SHORT_IDENTIFIER); + cursor += LENGTH_SHORT_IDENTIFIER; + + // Get the volume identifier + Array.Copy(buffer, cursor, + this.VolumeIdentifier, 0, LENGTH_SHORT_IDENTIFIER); + cursor += LENGTH_SHORT_IDENTIFIER; + + cursor += 8; + + // Get the total number of sectors + this.NumberOfSectors = bc.ToInt32(buffer, cursor); + cursor += 8; + + cursor += 32; + + this.VolumeSetSize = bc.ToInt16(buffer, cursor); + cursor += 4; + this.VolumeSequenceNumber = bc.ToInt16(buffer, cursor); + cursor += 4; + this.SectorSize = bc.ToInt16(buffer, cursor); + cursor += 4; + + this.PathTableSize = bc.ToInt32(buffer, cursor); + cursor += 8; + this.OffsetOfFirstLittleEndianPathTable = bc.ToInt32(buffer, cursor); + cursor += 4; + this.OffsetOfSecondLittleEndianPathTable = bc.ToInt32(buffer, cursor); + cursor += 4; + this.OffsetOfFirstLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); + cursor += 4; + this.OffsetOfSecondLittleEndianPathTable = bcBig.ToInt32(buffer, cursor); + cursor += 4; + + this.RootDirectoryRecord.Parse(buffer, cursor); + cursor += LENGTH_ROOT_DIRECTORY_RECORD; + + Array.Copy(buffer, cursor, + this.VolumeSetIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + Array.Copy(buffer, cursor, + this.PublisherIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + Array.Copy(buffer, cursor, + this.DataPreparerIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + Array.Copy(buffer, cursor, + this.ApplicationIdentifier, 0, LENGTH_LONG_IDENTIFIER); + cursor += LENGTH_LONG_IDENTIFIER; + + Array.Copy(buffer, cursor, + this.CopyrightFileIdentifier, 0, LENGTH_IDENTIFIER); + cursor += LENGTH_IDENTIFIER; + Array.Copy(buffer, cursor, + this.AbstractFileIdentifier, 0, LENGTH_IDENTIFIER); + cursor += LENGTH_IDENTIFIER; + Array.Copy(buffer, cursor, + this.BibliographicalFileIdentifier, 0, LENGTH_IDENTIFIER); + cursor += LENGTH_IDENTIFIER; + + Array.Copy(buffer, cursor, + this.VolumeCreationDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + Array.Copy(buffer, cursor, + this.LastModifiedDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + Array.Copy(buffer, cursor, + this.ExpirationDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + Array.Copy(buffer, cursor, + this.EffectiveDateTime, 0, LENGTH_TIME); + cursor += LENGTH_TIME; + + cursor += 1; + + cursor += 1; + + Array.Copy(buffer, cursor, + this.Reserved, 0, LENGTH_RESERVED); + cursor += LENGTH_RESERVED; + } + } + + public void ParseCDInteractive(Stream s) + { + /* From the Green Book Spec + * BP (byte position) obviously is n+1 + + BP Size in Bytes Description + 1 1 Disc Label Record Type + 2 5 Volume Structure Standard ID + 7 1 Volume Structure Version number + 8 1 Volume flags + 9 32 System identifier + 41 32 Volume identifier + 73 12 Reserved + 85 4 Volume space size + 89 32 Coded Character Set identifier + 121 2 Reserved + 123 2 Number of Volumes in Album + 125 2 Reserved + 127 2 Album Set Sequence number + 129 2 Reserved + 131 2 Logical Block size + 133 4 Reserved + 137 4 Path Table size + 141 8 Reserved + 149 4 Address of Path Table + 153 38 Reserved + 191 128 Album identifier + 319 128 Publisher identifier + 447 128 Data Preparer identifier + 575 128 Application identifier + 703 32 Copyright file name + 735 5 Reserved + 740 32 Abstract file name + 772 5 Reserved + 777 32 Bibliographic file name + 809 5 Reserved + 814 16 Creation date and time + 830 1 Reserved + 831 16 Modification date and time + 847 1 Reserved + 848 16 Expiration date and time + 864 1 Reserved + 865 16 Effective date and time + 881 1 Reserved + 882 1 File Structure Standard Version number + 883 1 Reserved + 884 512 Application use + 1396 653 Reserved */ + + long startPosition = s.Position; + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + s.Position = startPosition - ISOFile.SECTOR_SIZE; + + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + + // Get the type + this.Type = buffer[0]; + + // Handle the primary volume information + if (this.Type == 1) + { + this.VolumeFlags = buffer[7]; + this.SystemIdentifier = bc.ReadBytes(buffer, 8, LENGTH_SHORT_IDENTIFIER); + this.VolumeIdentifier = bc.ReadBytes(buffer, 40, LENGTH_SHORT_IDENTIFIER); + this.NumberOfSectors = bcBig.ReadIntValue(buffer, 84, 4); + this.CodedCharSetIdent = bc.ReadBytes(buffer, 88, LENGTH_SHORT_IDENTIFIER); + this.VolumeSetSize = bcBig.ReadIntValue(buffer, 122, 2); + this.VolumeSequenceNumber = bcBig.ReadIntValue(buffer, 126, 2); + this.SectorSize = bcBig.ReadIntValue(buffer, 130, 2); + this.PathTableSize = bcBig.ReadIntValue(buffer, 136, 4); + this.AddressOfPathTable = bcBig.ReadIntValue(buffer, 148, 4); + + this.VolumeSetIdentifier = bc.ReadBytes(buffer, 190, LENGTH_LONG_IDENTIFIER); + this.PublisherIdentifier = bc.ReadBytes(buffer, 318, LENGTH_LONG_IDENTIFIER); + this.DataPreparerIdentifier = bc.ReadBytes(buffer, 446, LENGTH_LONG_IDENTIFIER); + this.ApplicationIdentifier = bc.ReadBytes(buffer, 574, LENGTH_LONG_IDENTIFIER); + + this.CopyrightFileIdentifier = bc.ReadBytes(buffer, 702, LENGTH_SHORT_IDENTIFIER); + this.AbstractFileIdentifier = bc.ReadBytes(buffer, 739, LENGTH_SHORT_IDENTIFIER); + this.BibliographicalFileIdentifier = bc.ReadBytes(buffer, 776, LENGTH_SHORT_IDENTIFIER); + + this.VolumeCreationDateTime = bc.ReadBytes(buffer, 813, 16); + this.LastModifiedDateTime = bc.ReadBytes(buffer, 830, 16); + this.ExpirationDateTime = bc.ReadBytes(buffer, 847, 16); + this.EffectiveDateTime = bc.ReadBytes(buffer, 864, 16); + + // save current position + long pos = s.Position; + + // get path table records + s.Position = ISOFile.SECTOR_SIZE * this.AddressOfPathTable; + ISOFile.CDIPathTable = CDIPathNode.ParsePathTable(s, this.PathTableSize); + + // read the root dir record + s.Position = ISOFile.SECTOR_SIZE * ISOFile.CDIPathTable[0].DirectoryBlockAddress; + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + this.RootDirectoryRecord.Parse(buffer, 0); + + // go back to where we were + s.Position = pos; + } + } + + /// + /// Detect ISO9660 + /// + /// + /// + public bool GetISO9660(byte[] buffer) + { + //zero 24-jun-2013 - validate ISO9660 + // "CD001" + 0x01 + if (buffer[1] == 'C' && buffer[2] == 'D' && buffer[3] == '0' && buffer[4] == '0' && buffer[5] == '1' && buffer[6] == 0x01) + { + ISOFile.Format = ISOFile.ISOFormat.ISO9660; + return true; + } + + return false; + } + + /// + /// Detect CD-I + /// + /// + /// + public bool GetCDI(byte[] buffer) + { + // CD-Interactive + if (Encoding.ASCII.GetString(bc.ReadBytes(buffer, 1, 5)).Contains("CD-I")) + { + ISOFile.Format = ISOFile.ISOFormat.CDInteractive; + return true; + } + + return false; + } + + #endregion + + #region Type Information + + /// + /// Returns true if this is the terminator volume descriptor. + /// + /// True if the terminator. + public bool IsTerminator() { return (this.Type == 255); } #endregion } + + /// + /// Represents a Directory Path Table entry on a CD-I disc + /// + public class CDIPathNode + { + #region Public Properties + + /// + /// The length of the directory name. + /// + public byte NameLength; + + /// + /// This is the length of the Extended Attribute record + /// + public byte ExtendedAttribRecordLength; + + /// + /// This field contains the beginning logical block number (LBN) of the directory file on disc + /// + public int DirectoryBlockAddress; + + /// + /// This is the number (relative to the beginning of the Path Table) of this directory's parent + /// + public int ParentDirectoryNumber; + + /// + /// The directory name. + /// This variable length field is used to store the actual text representing the name of the directory. + /// If the length of the file name is odd, a null padding byte is added to make the size of the Path Table record even. + /// The padding byte is not included in the name size field. + /// + public string Name; + + #endregion + + #region Construction + + /// + /// Empty Constructor + /// + public CDIPathNode() + { + + } + + #endregion + + #region Parsing + + /* + BP Size in bytes Description + 1 1 Name size + 2 1 Extended Attribute record length + 3 4 Directory block address + 7 2 Parent Directory number + 9 n Directory file name + */ + + public static List ParsePathTable(Stream s, int PathTableSize) + { + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + + byte[] buffer = new byte[ISOFile.SECTOR_SIZE]; + + // Read the entire structure + s.Read(buffer, 0, ISOFile.SECTOR_SIZE); + + int startCursor = 0; + + List pathNodes = new List(); + + int pad = 0; + + do + { + CDIPathNode node = new CDIPathNode(); + byte[] data = bc.ReadBytes(buffer, startCursor, ISOFile.SECTOR_SIZE - startCursor); + node.NameLength = data[0]; + + node.ExtendedAttribRecordLength = data[1]; + node.DirectoryBlockAddress = bcBig.ReadIntValue(data, 2, 4); + node.ParentDirectoryNumber = bcBig.ReadIntValue(data, 6, 2); + node.Name = Encoding.ASCII.GetString(bc.ReadBytes(data, 8, data[0])); + + // if nameLength is odd a padding byte must be added + + if (node.NameLength % 2 != 0) + pad = 1; + + pathNodes.Add(node); + + startCursor += node.NameLength + 8; + + } while (startCursor < PathTableSize + pad); + + + return pathNodes; + } + + #endregion + } } diff --git a/BizHawk.Emulation.DiscSystem/Disc.cs b/BizHawk.Emulation.DiscSystem/Disc.cs index ea971e56e9..88b38540ae 100644 --- a/BizHawk.Emulation.DiscSystem/Disc.cs +++ b/BizHawk.Emulation.DiscSystem/Disc.cs @@ -74,12 +74,36 @@ namespace BizHawk.Emulation.DiscSystem } } + /// + /// Easily extracts a mode1 sector range (suitable for extracting ISO FS data files) + /// + public byte[] Easy_Extract_Mode1(int lba_start, int lba_count, int byteLength = -1) + { + int totsize = lba_count * 2048; + byte[] ret = new byte[totsize]; + var dsr = new DiscSectorReader(this); + dsr.Policy.DeterministicClearBuffer = false; + for (int i = 0; i < lba_count; i++) + { + dsr.ReadLBA_2048(lba_start + i, ret, i*2048); + } + if (byteLength != -1 && byteLength != totsize) + { + byte[] newret = new byte[byteLength]; + Array.Copy(ret, newret, byteLength); + return newret; + } + return ret; + } + /// /// The DiscMountPolicy used to mount the disc. Consider this read-only. /// NOT SURE WE NEED THIS /// //public DiscMountPolicy DiscMountPolicy; + + //---------------------------------------------------------------------------- /// diff --git a/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs b/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs new file mode 100644 index 0000000000..27699da2d1 --- /dev/null +++ b/BizHawk.Emulation.DiscSystem/DiscFormats/MDS_Format.cs @@ -0,0 +1,915 @@ +using System; +using System.Text; +using System.IO; +using System.Globalization; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; + +namespace BizHawk.Emulation.DiscSystem +{ + /// + /// Parsing Alcohol 120% files + /// Info taken from: + /// * http://forum.redump.org/post/41803/#p41803 + /// * Libmirage image-mds parser - https://sourceforge.net/projects/cdemu/files/libmirage/ + /// * DiscImageChef - https://github.com/claunia/DiscImageChef/blob/master/DiscImageChef.DiscImages/Alcohol120.cs + /// + public class MDS_Format + { + /// + /// A loose representation of an Alcohol 120 .mds file (with a few extras) + /// + public class AFile + { + /// + /// Full path to the MDS file + /// + public string MDSPath; + + /// + /// MDS Header + /// + public AHeader Header = new AHeader(); + + /// + /// List of MDS session blocks + /// + public List Sessions = new List(); + + /// + /// List of track blocks + /// + public List Tracks = new List(); + + /// + /// Current parsed session objects + /// + public List ParsedSession = new List(); + + /// + /// Calculated MDS TOC entries (still to be parsed into BizHawk) + /// + public List TOCEntries = new List(); + + } + + public class AHeader + { + /// + /// Standard alcohol 120% signature - usually "MEDIA DESCRIPTOR" + /// + public string Signature; // 16 bytes + + /// + /// Alcohol version? + /// + public byte[] Version; // 2 bytes + + /// + /// The medium type + /// * 0x00 - CD + /// * 0x01 - CD-R + /// * 0x02 - CD-RW + /// * 0x10 - DVD + /// * 0x12 - DVD-R + /// + public int Medium; + + /// + /// Number of sessions + /// + public int SessionCount; + + /// + /// Burst Cutting Area length + /// + public int BCALength; + + /// + /// Burst Cutting Area data offset + /// + public Int64 BCAOffset; + + /// + /// Offset to disc (DVD?) structures + /// + public Int64 StructureOffset; + + /// + /// Offset to the first session block + /// + public Int64 SessionOffset; + + /// + /// Data Position Measurement offset + /// + public Int64 DPMOffset; + + /// + /// Parse mds stream for the header + /// + /// + /// + public AHeader Parse(Stream stream) + { + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + + byte[] header = new byte[88]; + stream.Read(header, 0, 88); + + this.Signature = Encoding.ASCII.GetString(header.Take(16).ToArray()); + this.Version = header.Skip(16).Take(2).ToArray(); + this.Medium = bc.ToInt16(header.Skip(18).Take(2).ToArray()); + this.SessionCount = bc.ToInt16(header.Skip(20).Take(2).ToArray()); + this.BCALength = bc.ToInt16(header.Skip(26).Take(2).ToArray()); + this.BCAOffset = bc.ToInt32(header.Skip(36).Take(4).ToArray()); + this.StructureOffset = bc.ToInt32(header.Skip(64).Take(4).ToArray()); + this.SessionOffset = bc.ToInt32(header.Skip(80).Take(4).ToArray()); + this.DPMOffset = bc.ToInt32(header.Skip(84).Take(4).ToArray()); + + return this; + } + } + + /// + /// MDS session block representation + /// + public class ASession + { + public int SessionStart; /* Session's start address */ + public int SessionEnd; /* Session's end address */ + public int SessionNumber; /* Session number */ + public byte AllBlocks; /* Number of all data blocks. */ + public byte NonTrackBlocks; /* Number of lead-in data blocks */ + public int FirstTrack; /* First track in session */ + public int LastTrack; /* Last track in session */ + public Int64 TrackOffset; /* Offset of lead-in+regular track data blocks. */ + } + + /// + /// Representation of an MDS track block + /// For convenience (and extra confusion) this also holds the track extrablock, filename(footer) block infos + /// as well as the calculated image filepath as specified in the MDS file + /// + public class ATrack + { + /// + /// The specified data mode + /// 0x00 - None (no data) + /// 0x02 - DVD + /// 0xA9 - Audio + /// 0xAA - Mode1 + /// 0xAB - Mode2 + /// 0xAC - Mode2 Form1 + /// 0xAD - Mode2 Form2 + /// + public byte Mode; /* Track mode */ + + /// + /// Subchannel mode for the track (0x00 = None, 0x08 = Interleaved) + /// + public byte SubMode; /* Subchannel mode */ + + /* These are the fields from Sub-channel Q information, which are + also returned in full TOC by READ TOC/PMA/ATIP command */ + public int ADR_Control; /* Adr/Ctl */ + public int TrackNo; /* Track number field */ + public int Point; /* Point field (= track number for track entries) */ + public int AMin; /* Min */ + public int ASec; /* Sec */ + public int AFrame; /* Frame */ + public int Zero; /* Zero */ + public int PMin; /* PMin */ + public int PSec; /* PSec */ + public int PFrame; /* PFrame */ + + public Int64 ExtraOffset; /* Start offset of this track's extra block. */ + public int SectorSize; /* Sector size. */ + public Int64 PLBA; /* Track start sector (PLBA). */ + public ulong StartOffset; /* Track start offset (from beginning of MDS file) */ + public Int64 Files; /* Number of filenames for this track */ + public Int64 FooterOffset; /* Start offset of footer (from beginning of MDS file) */ + + /// + /// Track extra block + /// + public ATrackExtra ExtraBlock = new ATrackExtra(); + + /// + /// List of footer(filename) blocks for this track + /// + public List FooterBlocks = new List(); + + /// + /// List of the calculated full paths to this track's image file + /// The MDS file itself may contain a filename, or just an *.extension + /// + public List ImageFileNamePaths = new List(); + + public int BlobIndex; + } + + /// + /// Extra track block + /// + public class ATrackExtra + { + public Int64 Pregap; /* Number of sectors in pregap. */ + public Int64 Sectors; /* Number of sectors in track. */ + } + + /// + /// Footer (filename) block - potentially one for every track + /// + public class AFooter + { + public Int64 FilenameOffset; /* Start offset of image filename string (from beginning of mds file) */ + public Int64 WideChar; /* Seems to be set to 1 if widechar filename is used */ + } + + /// + /// Represents a parsed MDS TOC entry + /// + public class ATOCEntry + { + public ATOCEntry(int entryNum) + { + EntryNum = entryNum; + } + + /// + /// these should be 0-indexed + /// + public int EntryNum; + + + /// + /// 1-indexed - the session that this entry belongs to + /// + public int Session; + + /// + /// this seems just to be the LBA corresponding to AMIN:ASEC:AFRAME (give or take 150). It's not stored on the disc, and it's redundant. + /// + //public int ALBA; + + /// + /// this seems just to be the LBA corresponding to PMIN:PSEC:PFRAME (give or take 150). + /// + public int PLBA; + + //these correspond pretty directly to values in the Q subchannel fields + //NOTE: they're specified as absolute MSF. That means, they're 2 seconds off from what they should be when viewed as final TOC values + public int ADR_Control; + public int TrackNo; + public int Point; + public int AMin; + public int ASec; + public int AFrame; + public int Zero; + public int PMin; + public int PSec; + public int PFrame; + + + public int SectorSize; + public long TrackOffset; + + /// + /// List of the calculated full paths to this track's image file + /// The MDS file itself may contain a filename, or just an *.extension + /// + public List ImageFileNamePaths = new List(); + + /// + /// Track extra block + /// + public ATrackExtra ExtraBlock = new ATrackExtra(); + + public int BlobIndex; + } + + public AFile Parse(Stream stream) + { + EndianBitConverter bc = EndianBitConverter.CreateForLittleEndian(); + EndianBitConverter bcBig = EndianBitConverter.CreateForBigEndian(); + bool isDvd = false; + + AFile aFile = new AFile(); + + aFile.MDSPath = (stream as FileStream).Name; + + stream.Seek(0, SeekOrigin.Begin); + + // check whether the header in the mds file is long enough + if (stream.Length < 88) throw new MDSParseException("Malformed MDS format: The descriptor file does not appear to be long enough."); + + // parse header + aFile.Header = aFile.Header.Parse(stream); + + // check version to make sure this is only v1.x + // currently NO support for version 2.x + + if (aFile.Header.Version[0] > 1) + { + throw new MDSParseException("MDS Parse Error: Only MDS version 1.x is supported!\nDetected version: " + aFile.Header.Version[0] + "." + aFile.Header.Version[1]); + } + + // parse sessions + Dictionary aSessions = new Dictionary(); + + stream.Seek(aFile.Header.SessionOffset, SeekOrigin.Begin); + for (int se = 0; se < aFile.Header.SessionCount; se++) + { + byte[] sessionHeader = new byte[24]; + stream.Read(sessionHeader, 0, 24); + //sessionHeader.Reverse().ToArray(); + + ASession session = new ASession(); + + session.SessionStart = bc.ToInt32(sessionHeader.Take(4).ToArray()); + session.SessionEnd = bc.ToInt32(sessionHeader.Skip(4).Take(4).ToArray()); + session.SessionNumber = bc.ToInt16(sessionHeader.Skip(8).Take(2).ToArray()); + session.AllBlocks = sessionHeader[10]; + session.NonTrackBlocks = sessionHeader[11]; + session.FirstTrack = bc.ToInt16(sessionHeader.Skip(12).Take(2).ToArray()); + session.LastTrack = bc.ToInt16(sessionHeader.Skip(14).Take(2).ToArray()); + session.TrackOffset = bc.ToInt32(sessionHeader.Skip(20).Take(4).ToArray()); + + + //mdsf.Sessions.Add(session); + aSessions.Add(session.SessionNumber, session); + } + + long footerOffset = 0; + + // parse track blocks + Dictionary aTracks = new Dictionary(); + + // iterate through each session block + foreach (ASession session in aSessions.Values) + { + stream.Seek(session.TrackOffset, SeekOrigin.Begin); + //Dictionary sessionToc = new Dictionary(); + + // iterate through every block specified in each session + for (int bl = 0; bl < session.AllBlocks; bl++) + { + byte[] trackHeader; + ATrack track = new ATrack(); + + trackHeader = new byte[80]; + + stream.Read(trackHeader, 0, 80); + + track.Mode = trackHeader[0]; + track.SubMode = trackHeader[1]; + track.ADR_Control = trackHeader[2]; + track.TrackNo = trackHeader[3]; + track.Point = trackHeader[4]; + track.AMin = trackHeader[5]; + track.ASec = trackHeader[6]; + track.AFrame = trackHeader[7]; + track.Zero = trackHeader[8]; + track.PMin = trackHeader[9]; + track.PSec = trackHeader[10]; + track.PFrame = trackHeader[11]; + track.ExtraOffset = bc.ToInt32(trackHeader.Skip(12).Take(4).ToArray()); + track.SectorSize = bc.ToInt16(trackHeader.Skip(16).Take(2).ToArray()); + track.PLBA = bc.ToInt32(trackHeader.Skip(36).Take(4).ToArray()); + track.StartOffset = BitConverter.ToUInt64(trackHeader.Skip(40).Take(8).ToArray(), 0); + track.Files = bc.ToInt32(trackHeader.Skip(48).Take(4).ToArray()); + track.FooterOffset = bc.ToInt32(trackHeader.Skip(52).Take(4).ToArray()); + + if (track.Mode == 0x02) + { + isDvd = true; + throw new MDSParseException("DVD Detected. Not currently supported!"); + } + + + // check for track extra block - this can probably be handled in a separate loop, + // but I'll just store the current stream position then seek forward to the extra block for this track + Int64 currPos = stream.Position; + + // Only CDs have extra blocks - for DVDs ExtraOffset = track length + if (track.ExtraOffset > 0 && !isDvd) + { + byte[] extHeader = new byte[8]; + stream.Seek(track.ExtraOffset, SeekOrigin.Begin); + stream.Read(extHeader, 0, 8); + track.ExtraBlock.Pregap = bc.ToInt32(extHeader.Take(4).ToArray()); + track.ExtraBlock.Sectors = bc.ToInt32(extHeader.Skip(4).Take(4).ToArray()); + stream.Seek(currPos, SeekOrigin.Begin); + } + else if (isDvd == true) + { + track.ExtraBlock.Sectors = track.ExtraOffset; + } + + // read the footer/filename block for this track + currPos = stream.Position; + long numOfFilenames = track.Files; + for (long fi = 1; fi <= numOfFilenames; fi++) + { + // skip leadin/out info tracks + if (track.FooterOffset == 0) + continue; + + byte[] foot = new byte[16]; + stream.Seek(track.FooterOffset, SeekOrigin.Begin); + stream.Read(foot, 0, 16); + + AFooter f = new AFooter(); + f.FilenameOffset = bc.ToInt32(foot.Take(4).ToArray()); + f.WideChar = bc.ToInt32(foot.Skip(4).Take(4).ToArray()); + track.FooterBlocks.Add(f); + track.FooterBlocks = track.FooterBlocks.Distinct().ToList(); + + // parse the filename string + string fileName = "*.mdf"; + if (f.FilenameOffset > 0) + { + // filename offset is present + stream.Seek(f.FilenameOffset, SeekOrigin.Begin); + byte[] fname; + + if (numOfFilenames == 1) + { + if (aFile.Header.DPMOffset == 0) + { + // filename is in the remaining space to EOF + fname = new byte[stream.Length - stream.Position]; + } + else + { + // filename is in the remaining space to EOF + dpm offset + fname = new byte[aFile.Header.DPMOffset - stream.Position]; + } + } + + else + { + // looks like each filename string is 6 bytes with a trailing \0 + fname = new byte[6]; + } + + + // read the filename + stream.Read(fname, 0, fname.Length); + + // if widechar is 1 filename is stored using 16-bit, otherwise 8-bit is used + if (f.WideChar == 1) + fileName = Encoding.Unicode.GetString(fname).TrimEnd('\0'); + else + fileName = Encoding.Default.GetString(fname).TrimEnd('\0'); + } + + else + { + // assume an MDF file with the same name as the MDS + } + + string dir = Path.GetDirectoryName(aFile.MDSPath); + + if (f.FilenameOffset == 0 || + string.Compare(fileName, "*.mdf", StringComparison.InvariantCultureIgnoreCase) == 0) + { + fileName = dir + @"\" + Path.GetFileNameWithoutExtension(aFile.MDSPath) + ".mdf"; + } + else + { + fileName = dir + @"\" + fileName; + } + + track.ImageFileNamePaths.Add(fileName); + track.ImageFileNamePaths = track.ImageFileNamePaths.Distinct().ToList(); + } + + stream.Position = currPos; + + + aTracks.Add(track.Point, track); + aFile.Tracks.Add(track); + + if (footerOffset == 0) + footerOffset = track.FooterOffset; + } + } + + + // build custom session object + aFile.ParsedSession = new List(); + foreach (var s in aSessions.Values) + { + Session session = new Session(); + ATrack startTrack; + ATrack endTrack; + + if (!aTracks.TryGetValue(s.FirstTrack, out startTrack)) + { + break; + } + + if (!aTracks.TryGetValue(s.LastTrack, out endTrack)) + { + break; + } + + session.StartSector = startTrack.PLBA; + session.StartTrack = s.FirstTrack; + session.SessionSequence = s.SessionNumber; + session.EndSector = endTrack.PLBA + endTrack.ExtraBlock.Sectors - 1; + session.EndTrack = s.LastTrack; + + aFile.ParsedSession.Add(session); + } + + // now build the TOC object + foreach (var se in aFile.ParsedSession) + { + // get the first and last tracks + int sTrack = se.StartTrack; + int eTrack = se.EndTrack; + + // get list of all tracks from aTracks for this session + var tracks = (from a in aTracks.Values + where a.TrackNo >= sTrack || a.TrackNo <= eTrack + orderby a.TrackNo + select a).ToList(); + + // create the TOC entries + foreach (var t in tracks) + { + ATOCEntry toc = new ATOCEntry(t.Point); + toc.ADR_Control = t.ADR_Control; + toc.AFrame = t.AFrame; + toc.AMin = t.AMin; + toc.ASec = t.ASec; + toc.EntryNum = t.TrackNo; + toc.PFrame = t.PFrame; + toc.PLBA = Convert.ToInt32(t.PLBA); + toc.PMin = t.PMin; + toc.Point = t.Point; + toc.PSec = t.PSec; + toc.SectorSize = t.SectorSize; + toc.Zero = t.Zero; + toc.TrackOffset = Convert.ToInt64(t.StartOffset); + toc.Session = se.SessionSequence; + toc.ImageFileNamePaths = t.ImageFileNamePaths; + toc.ExtraBlock = t.ExtraBlock; + toc.BlobIndex = t.BlobIndex; + aFile.TOCEntries.Add(toc); + } + + } + + return aFile; + } + + /// + /// Custom session object + /// + public class Session + { + public long StartSector; + public int StartTrack; + public int SessionSequence; + public long EndSector; + public int EndTrack; + } + + + public class MDSParseException : Exception + { + public MDSParseException(string message) : base(message) { } + } + + + public class LoadResults + { + public List RawTOCEntries; + public AFile ParsedMDSFile; + public bool Valid; + public Exception FailureException; + public string MdsPath; + } + + public static LoadResults LoadMDSPath(string path) + { + LoadResults ret = new LoadResults(); + ret.MdsPath = path; + //ret.MdfPath = Path.ChangeExtension(path, ".mdf"); + try + { + if (!File.Exists(path)) throw new MDSParseException("Malformed MDS format: nonexistent MDS file!"); + + AFile mdsf; + using (var infMDS = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) + mdsf = new MDS_Format().Parse(infMDS); + + ret.ParsedMDSFile = mdsf; + + ret.Valid = true; + } + catch (MDSParseException ex) + { + ret.FailureException = ex; + } + + return ret; + } + + Dictionary MountBlobs(AFile mdsf, Disc disc) + { + Dictionary BlobIndex = new Dictionary(); + + int count = 0; + foreach (var track in mdsf.Tracks) + { + foreach (var file in track.ImageFileNamePaths.Distinct()) + { + if (!File.Exists(file)) + throw new MDSParseException("Malformed MDS format: nonexistent image file: " + file); + + IBlob mdfBlob = null; + long mdfLen = -1; + + //mount the file + if (mdfBlob == null) + { + var mdfFile = new Disc.Blob_RawFile() { PhysicalPath = file }; + mdfLen = mdfFile.Length; + mdfBlob = mdfFile; + } + + bool dupe = false; + foreach (var re in disc.DisposableResources) + { + if (re.ToString() == mdfBlob.ToString()) + dupe = true; + } + + if (!dupe) + { + // wrap in zeropadadapter + disc.DisposableResources.Add(mdfBlob); + BlobIndex[count] = mdfBlob; + } + } + } + + return BlobIndex; + } + + RawTOCEntry EmitRawTOCEntry(ATOCEntry entry) + { + BCD2 tno, ino; + + //this should actually be zero. im not sure if this is stored as BCD2 or not + tno = BCD2.FromDecimal(entry.TrackNo); + + //these are special values.. I think, taken from this: + //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html + //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD. + //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing. + ino = BCD2.FromDecimal(entry.Point); + if (entry.Point == 0xA0) ino.BCDValue = 0xA0; + else if (entry.Point == 0xA1) ino.BCDValue = 0xA1; + else if (entry.Point == 0xA2) ino.BCDValue = 0xA2; + + // get ADR & Control from ADR_Control byte + byte adrc = Convert.ToByte(entry.ADR_Control); + var Control = adrc & 0x0F; + var ADR = adrc >> 4; + + var q = new SubchannelQ + { + q_status = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)), + q_tno = tno, + q_index = ino, + min = BCD2.FromDecimal(entry.AMin), + sec = BCD2.FromDecimal(entry.ASec), + frame = BCD2.FromDecimal(entry.AFrame), + zero = (byte)entry.Zero, + ap_min = BCD2.FromDecimal(entry.PMin), + ap_sec = BCD2.FromDecimal(entry.PSec), + ap_frame = BCD2.FromDecimal(entry.PFrame), + q_crc = 0, //meaningless + }; + + return new RawTOCEntry { QData = q }; + } + + + /// + /// Loads a MDS at the specified path to a Disc object + /// + public Disc LoadMDSToDisc(string mdsPath, DiscMountPolicy IN_DiscMountPolicy) + { + var loadResults = LoadMDSPath(mdsPath); + if (!loadResults.Valid) + throw loadResults.FailureException; + + Disc disc = new Disc(); + + // load all blobs + Dictionary BlobIndex = MountBlobs(loadResults.ParsedMDSFile, disc); + + var mdsf = loadResults.ParsedMDSFile; + + //generate DiscTOCRaw items from the ones specified in the MDS file + disc.RawTOCEntries = new List(); + foreach (var entry in mdsf.TOCEntries) + { + disc.RawTOCEntries.Add(EmitRawTOCEntry(entry)); + } + + //analyze the RAWTocEntries to figure out what type of track track 1 is + var tocSynth = new Synthesize_DiscTOC_From_RawTOCEntries_Job() { Entries = disc.RawTOCEntries }; + tocSynth.Run(); + + // now build the sectors + int currBlobIndex = 0; + foreach (var session in mdsf.ParsedSession) + { + for (int i = session.StartTrack; i <= session.EndTrack; i++) + { + int relMSF = -1; + + var track = mdsf.TOCEntries.Where(t => t.Point == i).FirstOrDefault(); + if (track == null) + break; + + // ignore the info entries + if (track.Point == 0xA0 || + track.Point == 0xA1 || + track.Point == 0xA2) + { + continue; + } + + // get the blob(s) for this track + // its probably a safe assumption that there will be only one blob per track, + // but i'm still not 100% sure on this + var tr = (from a in mdsf.TOCEntries + where a.Point == i + select a).FirstOrDefault(); + + if (tr == null) + throw new MDSParseException("BLOB Error!"); + + List blobstrings = new List(); + foreach (var t in tr.ImageFileNamePaths) + { + if (!blobstrings.Contains(t)) + blobstrings.Add(t); + } + + var tBlobs = (from a in tr.ImageFileNamePaths + select a).ToList(); + + if (tBlobs.Count < 1) + throw new MDSParseException("BLOB Error!"); + + // is the currBlob valid for this track, or do we need to increment? + string bString = tBlobs.First(); + + IBlob mdfBlob = null; + + // check for track pregap and create if neccessary + // this is specified in the track extras block + if (track.ExtraBlock.Pregap > 0) + { + CUE.CueTrackType pregapTrackType = CUE.CueTrackType.Audio; + if (tocSynth.Result.TOCItems[1].IsData) + { + if (tocSynth.Result.Session1Format == SessionFormat.Type20_CDXA) + pregapTrackType = CUE.CueTrackType.Mode2_2352; + else if (tocSynth.Result.Session1Format == SessionFormat.Type10_CDI) + pregapTrackType = CUE.CueTrackType.CDI_2352; + else if (tocSynth.Result.Session1Format == SessionFormat.Type00_CDROM_CDDA) + pregapTrackType = CUE.CueTrackType.Mode1_2352; + } + for (int pre = 0; pre < track.ExtraBlock.Pregap; pre++) + { + relMSF++; + + var ss_gap = new CUE.SS_Gap() + { + Policy = IN_DiscMountPolicy, + TrackType = pregapTrackType + }; + disc._Sectors.Add(ss_gap); + + int qRelMSF = pre - Convert.ToInt32(track.ExtraBlock.Pregap); + + //tweak relMSF due to ambiguity/contradiction in yellowbook docs + if (!IN_DiscMountPolicy.CUE_PregapContradictionModeA) + qRelMSF++; + + //setup subQ + byte ADR = 1; //absent some kind of policy for how to set it, this is a safe assumption: + ss_gap.sq.SetStatus(ADR, tocSynth.Result.TOCItems[1].Control); + ss_gap.sq.q_tno = BCD2.FromDecimal(1); + ss_gap.sq.q_index = BCD2.FromDecimal(0); + ss_gap.sq.AP_Timestamp = pre; + ss_gap.sq.Timestamp = qRelMSF; + + //setup subP + ss_gap.Pause = true; + } + // pregap processing completed + } + + + + // create track sectors + long currBlobOffset = track.TrackOffset; + for (long sector = session.StartSector; sector <= session.EndSector; sector++) + { + CUE.SS_Base sBase = null; + + // get the current blob from the BlobIndex + Disc.Blob_RawFile currBlob = BlobIndex[currBlobIndex] as Disc.Blob_RawFile; + long currBlobLength = currBlob.Length; + long currBlobPosition = sector; + if (currBlobPosition == currBlobLength) + currBlobIndex++; + mdfBlob = disc.DisposableResources[currBlobIndex] as Disc.Blob_RawFile; + + int userSector = 2048; + switch (track.SectorSize) + { + case 2448: + sBase = new CUE.SS_2352() + { + Policy = IN_DiscMountPolicy + }; + userSector = 2352; + break; + case 2048: + default: + sBase = new CUE.SS_Mode1_2048() + { + Policy = IN_DiscMountPolicy + }; + userSector = 2048; + break; + + //throw new Exception("Not supported: Sector Size " + track.SectorSize); + } + + // configure blob + sBase.Blob = mdfBlob; + sBase.BlobOffset = currBlobOffset; + + currBlobOffset += track.SectorSize; // userSector; + + // add subchannel data + relMSF++; + BCD2 tno, ino; + + //this should actually be zero. im not sure if this is stored as BCD2 or not + tno = BCD2.FromDecimal(track.TrackNo); + + //these are special values.. I think, taken from this: + //http://www.staff.uni-mainz.de/tacke/scsi/SCSI2-14.html + //the CCD will contain Points as decimal values except for these specially converted decimal values which should stay as BCD. + //Why couldn't they all be BCD? I don't know. I guess because BCD is inconvenient, but only A0 and friends have special meaning. It's confusing. + ino = BCD2.FromDecimal(track.Point); + if (track.Point == 0xA0) ino.BCDValue = 0xA0; + else if (track.Point == 0xA1) ino.BCDValue = 0xA1; + else if (track.Point == 0xA2) ino.BCDValue = 0xA2; + + // get ADR & Control from ADR_Control byte + byte adrc = Convert.ToByte(track.ADR_Control); + var Control = adrc & 0x0F; + var ADR = adrc >> 4; + + var q = new SubchannelQ + { + q_status = SubchannelQ.ComputeStatus(ADR, (EControlQ)(Control & 0xF)), + q_tno = BCD2.FromDecimal(track.Point), + q_index = ino, + AP_Timestamp = disc._Sectors.Count, + Timestamp = relMSF - Convert.ToInt32(track.ExtraBlock.Pregap) + }; + + sBase.sq = q; + + disc._Sectors.Add(sBase); + + } + } + } + + return disc; + } + + } //class MDS_Format +} + + diff --git a/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs b/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs index a9add9cf4e..e4fe3c2f74 100644 --- a/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs +++ b/BizHawk.Emulation.DiscSystem/DiscIdentifier.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; //disc type identification logic @@ -8,7 +9,7 @@ namespace BizHawk.Emulation.DiscSystem public enum DiscType { /// - /// Disc contains audio in track 1. Nothing more can readily be determined + /// Disc contains audio in track 1. This may be a PCFX or PCECD game, but if not it is assumed AudioDisc /// AudioDisc, @@ -38,7 +39,7 @@ namespace BizHawk.Emulation.DiscSystem SegaSaturn, /// - /// Its not clear whether we can ever have enough info to ID a turboCD disc (we're using hashes) + /// PC Engine CD /// TurboCD, @@ -50,7 +51,47 @@ namespace BizHawk.Emulation.DiscSystem /// /// By NEC. /// - PCFX + PCFX, + + /// + /// By Panasonic + /// + Panasonic3DO, + + /// + /// Philips + /// + CDi, + + /// + /// Nintendo Gamecube + /// + GameCube, + + /// + /// Nintendo Wii + /// + Wii, + + /// + /// SNK NeoGeo + /// + NeoGeoCD, + + /// + /// Bandai Playdia + /// + Playdia, + + /// + /// Either CDTV or CD32 (I havent found a reliable way of distinguishing between them yet -asni) + /// + Amiga, + + /// + /// Sega Dreamcast + /// + Dreamcast } public class DiscIdentifier @@ -76,24 +117,26 @@ namespace BizHawk.Emulation.DiscSystem /// public DiscType DetectDiscType() { - // not fully tested yet + // PCFX & TurboCD sometimes (if not alltimes) have audio on track 1 - run these before the AudioDisc detection (asni) if (DetectPCFX()) return DiscType.PCFX; - //check track 1's data type. if it's an audio track, further data-track testing is useless - //furthermore, it's probably senseless (no binary data there to read) - //NOTE: PCE-CD detection goes through here (no good way to detect PCE cd) - if (!_disc.TOC.TOCItems[1].IsData) + if (DetectTurboCD()) + return DiscType.TurboCD; + + //check track 1's data type. if it's an audio track, further data-track testing is useless + //furthermore, it's probably senseless (no binary data there to read) + if (!_disc.TOC.TOCItems[1].IsData) return DiscType.AudioDisc; // if (_dsr.ReadLBA_Mode(_disc.TOC.TOCItems[1].LBA) == 0) // return DiscType.AudioDisc; // sega doesnt put anything identifying in the cdfs volume info. but its consistent about putting its own header here in sector 0 + //asni - this isn't strictly true - SystemIdentifier in volume descriptor has been observed on occasion (see below) if (DetectSegaSaturn()) return DiscType.SegaSaturn; - // not fully tested yet if (DetectMegaCD()) return DiscType.MegaCD; @@ -102,31 +145,79 @@ namespace BizHawk.Emulation.DiscSystem if (DetectPSX()) return DiscType.SonyPSX; - //we dont know how to detect TurboCD. - //an emulator frontend will likely just guess TurboCD if the disc is UnknownFormat - //(we can also have a gameDB!) + if (Detect3DO()) + return DiscType.Panasonic3DO; - var discView = EDiscStreamView.DiscStreamView_Mode1_2048; + if (DetectCDi()) + return DiscType.CDi; + + if (DetectGameCube()) + return DiscType.GameCube; + + if (DetectWii()) + return DiscType.Wii; + + var discView = EDiscStreamView.DiscStreamView_Mode1_2048; if (_disc.TOC.Session1Format == SessionFormat.Type20_CDXA) discView = EDiscStreamView.DiscStreamView_Mode2_Form1_2048; var iso = new ISOFile(); bool isIso = iso.Parse(new DiscStream(_disc, discView, 0)); + if (!isIso) + { + // its much quicker to detect dreamcast from ISO data. Only do this if ISO is not detected + if (DetectDreamcast()) + return DiscType.Dreamcast; + } + + //*** asni - 20171011 - Suggestion: move this to the beginning of the DetectDiscType() method before any longer running lookups? + //its a cheap win for a lot of systems, but ONLY if the iso.Parse() method is quick running (might have to time it) if (isIso) { var appId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].ApplicationIdentifier).TrimEnd('\0', ' '); + var sysId = System.Text.Encoding.ASCII.GetString(iso.VolumeDescriptors[0].SystemIdentifier).TrimEnd('\0', ' '); - //for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields - //but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here - if (appId == "PLAYSTATION") + //for example: PSX magical drop F (JP SLPS_02337) doesn't have the correct iso PVD fields + //but, some PSX games (junky rips) don't have the 'licensed by string' so we'll hope they get caught here + if (appId == "PLAYSTATION") return DiscType.SonyPSX; if (appId == "PSP GAME") return DiscType.SonyPSP; + // in case the appId is not set correctly... + if (iso.Root.Children.Where(a => a.Key == "PSP_GAME").FirstOrDefault().Value as ISODirectoryNode != null) + return DiscType.SonyPSP; - return DiscType.UnknownCDFS; - } + if (sysId == "SEGA SEGASATURN") + return DiscType.SegaSaturn; + + if (sysId.Contains("SEGAKATANA")) + return DiscType.Dreamcast; + + if (sysId == "MEGA_CD") + return DiscType.MegaCD; + + if (sysId == "ASAHI-CDV") + return DiscType.Playdia; + + if (sysId == "CDTV" || sysId == "AMIGA") + return DiscType.Amiga; + foreach (var f in iso.Root.Children) + if (f.Key.ToLower().Contains("cd32")) + return DiscType.Amiga; + + // NeoGeoCD Check + var absTxt = iso.Root.Children.Where(a => a.Key.Contains("ABS.TXT")).ToList(); + if (absTxt.Count > 0) + { + if (SectorContains("abstracted by snk", Convert.ToInt32(absTxt.First().Value.Offset))) + return DiscType.NeoGeoCD; + } + + + return DiscType.UnknownCDFS; + } return DiscType.UnknownFormat; } @@ -165,13 +256,87 @@ namespace BizHawk.Emulation.DiscSystem t++) { var track = _disc.TOC.TOCItems[t]; - if (track.IsData && StringAt("PC-FX:Hu_CD-ROM", 0, track.LBA)) + //asni - this search is less specific - turns out there are discs where 'Hu:' is not present + if (track.IsData && SectorContains("pc-fx", track.LBA)) return true; } return false; } - private byte[] ReadSectorCached(int lba) + //asni 20171011 - this ONLY works if a valid cuefile/ccd is passed into DiscIdentifier. + //if an .iso is presented, the internally manufactured cue data does not work - possibly something to do with + //track 01 being Audio. Not tested, but presumably PCFX has the same issue + bool DetectTurboCD() + { + var toc = _disc.TOC; + for (int t = toc.FirstRecordedTrackNumber; + t <= toc.LastRecordedTrackNumber; + t++) + { + var track = _disc.TOC.TOCItems[t]; + //asni - pcfx games also contain the 'PC Engine' string + if ((track.IsData && SectorContains("pc engine", track.LBA + 1) && !SectorContains("pc-fx", track.LBA + 1))) + return true; + } + return false; + } + + bool Detect3DO() + { + var toc = _disc.TOC; + for (int t = toc.FirstRecordedTrackNumber; + t <= toc.LastRecordedTrackNumber; + t++) + { + var track = _disc.TOC.TOCItems[t]; + if (track.IsData && SectorContains("iamaduckiamaduck", track.LBA)) + return true; + } + return false; + } + + //asni - slightly longer running than the others due to its brute-force nature. Should run later in the method + bool DetectDreamcast() + { + for (int i = 0; i < 1000; i++) + { + if (SectorContains("segakatana", i)) + return true; + } + + return false; + } + + bool DetectCDi() + { + return StringAt("CD-RTOS", 8, 16); + } + + bool DetectGameCube() + { + var data = ReadSectorCached(0); + if (data == null) return false; + byte[] magic = data.Skip(28).Take(4).ToArray(); + string hexString = ""; + foreach (var b in magic) + hexString += b.ToString("X2"); + + return hexString == "C2339F3D"; + } + + bool DetectWii() + { + var data = ReadSectorCached(0); + if (data == null) return false; + byte[] magic = data.Skip(24).Take(4).ToArray(); + string hexString = ""; + foreach (var b in magic) + hexString += b.ToString("X2"); + + return hexString == "5D1C9EA3"; + } + + private byte[] ReadSectorCached(int lba) { //read it if we dont have it cached //we wont be caching very much here, it's no big deal @@ -197,5 +362,12 @@ namespace BizHawk.Emulation.DiscSystem Buffer.BlockCopy(data, n, cmp2, 0, cmp.Length); return System.Linq.Enumerable.SequenceEqual(cmp, cmp2); } + + private bool SectorContains(string s, int lba = 0) + { + var data = ReadSectorCached(lba); + if (data == null) return false; + return System.Text.Encoding.ASCII.GetString(data).ToLower().Contains(s.ToLower()); + } } } \ No newline at end of file diff --git a/BizHawk.Emulation.DiscSystem/DiscMountJob.cs b/BizHawk.Emulation.DiscSystem/DiscMountJob.cs index dab08a7dbf..7282d00f74 100644 --- a/BizHawk.Emulation.DiscSystem/DiscMountJob.cs +++ b/BizHawk.Emulation.DiscSystem/DiscMountJob.cs @@ -187,6 +187,11 @@ namespace BizHawk.Emulation.DiscSystem CCD_Format ccdLoader = new CCD_Format(); OUT_Disc = ccdLoader.LoadCCDToDisc(IN_FromPath, IN_DiscMountPolicy); } + else if (ext == ".mds") + { + MDS_Format mdsLoader = new MDS_Format(); + OUT_Disc = mdsLoader.LoadMDSToDisc(IN_FromPath, IN_DiscMountPolicy); + } DONE: diff --git a/BizHawk.Installer/BizHawkFiles.wxs b/BizHawk.Installer/BizHawkFiles.wxs index aa1e5325e5..e3f3e641da 100644 --- a/BizHawk.Installer/BizHawkFiles.wxs +++ b/BizHawk.Installer/BizHawkFiles.wxs @@ -66,9 +66,6 @@ - - - @@ -560,9 +557,6 @@ - - - @@ -847,4 +841,4 @@ - \ No newline at end of file + diff --git a/BizHawk.Installer/BizHawkInstall.wxs b/BizHawk.Installer/BizHawkInstall.wxs index 54d42bfda9..5d6c3753f6 100644 --- a/BizHawk.Installer/BizHawkInstall.wxs +++ b/BizHawk.Installer/BizHawkInstall.wxs @@ -50,7 +50,6 @@ - @@ -79,7 +78,6 @@ - @@ -365,4 +363,4 @@ - \ No newline at end of file + diff --git a/Building Other Solutions.txt b/Building Other Solutions.txt index 868aaf0d2a..fc6740b8a9 100644 --- a/Building Other Solutions.txt +++ b/Building Other Solutions.txt @@ -1,8 +1,6 @@ Besides the main Bizhawk.sln, there are a number of other projects, each with its own build method. To develop Bizhawk, you do not need to build these other projects, as they are included prebuild in SVN. You need only build them if you want to modify the cores themselves. -EMU7800: Load EMU7800/EMU7800.sln; builds as .NET 4.0. Does file automatically copy to appropriate folder?? - genplus-gx: Load genplus-gx/libretro/msvc/msvc-2010.sln; builds as VC++ (VC10). Output dll automatically copies to appropriate folder. waterbox: check the waterbox/ folder for instructions on the alpha waterbox builds. diff --git a/Dist/BuildAndPackage.bat b/Dist/BuildAndPackage.bat index f259b92b64..616b39d95a 100644 --- a/Dist/BuildAndPackage.bat +++ b/Dist/BuildAndPackage.bat @@ -35,7 +35,7 @@ rem explicitly list the OK ones here as individual copies. until then.... copy *.dll dll rem Now, we're about to zip and then unzip. Why, you ask? Because that's just the way this evolved. -..\dist\zip.exe -X -r ..\Dist\%NAME% EmuHawk.exe DiscoHawk.exe defctrl.json dll shaders gamedb Tools NES\Palettes Lua Gameboy\Palettes -x *.pdb -x *.lib -x *.pgd -x *.ipdb -x *.iobj -x *.exp -x dll\libsneshawk-64*.exe -x *.ilk -x dll\gpgx.elf -x dll\miniclient.* +..\dist\zip.exe -X -r ..\Dist\%NAME% EmuHawk.exe EmuHawk.exe.config DiscoHawk.exe DiscoHawk.exe.config defctrl.json dll shaders gamedb Tools NES\Palettes Lua Gameboy\Palettes -x *.pdb -x *.lib -x *.pgd -x *.ipdb -x *.iobj -x *.exp -x dll\libsneshawk-64*.exe -x *.ilk -x dll\gpgx.elf -x dll\miniclient.* cd ..\Dist .\unzip.exe %NAME% -d temp diff --git a/EMU7800/Class1.cs b/EMU7800/Class1.cs deleted file mode 100644 index 1b18b6adf6..0000000000 --- a/EMU7800/Class1.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace EMU7800 -{ - public class Class1 - { - } -} diff --git a/EMU7800/Core/AddressSpace.cs b/EMU7800/Core/AddressSpace.cs deleted file mode 100644 index 17b8b44f00..0000000000 --- a/EMU7800/Core/AddressSpace.cs +++ /dev/null @@ -1,154 +0,0 @@ -/* - * AddressSpace.cs - * - * The class representing the memory map or address space of a machine. - * - * Copyright © 2003, 2011 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class AddressSpace - { - public MachineBase M { get; private set; } - - readonly int AddrSpaceShift; - readonly int AddrSpaceSize; - readonly int AddrSpaceMask; - - readonly int PageShift; - readonly int PageSize; - - readonly IDevice[] MemoryMap; - IDevice Snooper; - - public byte DataBusState { get; private set; } - - public override string ToString() - { - return "AddressSpace"; - } - - public byte this[ushort addr] - { - get - { - if (Snooper != null) - { - // here DataBusState is just facilitating a dummy read to the snooper device - // the read operation may have important side effects within the device - DataBusState = Snooper[addr]; - } - var pageno = (addr & AddrSpaceMask) >> PageShift; - var dev = MemoryMap[pageno]; - DataBusState = dev[addr]; - return DataBusState; - } - set - { - DataBusState = value; - if (Snooper != null) - { - Snooper[addr] = DataBusState; - } - var pageno = (addr & AddrSpaceMask) >> PageShift; - var dev = MemoryMap[pageno]; - dev[addr] = DataBusState; - } - } - - public void Map(ushort basea, ushort size, IDevice device) - { - if (device == null) - throw new ArgumentNullException("device"); - - for (int addr = basea; addr < basea + size; addr += PageSize) - { - var pageno = (addr & AddrSpaceMask) >> PageShift; - MemoryMap[pageno] = device; - } - - LogDebug("{0}: Mapped {1} to ${2:x4}:${3:x4}", this, device, basea, basea + size - 1); - } - - public void Map(ushort basea, ushort size, Cart cart) - { - if (cart == null) - throw new ArgumentNullException("cart"); - - cart.Attach(M); - var device = (IDevice)cart; - if (cart.RequestSnooping) - { - Snooper = device; - } - Map(basea, size, device); - } - - #region Constructors - - private AddressSpace() - { - } - - public AddressSpace(MachineBase m, int addrSpaceShift, int pageShift) - { - if (m == null) - throw new ArgumentNullException("m"); - - M = m; - - AddrSpaceShift = addrSpaceShift; - AddrSpaceSize = 1 << AddrSpaceShift; - AddrSpaceMask = AddrSpaceSize - 1; - - PageShift = pageShift; - PageSize = 1 << PageShift; - - MemoryMap = new IDevice[1 << addrSpaceShift >> PageShift]; - IDevice nullDev = new NullDevice(M); - for (var pageno=0; pageno < MemoryMap.Length; pageno++) - { - MemoryMap[pageno] = nullDev; - } - } - - #endregion - - #region Serialization Members - - public AddressSpace(DeserializationContext input, MachineBase m, int addrSpaceShift, int pageShift) : this(m, addrSpaceShift, pageShift) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - DataBusState = input.ReadByte(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(DataBusState); - } - - #endregion - - #region Helpers - - [System.Diagnostics.Conditional("DEBUG")] - void LogDebug(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Bios7800.cs b/EMU7800/Core/Bios7800.cs deleted file mode 100644 index c02b3a648f..0000000000 --- a/EMU7800/Core/Bios7800.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * BIOS7800.cs - * - * The BIOS of the Atari 7800. - * - * Copyright © 2004 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class Bios7800 : IDevice - { - readonly byte[] ROM; - readonly ushort Mask; - - public ushort Size { get { return (ushort)ROM.Length; } } - - public void Reset() { } - - public byte this[ushort addr] - { - get { return ROM[addr & Mask]; } - set { } - } - - public Bios7800(byte[] rom) - { - if (rom == null) - throw new ArgumentNullException("rom"); - if (rom.Length != 4096 && rom.Length != 16384) - throw new ArgumentException("ROM size not 4096 or 16384", "rom"); - - ROM = rom; - Mask = (ushort)ROM.Length; - Mask--; - } - - #region Serialization Members - - public Bios7800(DeserializationContext input) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - ROM = input.ReadExpectedBytes(4096, 16384); - - Mask = (ushort)ROM.Length; - Mask--; - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/BufferElement.cs b/EMU7800/Core/BufferElement.cs deleted file mode 100644 index c339eacc7a..0000000000 --- a/EMU7800/Core/BufferElement.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace EMU7800.Core -{ - /* - * why this sucks: - * A read costs 3 shifts and an or. A write costs 2 shifts. Additional shifts are - * needed elsewhere to figure out which item in a BufferElement[] to access. Because - * the encapsulation is for a BufferElement and not a whole array of them, code elsewhere - * is gunked up with 'BufferElement.SIZE' shifts. If the 32 bit "alias" was actually used, - * there might be some purpose to this code: but it's only used for a ZeroMemory() - * replacement. Every use of BufferElement in the code is a BufferElement[] used as a gunked - * up replacement for a byte[]. - * - * A small speed increase was observed hacking this out; but my motivation was more about cleaness - * and stomping out bad ideas. - */ - - /* - /// - /// Frames are composed of s, - /// that group bytes into machine words for efficient array processing. - /// Bytes are packed in logical little endian order. - /// - public struct BufferElement - { - /// - /// The number of bytes contained within a . - /// - public const int SIZE = 4; // 2^SHIFT - - /// - /// The mask value applied against a byte array index to access the individual bytes within a . - /// - public const int MASK = 3; // SIZE - 1 - - /// - /// The left shift value to convert a byte array index to a array index. - /// - public const int SHIFT = 2; - - uint _data; - - /// - /// A convenience accessor for reading/writing individual bytes within this . - /// - /// - public byte this[int offset] - { - get - { - var i = (offset & MASK) << 3; - return (byte)(_data >> i); - } - set - { - var i = (offset & MASK) << 3; - var d = (uint)value << i; - var di = (uint)0xff << i; - _data = _data & ~di | d; - } - } - - /// - /// Zeros out all bytes of this . - /// - public void ClearAll() - { - _data = 0; - } - } - */ -} diff --git a/EMU7800/Core/Cart.cs b/EMU7800/Core/Cart.cs deleted file mode 100644 index bd0e6a2aea..0000000000 --- a/EMU7800/Core/Cart.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Cart.cs - * - * An abstraction of a game cart. Attributable to Kevin Horton's Bankswitching - * document, the Stella source code, and Eckhard Stolberg's 7800 Bankswitching Guide. - * - * Copyright © 2003, 2004, 2010, 2011 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public abstract class Cart : IDevice - { - static int _multicartBankSelector; - - protected MachineBase M { get; set; } - protected internal byte[] ROM { get; set; } - - #region IDevice Members - - public virtual void Reset() { } - - public abstract byte this[ushort addr] { get; set; } - - #endregion - - public virtual void Attach(MachineBase m) - { - if (m == null) - throw new ArgumentNullException("m"); - if (M != null && M != m) - throw new InvalidOperationException("Cart already attached to a different machine."); - M = m; - } - - public virtual void StartFrame() - { - } - - public virtual void EndFrame() - { - } - - protected internal virtual bool RequestSnooping - { - get { return false; } - } - - /// - /// Creates an instance of the specified cart. - /// - /// - /// - /// Specified CartType is unexpected. - public static Cart Create(byte[] romBytes, CartType cartType) - { - if (cartType == CartType.None) - { - switch (romBytes.Length) - { - case 2048: - cartType = CartType.A2K; - break; - case 4096: - cartType = CartType.A4K; - break; - case 8192: - cartType = CartType.A8K; - break; - case 16384: - cartType = CartType.A16K; - break; - case 32768: - cartType = CartType.A32K; - break; - } - } - - switch (cartType) - { - case CartType.A2K: return new CartA2K(romBytes); - case CartType.A4K: return new CartA4K(romBytes); - case CartType.A8K: return new CartA8K(romBytes); - case CartType.A8KR: return new CartA8KR(romBytes); - case CartType.A16K: return new CartA16K(romBytes); - case CartType.A16KR: return new CartA16KR(romBytes); - case CartType.DC8K: return new CartDC8K(romBytes); - case CartType.PB8K: return new CartPB8K(romBytes); - case CartType.TV8K: return new CartTV8K(romBytes); - case CartType.CBS12K: return new CartCBS12K(romBytes); - case CartType.A32K: return new CartA32K(romBytes); - case CartType.A32KR: return new CartA32KR(romBytes); - case CartType.MN16K: return new CartMN16K(romBytes); - case CartType.DPC: return new CartDPC(romBytes); - case CartType.M32N12K: return new CartA2K(romBytes, _multicartBankSelector++); - case CartType.A7808: return new Cart7808(romBytes); - case CartType.A7816: return new Cart7816(romBytes); - case CartType.A7832P: return new Cart7832P(romBytes); - case CartType.A7832: return new Cart7832(romBytes); - case CartType.A7848: return new Cart7848(romBytes); - case CartType.A78SGP: return new Cart78SGP(romBytes); - case CartType.A78SG: return new Cart78SG(romBytes, false); - case CartType.A78SGR: return new Cart78SG(romBytes, true); - case CartType.A78S9: return new Cart78S9(romBytes); - case CartType.A78S4: return new Cart78S4(romBytes, false); - case CartType.A78S4R: return new Cart78S4(romBytes, true); - case CartType.A78AB: return new Cart78AB(romBytes); - case CartType.A78AC: return new Cart78AC(romBytes); - default: - throw new Emu7800Exception("Unexpected CartType: " + cartType); - } - } - - protected void LoadRom(byte[] romBytes, int multicartBankSize, int multicartBankNo) - { - if (romBytes == null) - throw new ArgumentNullException("romBytes"); - - ROM = new byte[multicartBankSize]; - Buffer.BlockCopy(romBytes, multicartBankSize*multicartBankNo, ROM, 0, multicartBankSize); - } - - protected void LoadRom(byte[] romBytes, int minSize) - { - if (romBytes == null) - throw new ArgumentNullException("romBytes"); - - if (romBytes.Length >= minSize) - { - ROM = romBytes; - } - else - { - ROM = new byte[minSize]; - Buffer.BlockCopy(romBytes, 0, ROM, 0, romBytes.Length); - } - } - - protected void LoadRom(byte[] romBytes) - { - LoadRom(romBytes, romBytes.Length); - } - - protected Cart() - { - } - - #region Serialization Members - - protected Cart(DeserializationContext input) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - } - - public virtual void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart7808.cs b/EMU7800/Core/Cart7808.cs deleted file mode 100644 index 7fa1c277bc..0000000000 --- a/EMU7800/Core/Cart7808.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 non-bankswitched 8KB cartridge - /// - public sealed class Cart7808 : Cart - { - // - // Cart Format Mapping to ROM Address Space - // 0x0000:0x2000 0xE000:0x2000 (repeated downward to 0x4000) - // - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[addr & 0x1fff]; } - set { } - } - - #endregion - - private Cart7808() - { - } - - public Cart7808(byte[] romBytes) - { - LoadRom(romBytes, 0x2000); - } - - #region Serialization Members - - public Cart7808(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x2000), 0x2000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart7816.cs b/EMU7800/Core/Cart7816.cs deleted file mode 100644 index fe93e39585..0000000000 --- a/EMU7800/Core/Cart7816.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 non-bankswitched 16KB cartridge - /// - public sealed class Cart7816 : Cart - { - // - // Cart Format Mapping to ROM Address Space - // 0x0000:0x4000 0xC000:0x4000 (repeated downward to 0x4000) - // - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[addr & 0x3fff]; } - set { } - } - - #endregion - - private Cart7816() - { - } - - public Cart7816(byte[] romBytes) - { - LoadRom(romBytes, 0x4000); - } - - #region Serialization Members - - public Cart7816(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x4000), 0x4000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart7832.cs b/EMU7800/Core/Cart7832.cs deleted file mode 100644 index 601e2f83f8..0000000000 --- a/EMU7800/Core/Cart7832.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 non-bankswitched 32KB cartridge - /// - public sealed class Cart7832 : Cart - { - // - // Cart Format Mapping to ROM Address Space - // 0x0000:0x8000 0x8000:0x8000 (repeated downward until 0x4000) - // - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[addr & 0x7fff]; } - set { } - } - - #endregion - - private Cart7832() - { - } - - public Cart7832(byte[] romBytes) - { - LoadRom(romBytes, 0x8000); - } - - #region Serialization Members - - public Cart7832(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x8000), 0x8000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart7832P.cs b/EMU7800/Core/Cart7832P.cs deleted file mode 100644 index c3a24be76e..0000000000 --- a/EMU7800/Core/Cart7832P.cs +++ /dev/null @@ -1,90 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 non-bankswitched 32KB cartridge w/Pokey - /// - public sealed class Cart7832P : Cart - { - // - // Cart Format Mapping to ROM Address Space - // 0x4000:0x4000 Pokey - // 0x0000:0x8000 0x8000:0x8000 - // - PokeySound _pokeySound; - - #region IDevice Members - - public override void Reset() - { - base.Reset(); - if (_pokeySound != null) - _pokeySound.Reset(); - } - - public override byte this[ushort addr] - { - get - { - return ((addr & 0xF000) == 0x4000 && _pokeySound != null) ? _pokeySound.Read(addr) : ROM[addr & 0x7fff]; - } - set - { - if ((addr & 0xF000) == 0x4000 && _pokeySound != null) - _pokeySound.Update(addr, value); - } - } - - #endregion - - public override void Attach(MachineBase m) - { - base.Attach(m); - if (_pokeySound == null) - _pokeySound = new PokeySound(M); - } - - public override void StartFrame() - { - if (_pokeySound != null) - _pokeySound.StartFrame(); - } - - public override void EndFrame() - { - if (_pokeySound != null) - _pokeySound.EndFrame(); - } - - private Cart7832P() - { - } - - public Cart7832P(byte[] romBytes) - { - LoadRom(romBytes, 0x8000); - } - - #region Serialization Members - - public Cart7832P(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x8000), 0x8000); - _pokeySound = input.ReadOptionalPokeySound(m); - } - - public override void GetObjectData(SerializationContext output) - { - if (_pokeySound == null) - throw new Emu7800SerializationException("Cart7832P must be attached before serialization."); - - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.WriteOptional(_pokeySound); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart7848.cs b/EMU7800/Core/Cart7848.cs deleted file mode 100644 index b9536da7eb..0000000000 --- a/EMU7800/Core/Cart7848.cs +++ /dev/null @@ -1,50 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 non-bankswitched 48KB cartridge - /// - public sealed class Cart7848 : Cart - { - // - // Cart Format Mapping to ROM Address Space - // 0x0000:0xc000 0x4000:0xc000 - // - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[addr - 0x4000]; } - set { } - } - - #endregion - - private Cart7848() - { - } - - public Cart7848(byte[] romBytes) - { - LoadRom(romBytes, 0xc000); - } - - #region Serialization Members - - public Cart7848(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0xc000), 0xc000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart78AB.cs b/EMU7800/Core/Cart78AB.cs deleted file mode 100644 index 6b4b6b53a7..0000000000 --- a/EMU7800/Core/Cart78AB.cs +++ /dev/null @@ -1,67 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 Absolute bankswitched cartridge - /// - public sealed class Cart78AB : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank0: 0x00000:0x4000 - // Bank1: 0x04000:0x4000 0x4000:0x4000 Bank0-1 (0 on startup) - // Bank2: 0x08000:0x4000 0x8000:0x4000 Bank2 - // Bank3: 0x0c000:0x4000 0xc000:0x4000 Bank3 - // - readonly int[] Bank = new int[4]; - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[ (Bank[addr >> 14] << 14) | (addr & 0x3fff) ]; } - set - { - if ((addr >> 14) == 2) - { - Bank[1] = (value - 1) & 1; - } - } - } - - #endregion - - private Cart78AB() - { - } - - public Cart78AB(byte[] romBytes) - { - Bank[1] = 0; - Bank[2] = 2; - Bank[3] = 3; - LoadRom(romBytes, 0x10000); - } - - #region Serialization Members - - public Cart78AB(DeserializationContext input, MachineBase m) : base(input) - { - var version = input.CheckVersion(1, 2); - LoadRom(input.ReadBytes()); - Bank = input.ReadIntegers(4); - if (version == 1) - input.ReadInt32(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(2); - output.Write(ROM); - output.Write(Bank); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart78AC.cs b/EMU7800/Core/Cart78AC.cs deleted file mode 100644 index fcf854c8b5..0000000000 --- a/EMU7800/Core/Cart78AC.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 Activision bankswitched cartridge - /// - public sealed class Cart78AC : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank0 : 0x00000:0x2000 - // Bank1 : 0x02000:0x2000 - // Bank2 : 0x04000:0x2000 0x4000:0x2000 Bank13 - // Bank3 : 0x06000:0x2000 0x6000:0x2000 Bank12 - // Bank4 : 0x08000:0x2000 0x8000:0x2000 Bank15 - // Bank5 : 0x0a000:0x2000 0xa000:0x2000 Bank(2*n) n in [0-7], n=0 on startup - // Bank6 : 0x0c000:0x2000 0xc000:0x2000 Bank(2*n+1) - // Bank7 : 0x0e000:0x2000 0xe000:0x2000 Bank14 - // Bank8 : 0x10000:0x2000 - // Bank9 : 0x12000:0x2000 - // Bank10: 0x14000:0x2000 - // Bank11: 0x16000:0x2000 - // Bank12: 0x18000:0x2000 - // Bank13: 0x1a000:0x2000 - // Bank14: 0x1c000:0x2000 - // Bank15: 0x1e000:0x2000 - // - // Banks are actually 16KB, but handled as 8KB for implementation ease. - // - readonly int[] Bank = new int[8]; - - #region IDevice Members - - public override byte this[ushort addr] - { - get - { - return ROM[ (Bank[addr >> 13] << 13) | (addr & 0x1fff) ]; - } - set - { - if ((addr & 0xfff0) == 0xff80) - { - Bank[5] = (addr & 7) << 1; - Bank[6] = Bank[5] + 1; - } - } - } - - #endregion - - private Cart78AC() - { - } - - public Cart78AC(byte[] romBytes) - { - Bank[2] = 13; - Bank[3] = 12; - Bank[4] = 15; - Bank[5] = 0; - Bank[6] = 1; - Bank[7] = 14; - LoadRom(romBytes, 0x20000); - } - - #region Serialization Members - - public Cart78AC(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadBytes()); - Bank = input.ReadIntegers(8); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(Bank); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart78S4.cs b/EMU7800/Core/Cart78S4.cs deleted file mode 100644 index 7920f19713..0000000000 --- a/EMU7800/Core/Cart78S4.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 SuperGame S4 bankswitched cartridge - /// - public sealed class Cart78S4 : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank0: 0x00000:0x4000 - // Bank1: 0x04000:0x4000 0x4000:0x4000 Bank2 - // Bank2: 0x08000:0x4000 0x8000:0x4000 Bank0 (0 on startup) - // Bank3: 0x0c000:0x4000 0xc000:0x4000 Bank3 - // - // Banks 0-3 are the same as banks 4-7 - // - readonly byte[] RAM; - readonly int[] Bank = new int[4]; - - #region IDevice Members - - public override byte this[ushort addr] - { - get - { - if (RAM != null && addr >= 0x6000 && addr <= 0x7fff) - { - return RAM[addr & 0x1fff]; - } - return ROM[(Bank[addr >> 14] << 14) | (addr & 0x3fff)]; - } - set - { - if (RAM != null && addr >= 0x6000 && addr <= 0x7fff) - { - RAM[addr & 0x1fff] = value; - } - else if ((addr >> 14) == 2) - { - Bank[2] = value & 3; - } - } - } - - #endregion - - private Cart78S4() - { - } - - public Cart78S4(byte[] romBytes, bool needRAM) - { - if (needRAM) - { - RAM = new byte[0x2000]; - } - - LoadRom(romBytes, 0xffff); - - Bank[1] = 2; - Bank[2] = 0; - Bank[3] = 3; - } - - #region Serialization Members - - public Cart78S4(DeserializationContext input, MachineBase m) : base(input) - { - var version = input.CheckVersion(1, 2); - LoadRom(input.ReadBytes()); - Bank = input.ReadIntegers(4); - if (version == 1) - input.ReadInt32(); - RAM = input.ReadOptionalBytes(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(2); - output.Write(ROM); - output.Write(Bank); - output.WriteOptional(RAM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart78S9.cs b/EMU7800/Core/Cart78S9.cs deleted file mode 100644 index 63b7ff0394..0000000000 --- a/EMU7800/Core/Cart78S9.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 SuperGame S9 bankswitched cartridge - /// - public sealed class Cart78S9 : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank0: 0x00000:0x4000 - // Bank1: 0x04000:0x4000 0x4000:0x4000 Bank0 - // Bank2: 0x08000:0x4000 0x8000:0x4000 Bank0-8 (1 on startup) - // Bank3: 0x0c000:0x4000 0xc000:0x4000 Bank8 - // Bank4: 0x10000:0x4000 - // Bank5: 0x14000:0x4000 - // Bank6: 0x18000:0x4000 - // Bank7: 0x1c000:0x4000 - // Bank8: 0x20000:0x4000 - // - readonly int[] Bank = new int[4]; - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[ (Bank[addr >> 14] << 14) | (addr & 0x3fff) ]; } - set - { - if ((addr >> 14) == 2 && value < 8) - { - Bank[2] = (value + 1); - } - } - } - - #endregion - - private Cart78S9() - { - } - - public Cart78S9(byte[] romBytes) - { - Bank[1] = 0; - Bank[2] = 1; - Bank[3] = 8; - LoadRom(romBytes, 0x24000); - } - - #region Serialization Members - - public Cart78S9(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadBytes()); - Bank = input.ReadIntegers(4); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(Bank); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart78SG.cs b/EMU7800/Core/Cart78SG.cs deleted file mode 100644 index 71dcdcfb64..0000000000 --- a/EMU7800/Core/Cart78SG.cs +++ /dev/null @@ -1,94 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 SuperGame bankswitched cartridge - /// - public sealed class Cart78SG : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank0: 0x00000:0x4000 - // Bank1: 0x04000:0x4000 0x4000:0x4000 Bank6 - // Bank2: 0x08000:0x4000 0x8000:0x4000 Bank0-7 (0 on startup) - // Bank3: 0x0c000:0x4000 0xc000:0x4000 Bank7 - // Bank4: 0x10000:0x4000 - // Bank5: 0x14000:0x4000 - // Bank6: 0x18000:0x4000 - // Bank7: 0x1c000:0x4000 - // - readonly int[] Bank = new int[4]; - readonly byte[] RAM; - - #region IDevice Members - - public override byte this[ushort addr] - { - get - { - var bankNo = addr >> 14; - if (RAM != null && bankNo == 1) - { - return RAM[addr & 0x3fff]; - } - return ROM[ (Bank[bankNo] << 14) | (addr & 0x3fff) ]; - } - set - { - var bankNo = addr >> 14; - if (bankNo == 2) - { - Bank[2] = value & 7; - } - else if (RAM != null && bankNo == 1) - { - RAM[addr & 0x3fff] = value; - } - } - } - - #endregion - - private Cart78SG() - { - } - - public Cart78SG(byte[] romBytes, bool needRAM) - { - if (needRAM) - { - // This works for titles that use 8KB instead of 16KB - RAM = new byte[0x4000]; - } - - Bank[1] = 6; - Bank[2] = 0; - Bank[3] = 7; - - LoadRom(romBytes, 0x20000); - } - - #region Serialization Members - - public Cart78SG(DeserializationContext input, MachineBase m) : base(input) - { - var version = input.CheckVersion(1, 2); - LoadRom(input.ReadBytes()); - Bank = input.ReadIntegers(4); - if (version == 1) - input.ReadInt32(); - RAM = input.ReadOptionalBytes(0x4000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(2); - output.Write(ROM); - output.Write(Bank); - output.WriteOptional(RAM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/Cart78SGP.cs b/EMU7800/Core/Cart78SGP.cs deleted file mode 100644 index 65feda2f84..0000000000 --- a/EMU7800/Core/Cart78SGP.cs +++ /dev/null @@ -1,118 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari 7800 SuperGame bankswitched cartridge w/Pokey - /// - public sealed class Cart78SGP : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank0: 0x00000:0x4000 - // Bank1: 0x04000:0x4000 0x4000:0x4000 Pokey - // Bank2: 0x08000:0x4000 0x8000:0x4000 Bank0-7 (0 on startup) - // Bank3: 0x0c000:0x4000 0xc000:0x4000 Bank7 - // Bank4: 0x10000:0x4000 - // Bank5: 0x14000:0x4000 - // Bank6: 0x18000:0x4000 - // Bank7: 0x1c000:0x4000 - // - readonly int[] _bank = new int[4]; - PokeySound _pokeySound; - - #region IDevice Members - - public override void Reset() - { - base.Reset(); - if (_pokeySound != null) - _pokeySound.Reset(); - } - - public override byte this[ushort addr] - { - get - { - var bankNo = addr >> 14; - switch (bankNo) - { - case 1: - return (_pokeySound != null) ? _pokeySound.Read(addr) : (byte)0; - default: - return ROM[(_bank[bankNo] << 14) | (addr & 0x3fff)]; - } - } - set - { - var bankNo = addr >> 14; - switch (bankNo) - { - case 1: - if (_pokeySound != null) - _pokeySound.Update(addr, value); - break; - case 2: - _bank[2] = value & 7; - break; - } - } - } - - #endregion - - public override void Attach(MachineBase m) - { - base.Attach(m); - if (_pokeySound == null) - _pokeySound = new PokeySound(M); - } - - public override void StartFrame() - { - if (_pokeySound != null) - _pokeySound.StartFrame(); - } - - public override void EndFrame() - { - if (_pokeySound != null) - _pokeySound.EndFrame(); - } - - private Cart78SGP() - { - } - - public Cart78SGP(byte[] romBytes) - { - _bank[2] = 0; - _bank[3] = 7; - - LoadRom(romBytes, 0x20000); - } - - #region Serialization Members - - public Cart78SGP(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadBytes()); - _bank = input.ReadIntegers(4); - _pokeySound = input.ReadOptionalPokeySound(m); - } - - public override void GetObjectData(SerializationContext output) - { - if (_pokeySound == null) - throw new Emu7800SerializationException("Cart78SGP must be attached before serialization."); - - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(_bank); - output.WriteOptional(_pokeySound); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA16K.cs b/EMU7800/Core/CartA16K.cs deleted file mode 100644 index 69bcc68700..0000000000 --- a/EMU7800/Core/CartA16K.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 16KB bankswitched carts - /// - public sealed class CartA16K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x1ff9-0x1ff9 - // Bank2: 0x1000:0x1000 - // Bank3: 0x2000:0x1000 - // Bank4: 0x3000:0x1000 - // - ushort BankBaseAddr; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 0; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - UpdateBank(addr); - } - } - - #endregion - - private CartA16K() - { - } - - public CartA16K(byte[] romBytes) - { - LoadRom(romBytes, 0x4000); - Bank = 0; - } - - void UpdateBank(ushort addr) - { - if (addr < 0x0ff6 || addr > 0x0ff9) - {} - else - { - Bank = addr - 0x0ff6; - } - } - - #region Serialization Members - - public CartA16K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x4000), 0x4000); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA16KR.cs b/EMU7800/Core/CartA16KR.cs deleted file mode 100644 index cd5f307bce..0000000000 --- a/EMU7800/Core/CartA16KR.cs +++ /dev/null @@ -1,100 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 16KB bankswitched carts with 128 bytes of RAM - /// - public sealed class CartA16KR : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x1ff9-0x1ff9 - // Bank2: 0x1000:0x1000 - // Bank3: 0x2000:0x1000 - // Bank4: 0x3000:0x1000 - // Shadows ROM - // 0x1000:0x0080 RAM write port - // 0x1080:0x0080 RAM read port - // - ushort BankBaseAddr; - readonly byte[] RAM; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 0; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - if (addr < 0x0100 && addr >= 0x0080) - { - return RAM[addr & 0x7f]; - } - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - if (addr < 0x0080) - { - RAM[addr & 0x7f] = value; - return; - } - UpdateBank(addr); - } - } - - #endregion - - private CartA16KR() - { - } - - public CartA16KR(byte[] romBytes) - { - LoadRom(romBytes, 0x4000); - Bank = 0; - RAM = new byte[0x80]; - } - - void UpdateBank(ushort addr) - { - if (addr < 0x0ff6 || addr > 0x0ff9) - {} - else - { - Bank = addr - 0x0ff6; - } - } - - #region Serialization Members - - public CartA16KR(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x4000), 0x4000); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA2K.cs b/EMU7800/Core/CartA2K.cs deleted file mode 100644 index 14674c4138..0000000000 --- a/EMU7800/Core/CartA2K.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 2KB carts (no bankswitching) - /// - public sealed class CartA2K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // 0x0000:0x0800 0x1000:0x0800 - // 0x1800:0x0800 (1st 2k bank repeated) - // - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return ROM[addr & 0x07ff]; } - set { } - } - - #endregion - - private CartA2K() - { - } - - public CartA2K(byte[] romBytes) - { - LoadRom(romBytes, 0x0800); - } - - public CartA2K(byte[] romBytes, int multicartBankSelector) - { - LoadRom(romBytes, 0x800, multicartBankSelector & 0x1f); - } - - #region Serialization Members - - public CartA2K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x0800), 0x0800); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA32K.cs b/EMU7800/Core/CartA32K.cs deleted file mode 100644 index d3140ac915..0000000000 --- a/EMU7800/Core/CartA32K.cs +++ /dev/null @@ -1,88 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 32KB bankswitched carts - /// - public sealed class CartA32K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x0ff4-0x0ffc - // Bank2: 0x1000:0x1000 - // Bank3: 0x2000:0x1000 - // Bank4: 0x3000:0x1000 - // Bank5: 0x4000:0x1000 - // Bank6: 0x5000:0x1000 - // Bank7: 0x6000:0x1000 - // Bank8: 0x7000:0x1000 - // - ushort BankBaseAddr; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 7; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - UpdateBank(addr); - } - } - - #endregion - - private CartA32K() - { - } - - public CartA32K(byte[] romBytes) - { - LoadRom(romBytes, 0x8000); - Bank = 7; - } - - void UpdateBank(ushort addr) - { - if (addr < 0x0ffc && addr >= 0x0ff4) - { - Bank = addr - 0x0ff4; - } - } - - #region Serialization Members - - public CartA32K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x8000), 0x8000); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA32KR.cs b/EMU7800/Core/CartA32KR.cs deleted file mode 100644 index 74e43461cb..0000000000 --- a/EMU7800/Core/CartA32KR.cs +++ /dev/null @@ -1,104 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 32KB bankswitched carts with 128 bytes of RAM - /// - public sealed class CartA32KR : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x0ff4-0x0ffc - // Bank2: 0x1000:0x1000 - // Bank3: 0x2000:0x1000 - // Bank4: 0x3000:0x1000 - // Bank5: 0x4000:0x1000 - // Bank6: 0x5000:0x1000 - // Bank7: 0x6000:0x1000 - // Bank8: 0x7000:0x1000 - // Shadows ROM - // 0x1000:0x80 RAM write port - // 0x1080:0x80 RAM read port - // - ushort BankBaseAddr; - readonly byte[] RAM; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 7; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - if (addr >= 0x0080 && addr < 0x0100) - { - return RAM[addr & 0x007f]; - } - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - if (addr < 0x0080) - { - RAM[addr & 0x007f] = value; - return; - } - UpdateBank(addr); - } - } - - #endregion - - private CartA32KR() - { - } - - public CartA32KR(byte[] romBytes) - { - LoadRom(romBytes, 0x8000); - RAM = new byte[0x80]; - Bank = 7; - } - - void UpdateBank(ushort addr) - { - if (addr < 0x0ffc && addr >= 0x0ff4 ) - { - Bank = addr - 0x0ff4; - } - } - - #region Serialization Members - - public CartA32KR(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x8000), 0x8000); - RAM = input.ReadExpectedBytes(0x80); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(RAM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA4K.cs b/EMU7800/Core/CartA4K.cs deleted file mode 100644 index 17726a3c2b..0000000000 --- a/EMU7800/Core/CartA4K.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 4KB carts (no bankswitching) - /// - public sealed class CartA4K : Cart - { - #region IDevice Members - - public override void Reset() { } - - public override byte this[ushort addr] - { - get { return ROM[addr & 0x0fff]; } - set { } - } - - #endregion - - private CartA4K() - { - } - - public CartA4K(byte[] romBytes) - { - LoadRom(romBytes, 0x1000); - } - - #region Serialization Members - - public CartA4K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x1000), 0x1000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA8K.cs b/EMU7800/Core/CartA8K.cs deleted file mode 100644 index c8f531e5cb..0000000000 --- a/EMU7800/Core/CartA8K.cs +++ /dev/null @@ -1,87 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 8KB bankswitched carts - /// - public sealed class CartA8K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x1ff8,0x1ff9 - // Bank2: 0x1000:0x1000 - // - ushort BankBaseAddr; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 1; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - UpdateBank(addr); - } - } - - #endregion - - private CartA8K() - { - } - - public CartA8K(byte[] romBytes) - { - LoadRom(romBytes, 0x2000); - Bank = 1; - } - - void UpdateBank(ushort addr) - { - switch(addr) - { - case 0x0ff8: - Bank = 0; - break; - case 0x0ff9: - Bank = 1; - break; - } - } - - #region Serialization Members - - public CartA8K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x2000), 0x2000); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartA8KR.cs b/EMU7800/Core/CartA8KR.cs deleted file mode 100644 index a0fd89e034..0000000000 --- a/EMU7800/Core/CartA8KR.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Atari standard 8KB bankswitched carts with 128 bytes of RAM - /// - public sealed class CartA8KR : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x1ff8,0x1ff9 - // Bank2: 0x1000:0x1000 - // Shadows ROM - // 0x1000:0x0080 RAM write port - // 0x1080:0x0080 RAM read port - // - ushort BankBaseAddr; - readonly byte[] RAM; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 1; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - if (addr < 0x0100 && addr >= 0x0080) - { - return RAM[addr & 0x7f]; - } - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - if (addr < 0x0080) - { - RAM[addr & 0x7f] = value; - return; - } - UpdateBank(addr); - } - } - - #endregion - - private CartA8KR() - { - } - - public CartA8KR(byte[] romBytes) - { - LoadRom(romBytes, 0x2000); - Bank = 1; - RAM = new byte[0x80]; - } - - void UpdateBank(ushort addr) - { - switch(addr) - { - case 0x0ff8: - Bank = 0; - break; - case 0x0ff9: - Bank = 1; - break; - } - } - - #region Serialization Members - - public CartA8KR(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x2000), 0x2000); - RAM = input.ReadExpectedBytes(0x80); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(RAM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartCBS12K.cs b/EMU7800/Core/CartCBS12K.cs deleted file mode 100644 index 9b0d7bbece..0000000000 --- a/EMU7800/Core/CartCBS12K.cs +++ /dev/null @@ -1,100 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// CBS RAM Plus 12KB bankswitched carts with 128 bytes of RAM. - /// - public sealed class CartCBS12K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 Bank1:0x1000:0x1000 Select Segment: 0ff8-0ffa - // Bank2: 0x1000:0x1000 - // Bank3: 0x2000:0x1000 - // Shadows ROM - // 0x1000:0x80 RAM write port - // 0x1080:0x80 RAM read port - // - ushort BankBaseAddr; - readonly byte[] RAM; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 2; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - if (addr < 0x0200 && addr >= 0x0100) - { - return RAM[addr & 0xff]; - } - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - if (addr < 0x0100) - { - RAM[addr & 0xff] = value; - return; - } - UpdateBank(addr); - } - } - - #endregion - - private CartCBS12K() - { - } - - public CartCBS12K(byte[] romBytes) - { - LoadRom(romBytes, 0x3000); - Bank = 2; - RAM = new byte[0x100]; - } - - void UpdateBank(ushort addr) - { - if (addr < 0x0ff8 || addr > 0x0ffa) { } - else - { - Bank = addr - 0x0ff8; - } - } - - #region Serialization Members - - public CartCBS12K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x3000), 0x3000); - RAM = input.ReadExpectedBytes(0x100); - BankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(RAM); - output.Write(BankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartDC8K.cs b/EMU7800/Core/CartDC8K.cs deleted file mode 100644 index 0b3808e24c..0000000000 --- a/EMU7800/Core/CartDC8K.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Activison's Robot Tank and Decathlon 8KB bankswitching cart. - /// - public sealed class CartDC8K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by A13=0/1? - // Bank2: 0x1000:0x1000 - // - // This does what the Stella code does, which is to follow A13 to determine - // the bank. Since A0-A12 are the only significant bits on the program - // counter, I am unsure how the cart/hardware could utilize this. - // - - #region IDevice Members - - public override byte this[ushort addr] - { - get { return (addr & 0x2000) == 0 ? ROM[addr & 0x0fff + 0x1000] : ROM[addr & 0x0fff]; } - set { } - } - - #endregion - - private CartDC8K() - { - } - - public CartDC8K(byte[] romBytes) - { - LoadRom(romBytes, 0x2000); - } - - #region Serialization Members - - public CartDC8K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x2000), 0x2000); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartDPC.cs b/EMU7800/Core/CartDPC.cs deleted file mode 100644 index 4695f64df7..0000000000 --- a/EMU7800/Core/CartDPC.cs +++ /dev/null @@ -1,341 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Pitfall II cartridge. - /// There are two 4k banks, 2k display bank, and the DPC chip. - /// For complete details on the DPC chip see David P. Crane's United States Patent Number 4,644,495. - /// - public sealed class CartDPC : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Bank1: 0x0000:0x1000 0x1000:0x1000 Bank selected by accessing 0x1ff8,0x1ff9 - // Bank2: 0x1000:0x1000 - // - const ushort DisplayBaseAddr = 0x2000; - ushort BankBaseAddr; - - readonly byte[] MusicAmplitudes = new byte[] { 0x00, 0x04, 0x05, 0x09, 0x06, 0x0a, 0x0b, 0x0f }; - - readonly byte[] Tops = new byte[8]; - readonly byte[] Bots = new byte[8]; - readonly ushort[] Counters = new ushort[8]; - readonly byte[] Flags = new byte[8]; - readonly bool[] MusicMode = new bool[3]; - - ulong LastSystemClock; - double FractionalClocks; - - byte _ShiftRegister; - - int Bank - { - set { BankBaseAddr = (ushort)(value * 0x1000); } - } - - // - // Generate a sequence of pseudo-random numbers 255 numbers long - // by emulating an 8-bit shift register with feedback taps at - // bits 4, 3, 2, and 0. - byte ShiftRegister - { - get - { - var a = _ShiftRegister; - a &= (1 << 0); - - var x = _ShiftRegister; - x &= (1 << 2); - x >>= 2; - a ^= x; - - x = _ShiftRegister; - x &= (1 << 3); - x >>= 3; - a ^= x; - - x = _ShiftRegister; - x &= (1 << 4); - x >>= 4; - a ^= x; - - a <<= 7; - _ShiftRegister >>= 1; - _ShiftRegister |= a; - - return _ShiftRegister; - } - set { _ShiftRegister = value; } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 1; - LastSystemClock = 3*M.CPU.Clock; - FractionalClocks = 0.0; - ShiftRegister = 1; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - if (addr < 0x0040) - { - return ReadPitfall2Reg(addr); - } - UpdateBank(addr); - return ROM[BankBaseAddr + addr]; - } - set - { - addr &= 0x0fff; - if (addr >= 0x0040 && addr < 0x0080) - { - WritePitfall2Reg(addr, value); - } - else - { - UpdateBank(addr); - } - } - } - - #endregion - - private CartDPC() - { - } - - public CartDPC(byte[] romBytes) - { - LoadRom(romBytes, 0x2800); - Bank = 1; - } - - void UpdateBank(ushort addr) - { - switch(addr) - { - case 0x0ff8: - Bank = 0; - break; - case 0x0ff9: - Bank = 1; - break; - } - } - - byte ReadPitfall2Reg(ushort addr) - { - byte result; - - var i = addr & 0x07; - var fn = (addr >> 3) & 0x07; - - // Update flag register for selected data fetcher - if ((Counters[i] & 0x00ff) == Tops[i]) - { - Flags[i] = 0xff; - } - else if ((Counters[i] & 0x00ff) == Bots[i]) - { - Flags[i] = 0x00; - } - - switch (fn) - { - case 0x00: - if (i < 4) - { - // This is a random number read - result = ShiftRegister; - break; - } - // Its a music read - UpdateMusicModeDataFetchers(); - - byte j = 0; - if (MusicMode[0] && Flags[5] != 0) - { - j |= 0x01; - } - if (MusicMode[1] && Flags[6] != 0) - { - j |= 0x02; - } - if (MusicMode[2] && Flags[7] != 0) - { - j |= 0x04; - } - result = MusicAmplitudes[j]; - break; - // DFx display data read - case 0x01: - result = ROM[DisplayBaseAddr + 0x7ff - Counters[i]]; - break; - // DFx display data read AND'd w/flag - case 0x02: - result = ROM[DisplayBaseAddr + 0x7ff - Counters[i]]; - result &= Flags[i]; - break; - // DFx flag - case 0x07: - result = Flags[i]; - break; - default: - result = 0; - break; - } - - // Clock the selected data fetcher's counter if needed - if (i < 5 || i >= 5 && MusicMode[i - 5] == false) - { - Counters[i]--; - Counters[i] &= 0x07ff; - } - - return result; - } - - void UpdateMusicModeDataFetchers() - { - var sysClockDelta = 3*M.CPU.Clock - LastSystemClock; - LastSystemClock = 3*M.CPU.Clock; - - var OSCclocks = ((15750.0 * sysClockDelta) / 1193191.66666667) + FractionalClocks; - - var wholeClocks = (int)OSCclocks; - FractionalClocks = OSCclocks - wholeClocks; - if (wholeClocks <= 0) - { - return; - } - - for (var i=0; i < 3; i++) - { - var r = i + 5; - if (!MusicMode[i]) continue; - - var top = Tops[r] + 1; - var newLow = Counters[r] & 0x00ff; - - if (Tops[r] != 0) - { - newLow -= (wholeClocks % top); - if (newLow < 0) - { - newLow += top; - } - } - else - { - newLow = 0; - } - - if (newLow <= Bots[r]) - { - Flags[r] = 0x00; - } - else if (newLow <= Tops[r]) - { - Flags[r] = 0xff; - } - - Counters[r] = (ushort)((Counters[r] & 0x0700) | (ushort)newLow); - } - } - - void WritePitfall2Reg(ushort addr, byte val) - { - var i = addr & 0x07; - var fn = (addr >> 3) & 0x07; - - switch (fn) - { - // DFx top count - case 0x00: - Tops[i] = val; - Flags[i] = 0x00; - break; - // DFx bottom count - case 0x01: - Bots[i] = val; - break; - // DFx counter low - case 0x02: - Counters[i] &= 0x0700; - if (i >= 5 && MusicMode[i - 5]) - { - // Data fetcher is in music mode so its low counter value - // should be loaded from the top register not the poked value - Counters[i] |= Tops[i]; - } - else - { - // Data fetcher is either not a music mode data fetcher or it - // isn't in music mode so it's low counter value should be loaded - // with the poked value - Counters[i] |= val; - } - break; - // DFx counter high - case 0x03: - Counters[i] &= 0x00ff; - Counters[i] |= (ushort)((val & 0x07) << 8); - // Execute special code for music mode data fetchers - if (i >= 5) - { - MusicMode[i - 5] = (val & 0x10) != 0; - // NOTE: We are not handling the clock source input for - // the music mode data fetchers. We're going to assume - // they always use the OSC input. - } - break; - // Random Number Generator Reset - case 0x06: - ShiftRegister = 1; - break; - } - } - - #region Serialization Members - - public CartDPC(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x2800), 0x2800); - BankBaseAddr = input.ReadUInt16(); - Tops = input.ReadExpectedBytes(8); - Bots = input.ReadExpectedBytes(8); - Counters = input.ReadUnsignedShorts(8); - Flags = input.ReadExpectedBytes(8); - MusicMode = input.ReadBooleans(3); - LastSystemClock = input.ReadUInt64(); - FractionalClocks = input.ReadDouble(); - _ShiftRegister = input.ReadByte(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(BankBaseAddr); - output.Write(Tops); - output.Write(Bots); - output.Write(Counters); - output.Write(Flags); - output.Write(MusicMode); - output.Write(LastSystemClock); - output.Write(FractionalClocks); - output.Write(_ShiftRegister); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartMN16K.cs b/EMU7800/Core/CartMN16K.cs deleted file mode 100644 index fbcaf99bca..0000000000 --- a/EMU7800/Core/CartMN16K.cs +++ /dev/null @@ -1,136 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// M-Network 16KB bankswitched carts with 2KB RAM. - /// - public sealed class CartMN16K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Segment1: 0x0000:0x0800 Bank1:0x1000:0x0800 Select Seg: 1fe0-1fe6, 1fe7=RAM Seg1 - // Segment2: 0x0800:0x0800 Bank2:0x1800:0x0800 Always Seg8 - // Segment3: 0x1000:0x0800 - // Segment4: 0x1800:0x0800 - // Segment5: 0x2000:0x0800 - // Segment6: 0x2800:0x0800 - // Segment7: 0x3000:0x0800 - // Segment8: 0x3800:0x0800 - // - // RAM RAM Segment1 when 1fe7 select is accessed - // Segment1: 0x0000:0x0400 0x1000-0x13FF write port - // Segment2: 0x0400:0x0400 0x1400-0x17FF read port - // - // RAM Segment2: 1ff8-1ffb selects 256-byte block - // 0x1800-0x18ff write port - // 0x1900-0x19ff read port - // - ushort BankBaseAddr, BankBaseRAMAddr; - bool RAMBankOn; - readonly byte[] RAM; - - int Bank - { - set - { - BankBaseAddr = (ushort)(value << 11); // multiply by 2048 - RAMBankOn = (value == 0x07); - } - } - - int BankRAM - { - set { BankBaseRAMAddr = (ushort) (value << 8); } // multiply by 256 - } - - #region IDevice Members - - public override void Reset() - { - Bank = 0; - BankRAM = 0; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - UpdateBanks(addr); - if (RAMBankOn && addr >= 0x0400 && addr < 0x0800) - { - return RAM[addr & 0x03ff]; - } - if (addr >= 0x0900 && addr < 0x0a00) - { - return RAM[0x400 + BankBaseRAMAddr + (addr & 0xff)]; - } - return addr < 0x0800 ? ROM[BankBaseAddr + (addr & 0x07ff)] : ROM[0x3800 + (addr & 0x07ff)]; - } - set - { - addr &= 0x0fff; - UpdateBanks(addr); - if (RAMBankOn && addr < 0x0400) - { - RAM[addr & 0x03ff] = value; - } - else if (addr >= 0x0800 && addr < 0x0900) - { - RAM[0x400 + BankBaseRAMAddr + (addr & 0xff)] = value; - } - } - } - - #endregion - - private CartMN16K() - { - } - - public CartMN16K(byte[] romBytes) - { - LoadRom(romBytes, 0x4000); - RAM = new byte[0x800]; - Bank = 0; - BankRAM = 0; - } - - void UpdateBanks(ushort addr) - { - if (addr >= 0x0fe0 && addr < 0x0fe8) - { - Bank = addr & 0x07; - } - else if (addr >= 0x0fe8 && addr < 0x0fec) - { - BankRAM = addr & 0x03; - } - } - - #region Serialization Members - - public CartMN16K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x4000), 0x4000); - RAM = input.ReadExpectedBytes(0x800); - BankBaseAddr = input.ReadUInt16(); - BankBaseRAMAddr = input.ReadUInt16(); - RAMBankOn = input.ReadBoolean(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(RAM); - output.Write(BankBaseAddr); - output.Write(BankBaseRAMAddr); - output.Write(RAMBankOn); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartPB8K.cs b/EMU7800/Core/CartPB8K.cs deleted file mode 100644 index 150bca0932..0000000000 --- a/EMU7800/Core/CartPB8K.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Parker Brothers 8KB bankswitched carts. - /// - public sealed class CartPB8K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Segment1: 0x0000:0x0400 Bank1:0x1000:0x0400 Select Segment: 1fe0-1fe7 - // Segment2: 0x0400:0x0400 Bank2:0x1400:0x0400 Select Segment: 1fe8-1ff0 - // Segment3: 0x0800:0x0400 Bank3:0x1800:0x0400 Select Segment: 1ff0-1ff8 - // Segment4: 0x0c00:0x0400 Bank4:0x1c00:0x0400 Always Segment8 - // Segment5: 0x1000:0x0400 - // Segment6: 0x1400:0x0400 - // Segment7: 0x1800:0x0400 - // Segment8: 0x1c00:0x0400 - // - readonly ushort[] SegmentBase; - - #region IDevice Members - - public override void Reset() - { - SegmentBase[0] = ComputeSegmentBase(4); - SegmentBase[1] = ComputeSegmentBase(5); - SegmentBase[2] = ComputeSegmentBase(6); - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - UpdateSegmentBases(addr); - return ROM[SegmentBase[addr >> 10] + (addr & 0x03ff)]; - } - set - { - addr &= 0x0fff; - UpdateSegmentBases(addr); - } - } - - #endregion - - private CartPB8K() - { - } - - public CartPB8K(byte[] romBytes) - { - LoadRom(romBytes, 0x2000); - SegmentBase = new ushort[4]; - SegmentBase[0] = ComputeSegmentBase(4); - SegmentBase[1] = ComputeSegmentBase(5); - SegmentBase[2] = ComputeSegmentBase(6); - SegmentBase[3] = ComputeSegmentBase(7); - } - - static ushort ComputeSegmentBase(int slice) - { - return (ushort)(slice << 10); // multiply by 1024 - } - - void UpdateSegmentBases(ushort addr) - { - if (addr < 0xfe0 || addr >= 0x0ff8) { } - else if (addr >= 0x0fe0 && addr < 0x0fe8) - { - SegmentBase[0] = ComputeSegmentBase(addr & 0x07); - } - else if (addr >= 0x0fe8 && addr < 0x0ff0) - { - SegmentBase[1] = ComputeSegmentBase(addr & 0x07); - } - else if (addr >= 0x0ff0 && addr < 0x0ff8) - { - SegmentBase[2] = ComputeSegmentBase(addr & 0x07); - } - } - - #region Serialization Members - - public CartPB8K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x2000), 0x2000); - SegmentBase = input.ReadUnsignedShorts(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(SegmentBase); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartTV8K.cs b/EMU7800/Core/CartTV8K.cs deleted file mode 100644 index cfeaa9d038..0000000000 --- a/EMU7800/Core/CartTV8K.cs +++ /dev/null @@ -1,90 +0,0 @@ -namespace EMU7800.Core -{ - /// - /// Tigervision 8KB bankswitched carts - /// - public sealed class CartTV8K : Cart - { - // - // Cart Format Mapping to ROM Address Space - // Segment1: 0x0000:0x0800 0x1000:0x0800 Selected segment via $003F - // Segment2: 0x0800:0x0800 0x1800:0x0800 Always last segment - // Segment3: 0x1000:0x0800 - // Segment4: 0x1800:0x0800 - // - ushort BankBaseAddr; - readonly ushort LastBankBaseAddr; - - byte Bank - { - set - { - BankBaseAddr = (ushort)(0x0800 * value); - BankBaseAddr %= (ushort)ROM.Length; - } - } - - protected internal override bool RequestSnooping - { - get { return true; } - } - - #region IDevice Members - - public override void Reset() - { - Bank = 0; - } - - public override byte this[ushort addr] - { - get - { - addr &= 0x0fff; - return addr < 0x0800 ? ROM[BankBaseAddr + (addr & 0x07ff)] : ROM[LastBankBaseAddr + (addr & 0x07ff)]; - } - set - { - if (addr <= 0x003f) - { - Bank = value; - } - } - } - - #endregion - - private CartTV8K() - { - } - - public CartTV8K(byte[] romBytes) - { - LoadRom(romBytes, 0x1000); - Bank = 0; - LastBankBaseAddr = (ushort)(ROM.Length - 0x0800); - } - - #region Serialization Members - - public CartTV8K(DeserializationContext input, MachineBase m) : base(input) - { - input.CheckVersion(1); - LoadRom(input.ReadExpectedBytes(0x1000), 0x1000); - BankBaseAddr = input.ReadUInt16(); - LastBankBaseAddr = input.ReadUInt16(); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(BankBaseAddr); - output.Write(LastBankBaseAddr); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/CartType.cs b/EMU7800/Core/CartType.cs deleted file mode 100644 index a334cb5034..0000000000 --- a/EMU7800/Core/CartType.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* - * CartType.cs - * - * Defines the set of all known Game Cartridges. - * - * 2010 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public enum CartType - { - None, - A2K, // Atari 2kb cart - TV8K, // Tigervision 8kb bankswitched cart - A4K, // Atari 4kb cart - PB8K, // Parker Brothers 8kb bankswitched cart - MN16K, // M-Network 16kb bankswitched cart - A16K, // Atari 16kb bankswitched cart - A16KR, // Atari 16kb bankswitched cart w/128 bytes RAM - A8K, // Atari 8KB bankswitched cart - A8KR, // Atari 8KB bankswitched cart w/128 bytes RAM - A32K, // Atari 32KB bankswitched cart - A32KR, // Atari 32KB bankswitched cart w/128 bytes RAM - CBS12K, // CBS' RAM Plus bankswitched cart w/256 bytes RAM - DC8K, // Special Activision cart (Robot Tank and Decathlon) - DPC, // Pitfall II DPC cart - M32N12K, // 32N1 Multicart: 32x2KB - A7808, // Atari7800 non-bankswitched 8KB cart - A7816, // Atari7800 non-bankswitched 16KB cart - A7832, // Atari7800 non-bankswitched 32KB cart - A7832P, // Atari7800 non-bankswitched 32KB cart w/Pokey - A7848, // Atari7800 non-bankswitched 48KB cart - A78SG, // Atari7800 SuperGame cart - A78SGP, // Atari7800 SuperGame cart w/Pokey - A78SGR, // Atari7800 SuperGame cart w/RAM - A78S9, // Atari7800 SuperGame cart, nine banks - A78S4, // Atari7800 SuperGame cart, four banks - A78S4R, // Atari7800 SuperGame cart, four banks, w/RAM - A78AB, // F18 Hornet cart (Absolute) - A78AC, // Double dragon cart (Activision) - }; -} diff --git a/EMU7800/Core/ConsoleSwitch.cs b/EMU7800/Core/ConsoleSwitch.cs deleted file mode 100644 index 7a07ba7eb5..0000000000 --- a/EMU7800/Core/ConsoleSwitch.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace EMU7800.Core -{ - internal enum ConsoleSwitch - { - GameReset, - GameSelect, - GameBW, - LeftDifficultyA, - RightDifficultyA, - } -} \ No newline at end of file diff --git a/EMU7800/Core/Controller.cs b/EMU7800/Core/Controller.cs deleted file mode 100644 index bc21cbcbd6..0000000000 --- a/EMU7800/Core/Controller.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace EMU7800.Core -{ - public enum Controller - { - None, - Joystick, - Paddles, - Keypad, - Driving, - BoosterGrip, - ProLineJoystick, - Lightgun, - } -} \ No newline at end of file diff --git a/EMU7800/Core/ControllerAction.cs b/EMU7800/Core/ControllerAction.cs deleted file mode 100644 index bad0cc82ee..0000000000 --- a/EMU7800/Core/ControllerAction.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace EMU7800.Core -{ - public enum ControllerAction - { - Up, - Down, - Left, - Right, - Trigger, // Interpretation: 7800 RFire; 2600 Fire, BoosterGrip top - Trigger2, // Interpretation: 7800 LFire, BoosterGrip trigger - Keypad1, Keypad2, Keypad3, - Keypad4, Keypad5, Keypad6, - Keypad7, Keypad8, Keypad9, - KeypadA, Keypad0, KeypadP, - Driving0, Driving1, Driving2, Driving3, - } -} \ No newline at end of file diff --git a/EMU7800/Core/DeserializationContext.cs b/EMU7800/Core/DeserializationContext.cs deleted file mode 100644 index 9a6fe64413..0000000000 --- a/EMU7800/Core/DeserializationContext.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System; -using System.IO; -using System.Linq; - -namespace EMU7800.Core -{ - /// - /// A context for deserializing objects. - /// - public class DeserializationContext - { - #region Fields - - readonly BinaryReader _binaryReader; - - #endregion - - public bool ReadBoolean() - { - return _binaryReader.ReadBoolean(); - } - - public byte ReadByte() - { - return _binaryReader.ReadByte(); - } - - public ushort ReadUInt16() - { - return _binaryReader.ReadUInt16(); - } - - public int ReadInt32() - { - return _binaryReader.ReadInt32(); - } - - public uint ReadUInt32() - { - return _binaryReader.ReadUInt32(); - } - - public long ReadInt64() - { - return _binaryReader.ReadInt64(); - } - - public ulong ReadUInt64() - { - return _binaryReader.ReadUInt64(); - } - - public double ReadDouble() - { - return _binaryReader.ReadDouble(); - } - - /* - public BufferElement ReadBufferElement() - { - var be = new BufferElement(); - for (var i = 0; i < BufferElement.SIZE; i++) - be[i] = ReadByte(); - return be; - } - */ - - public byte[] ReadBytes() - { - var count = _binaryReader.ReadInt32(); - if (count <= 0) - return new byte[0]; - if (count > 0x40000) - throw new Emu7800SerializationException("Byte array length too large."); - return _binaryReader.ReadBytes(count); - } - - public byte[] ReadExpectedBytes(params int[] expectedSizes) - { - var count = _binaryReader.ReadInt32(); - if (!expectedSizes.Any(t => t == count)) - throw new Emu7800SerializationException("Byte array length incorrect."); - return _binaryReader.ReadBytes(count); - } - - public byte[] ReadOptionalBytes(params int[] expectedSizes) - { - var hasBytes = _binaryReader.ReadBoolean(); - return (hasBytes) ? ReadExpectedBytes(expectedSizes) : null; - } - - public ushort[] ReadUnsignedShorts(params int[] expectedSizes) - { - var bytes = ReadExpectedBytes(expectedSizes.Select(t => t << 1).ToArray()); - var ushorts = new ushort[bytes.Length >> 1]; - Buffer.BlockCopy(bytes, 0, ushorts, 0, bytes.Length); - return ushorts; - } - - public int[] ReadIntegers(params int[] expectedSizes) - { - var bytes = ReadExpectedBytes(expectedSizes.Select(t => t << 2).ToArray()); - var integers = new int[bytes.Length >> 2]; - Buffer.BlockCopy(bytes, 0, integers, 0, bytes.Length); - return integers; - } - - public uint[] ReadUnsignedIntegers(params int[] expectedSizes) - { - var bytes = ReadExpectedBytes(expectedSizes.Select(t => t << 2).ToArray()); - var uints = new uint[bytes.Length >> 2]; - Buffer.BlockCopy(bytes, 0, uints, 0, bytes.Length); - return uints; - } - - public bool[] ReadBooleans(params int[] expectedSizes) - { - var bytes = ReadExpectedBytes(expectedSizes); - var booleans = new bool[bytes.Length]; - for (var i = 0; i < bytes.Length; i++) - booleans[i] = (bytes[i] != 0); - return booleans; - } - - public int CheckVersion(params int[] validVersions) - { - var magicNumber = _binaryReader.ReadInt32(); - if (magicNumber != 0x78000087) - throw new Emu7800SerializationException("Magic number not found."); - var version = _binaryReader.ReadInt32(); - if (!validVersions.Any(t => t == version)) - throw new Emu7800SerializationException("Invalid version number found."); - return version; - } - - public MachineBase ReadMachine() - { - var typeName = _binaryReader.ReadString(); - if (string.IsNullOrWhiteSpace(typeName)) - throw new Emu7800SerializationException("Invalid type name."); - - var type = Type.GetType(typeName); - if (type == null) - throw new Emu7800SerializationException("Unable to resolve type name: " + typeName); - - return (MachineBase)Activator.CreateInstance(type, new object[] { this }); - } - - public AddressSpace ReadAddressSpace(MachineBase m, int addrSpaceShift, int pageShift) - { - var addressSpace = new AddressSpace(this, m, addrSpaceShift, pageShift); - return addressSpace; - } - - public M6502 ReadM6502(MachineBase m, int runClocksMultiple) - { - var cpu = new M6502(this, m, runClocksMultiple); - return cpu; - } - - public Maria ReadMaria(Machine7800 m, int scanlines) - { - var maria = new Maria(this, m, scanlines); - return maria; - } - - public PIA ReadPIA(MachineBase m) - { - var pia = new PIA(this, m); - return pia; - } - - public TIA ReadTIA(MachineBase m) - { - var tia = new TIA(this, m); - return tia; - } - - public TIASound ReadTIASound(MachineBase m, int cpuClocksPerSample) - { - var tiaSound = new TIASound(this, m, cpuClocksPerSample); - return tiaSound; - } - - public RAM6116 ReadRAM6116() - { - var ram6116 = new RAM6116(this); - return ram6116; - } - - public InputState ReadInputState() - { - var inputState = new InputState(this); - return inputState; - } - - public HSC7800 ReadOptionalHSC7800() - { - var exist = ReadBoolean(); - return exist ? new HSC7800(this) : null; - } - - public Bios7800 ReadOptionalBios7800() - { - var exist = ReadBoolean(); - return exist ? new Bios7800(this) : null; - } - - public PokeySound ReadOptionalPokeySound(MachineBase m) - { - var exist = ReadBoolean(); - return exist ? new PokeySound(this, m) : null; - } - - public Cart ReadCart(MachineBase m) - { - var typeName = _binaryReader.ReadString(); - if (string.IsNullOrWhiteSpace(typeName)) - throw new Emu7800SerializationException("Invalid type name."); - - var type = Type.GetType(typeName); - if (type == null) - throw new Emu7800SerializationException("Unable to resolve type name: " + typeName); - - return (Cart)Activator.CreateInstance(type, new object[] { this, m }); - } - - #region Constructors - - private DeserializationContext() - { - } - - /// - /// Instantiates a new instance of . - /// - /// - internal DeserializationContext(BinaryReader binaryReader) - { - if (binaryReader == null) - throw new ArgumentNullException("binaryReader"); - _binaryReader = binaryReader; - } - - #endregion - } -} diff --git a/EMU7800/Core/Emu7800Exception.cs b/EMU7800/Core/Emu7800Exception.cs deleted file mode 100644 index 18de9a42a4..0000000000 --- a/EMU7800/Core/Emu7800Exception.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace EMU7800.Core -{ - public class Emu7800Exception : Exception - { - internal Emu7800Exception() - { - } - - internal Emu7800Exception(string message) : base(message) - { - } - - internal Emu7800Exception(string message, Exception ex) : base(message, ex) - { - } - } -} diff --git a/EMU7800/Core/Emu7800SerializationException.cs b/EMU7800/Core/Emu7800SerializationException.cs deleted file mode 100644 index 4f0827d13c..0000000000 --- a/EMU7800/Core/Emu7800SerializationException.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace EMU7800.Core -{ - public class Emu7800SerializationException : Emu7800Exception - { - private Emu7800SerializationException() - { - } - - internal Emu7800SerializationException(string message) : base(message) - { - } - - internal Emu7800SerializationException(string message, Exception ex) : base(message, ex) - { - } - } -} diff --git a/EMU7800/Core/FontRenderer.cs b/EMU7800/Core/FontRenderer.cs deleted file mode 100644 index 763bc95d69..0000000000 --- a/EMU7800/Core/FontRenderer.cs +++ /dev/null @@ -1,170 +0,0 @@ -/* - * FontRenderer - * - * A simple font renderer for displaying text during emulation. Font data and - * rendering algorithm courtesy of Bradford W. Mott's Stella source. - * - * Copyright © 2004 Mike Murphy - * - */ - -using System; - -namespace EMU7800.Core -{ - /// - /// A simple font renderer for displaying text during emulation. - /// - public class FontRenderer - { - static readonly uint[] AlphaFontData = - { - 0x699f999, // A - 0xe99e99e, // B - 0x6988896, // C - 0xe99999e, // D - 0xf88e88f, // E - 0xf88e888, // F - 0x698b996, // G - 0x999f999, // H - 0x7222227, // I - 0x72222a4, // J - 0x9accaa9, // K - 0x888888f, // L - 0x9ff9999, // M - 0x9ddbb99, // N - 0x6999996, // O - 0xe99e888, // P - 0x69999b7, // Q - 0xe99ea99, // R - 0x6986196, // S - 0x7222222, // T - 0x9999996, // U - 0x9999966, // V - 0x9999ff9, // W - 0x99fff99, // X - 0x9996244, // Y - 0xf12488f // Z - }; - - static readonly uint[] DigitFontData = - { - 0x69bd996, // 0 - 0x2622227, // 1 - 0x691248f, // 2 - 0x6916196, // 3 - 0xaaaf222, // 4 - 0xf88e11e, // 5 - 0x698e996, // 6 - 0xf112244, // 7 - 0x6996996, // 8 - 0x6997196 // 9 - }; - - /// - /// Draw specified text at specified position using the specified foreground and background colors. - /// - /// - /// - /// - /// - /// - /// - /// text must be non-null. - public void DrawText(FrameBuffer frameBuffer, string text, int xoffset, int yoffset, byte fore, byte back) - { - if (text == null) - throw new ArgumentNullException("text"); - - var textchars = text.ToUpper().ToCharArray(); - - for (var i = 0; i < text.Length + 1; i++) - { - for (var j = 0; j < 9; j++) - { - var pos = (j + yoffset) * frameBuffer.VisiblePitch + i * 5; - for (var k = 0; k < 5; k++) - { - while (pos >= frameBuffer.VideoBufferByteLength) - { - pos -= frameBuffer.VideoBufferByteLength; - } - while (pos < 0) - { - pos += frameBuffer.VideoBufferByteLength; - } - frameBuffer.VideoBuffer[pos++] = back; - } - } - } - - for (var i = 0; i < text.Length; i++) - { - var c = textchars[i]; - uint fdata; - - switch (c) - { - case '/': - case '\\': - fdata = 0x0122448; - break; - case '(': - fdata = 0x2488842; - break; - case ')': - fdata = 0x4211124; - break; - case '.': - fdata = 0x0000066; - break; - case ':': - fdata = 0x0660660; - break; - case '-': - fdata = 0x0007000; - break; - default: - if (c >= 'A' && c <= 'Z') - { - fdata = AlphaFontData[c - 'A']; - } - else if (c >= '0' && c <= '9') - { - fdata = DigitFontData[c - '0']; - } - else - { - fdata = 0; - } - break; - } - - var ypos = 8; - for (var j = 0; j < 32; j++) - { - var xpos = j & 3; - if (xpos == 0) - { - ypos--; - } - - var pos = (ypos + yoffset) * frameBuffer.VisiblePitch + (4 - xpos) + xoffset; - while (pos >= frameBuffer.VideoBufferByteLength) - { - pos -= frameBuffer.VideoBufferByteLength; - } - while (pos < 0) - { - pos += frameBuffer.VideoBufferByteLength; - } - if (((fdata >> j) & 1) != 0) - { - frameBuffer.VideoBuffer[pos] = fore; - } - } - xoffset += 5; - } - } - } -} diff --git a/EMU7800/Core/FrameBuffer.cs b/EMU7800/Core/FrameBuffer.cs deleted file mode 100644 index 073b2e9d82..0000000000 --- a/EMU7800/Core/FrameBuffer.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; - -namespace EMU7800.Core -{ - public class FrameBuffer - { - /// - /// Number of visible pixels on a single horizontal line. - /// - public int VisiblePitch { get; private set; } - - /// - /// Number of s that represent VisiblePitch. - /// - //public int VideoBufferElementVisiblePitch { get; private set; } - - /// - /// Number of visible scan lines. - /// - public int Scanlines { get; private set; } - - /// - /// The number of bytes contained by VideoBuffer. - /// - public int VideoBufferByteLength { get; private set; } - - /// - /// The number of s contained by VideoBuffer - /// - //public int VideoBufferElementLength { get; private set; } - - /// - /// The number of bytes contained by SoundBuffer. - /// - public int SoundBufferByteLength { get; private set; } - - /// - /// The number of s contained by SoundBuffer - /// - //public int SoundBufferElementLength { get; private set; } - - /// - /// The buffer containing computed pixel data. - /// - public byte[] VideoBuffer { get; private set; } - - /// - /// The buffer containing computed PCM audio data. - /// - public byte[] SoundBuffer { get; private set; } - - #region Constructors - - private FrameBuffer() - { - } - - internal FrameBuffer(int visiblePitch, int scanLines) - { - if (visiblePitch < 0) - throw new ArgumentException("visiblePitch must be non-negative."); - if (scanLines < 0) - throw new ArgumentException("scanLines must be non-negative."); - - VisiblePitch = visiblePitch; - //VideoBufferElementVisiblePitch = VisiblePitch >> BufferElement.SHIFT; - Scanlines = scanLines; - VideoBufferByteLength = VisiblePitch * Scanlines; - //VideoBufferElementLength = VideoBufferElementVisiblePitch * Scanlines; - SoundBufferByteLength = Scanlines << 1; - //SoundBufferElementLength = SoundBufferByteLength >> BufferElement.SHIFT; - - VideoBuffer = new byte[VideoBufferByteLength + 64]; - SoundBuffer = new byte[SoundBufferByteLength + 64]; - } - - #endregion - } -} diff --git a/EMU7800/Core/HSC7800.cs b/EMU7800/Core/HSC7800.cs deleted file mode 100644 index 4186e66097..0000000000 --- a/EMU7800/Core/HSC7800.cs +++ /dev/null @@ -1,85 +0,0 @@ -/* - * HSC7800.cs - * - * The 7800 High Score cartridge--courtesy of Matthias . - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class HSC7800 : IDevice - { - readonly byte[] ROM; - readonly ushort Mask; - - public static ushort Size { get; private set; } - - #region IDevice Members - - public void Reset() - { - } - - public byte this[ushort addr] - { - get { return ROM[addr & Mask]; } - set { } - } - - #endregion - - public RAM6116 SRAM { get; private set; } - - #region Constructors - - private HSC7800() - { - } - - public HSC7800(byte[] hscRom, byte[] ram) - { - if (hscRom == null) - throw new ArgumentNullException("hscRom"); - if (ram == null) - throw new ArgumentNullException("ram"); - if (hscRom.Length != 4096) - throw new ArgumentException("ROM size not 4096", "hscRom"); - - ROM = hscRom; - SRAM = new RAM6116(ram); - - Size = Mask = (ushort)ROM.Length; - Mask--; - } - - #endregion - - #region Serialization Members - - public HSC7800(DeserializationContext input) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - ROM = input.ReadExpectedBytes(4096); - SRAM = input.ReadRAM6116(); - - Size = Mask = (ushort)ROM.Length; - Mask--; - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(ROM); - output.Write(SRAM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/IDevice.cs b/EMU7800/Core/IDevice.cs deleted file mode 100644 index 38a8b83980..0000000000 --- a/EMU7800/Core/IDevice.cs +++ /dev/null @@ -1,16 +0,0 @@ -/* - * IDevice.cs - * - * Defines interface for devices accessable via the AddressSpace class. - * - * Copyright © 2003, 2011 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public interface IDevice - { - void Reset(); - byte this[ushort addr] { get; set; } - } -} diff --git a/EMU7800/Core/ILogger.cs b/EMU7800/Core/ILogger.cs deleted file mode 100644 index 919c3b0b25..0000000000 --- a/EMU7800/Core/ILogger.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace EMU7800.Core -{ - public interface ILogger - { - void WriteLine(string format, params object[] args); - void WriteLine(object value); - void Write(string format, params object[] args); - void Write(object value); - } -} diff --git a/EMU7800/Core/InputState.cs b/EMU7800/Core/InputState.cs deleted file mode 100644 index 95950a9eb9..0000000000 --- a/EMU7800/Core/InputState.cs +++ /dev/null @@ -1,398 +0,0 @@ -/* - * InputState.cs - * - * Class containing the input state of the console and its controllers, - * mapping emulator input devices to external input. - * - * Copyright © 2003-2010 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public class InputState - { - #region Fields - - const int - PaddleOhmMin = 100000, - PaddleOhmMax = 800000; - - const int - LeftControllerJackIndex = 0, - RightControllerJackIndex = 1, - ConsoleSwitchIndex = 2, - ControllerActionStateIndex = 3, - OhmsIndex = ControllerActionStateIndex + 4, - LightgunPositionIndex = ControllerActionStateIndex + 4, - InputStateSize = ControllerActionStateIndex + 8 + 1; - - // For driving controllers - readonly byte[] _rotGrayCodes = new byte[] { 0x0f, 0x0d, 0x0c, 0x0e }; - readonly int[] _rotState = new int[2]; - - readonly int[] _nextInputState = new int[InputStateSize]; - readonly int[] _inputState = new int[InputStateSize]; - - bool _lagged = true; - - #endregion - - #region Public Members - - /// - /// Enables the incoming input state buffer to be populated prior to the start of the frame. - /// Useful for input playback senarios. - /// - /// Return value is ignored. - public Func InputAdvancing { get; set; } - - /// - /// Enables access to the input state buffer. - /// Useful for input recording senarios. - /// - /// Return value is ignored. - public Func InputAdvanced { get; set; } - - public void CaptureInputState() - { - if (InputAdvancing != null) - InputAdvancing(_nextInputState); - Buffer.BlockCopy(_nextInputState, 0, _inputState, 0, InputStateSize * sizeof(int)); - if (InputAdvanced != null) - InputAdvanced(_inputState); - _lagged = true; - } - - public Controller LeftControllerJack - { - get { return (Controller)_nextInputState[LeftControllerJackIndex]; } - set { _nextInputState[LeftControllerJackIndex] = (int)value; } - } - - public Controller RightControllerJack - { - get { return (Controller)_nextInputState[RightControllerJackIndex]; } - set { _nextInputState[RightControllerJackIndex] = (int)value; } - } - - public bool IsGameBWConsoleSwitchSet - { - get { return (_nextInputState[ConsoleSwitchIndex] & (1 << (int) ConsoleSwitch.GameBW)) != 0; } - } - - public bool IsLeftDifficultyAConsoleSwitchSet - { - get { return (_nextInputState[ConsoleSwitchIndex] & (1 << (int)ConsoleSwitch.LeftDifficultyA)) != 0; } - } - - public bool IsRightDifficultyAConsoleSwitchSet - { - get { return (_nextInputState[ConsoleSwitchIndex] & (1 << (int)ConsoleSwitch.RightDifficultyA)) != 0; } - } - - public bool Lagged - { - get { return _lagged; } - } - - public Action InputPollCallback { get; set; } - - public void RaiseInput(int playerNo, MachineInput input, bool down) - { - if (InputPollCallback != null) - { - InputPollCallback(); - } - switch (input) - { - case MachineInput.Fire: - SetControllerActionState(playerNo, ControllerAction.Trigger, down); - break; - case MachineInput.Fire2: - SetControllerActionState(playerNo, ControllerAction.Trigger2, down); - break; - case MachineInput.Left: - SetControllerActionState(playerNo, ControllerAction.Left, down); - if (down) SetControllerActionState(playerNo, ControllerAction.Right, false); - break; - case MachineInput.Up: - SetControllerActionState(playerNo, ControllerAction.Up, down); - if (down) SetControllerActionState(playerNo, ControllerAction.Down, false); - break; - case MachineInput.Right: - SetControllerActionState(playerNo, ControllerAction.Right, down); - if (down) SetControllerActionState(playerNo, ControllerAction.Left, false); - break; - case MachineInput.Down: - SetControllerActionState(playerNo, ControllerAction.Down, down); - if (down) SetControllerActionState(playerNo, ControllerAction.Up, false); - break; - case MachineInput.NumPad7: - SetControllerActionState(playerNo, ControllerAction.Keypad7, down); - break; - case MachineInput.NumPad8: - SetControllerActionState(playerNo, ControllerAction.Keypad8, down); - break; - case MachineInput.NumPad9: - SetControllerActionState(playerNo, ControllerAction.Keypad9, down); - break; - case MachineInput.NumPad4: - SetControllerActionState(playerNo, ControllerAction.Keypad4, down); - break; - case MachineInput.NumPad5: - SetControllerActionState(playerNo, ControllerAction.Keypad5, down); - break; - case MachineInput.NumPad6: - SetControllerActionState(playerNo, ControllerAction.Keypad6, down); - break; - case MachineInput.NumPad1: - SetControllerActionState(playerNo, ControllerAction.Keypad1, down); - break; - case MachineInput.NumPad2: - SetControllerActionState(playerNo, ControllerAction.Keypad2, down); - break; - case MachineInput.NumPad3: - SetControllerActionState(playerNo, ControllerAction.Keypad3, down); - break; - case MachineInput.NumPadMult: - SetControllerActionState(playerNo, ControllerAction.KeypadA, down); - break; - case MachineInput.NumPad0: - SetControllerActionState(playerNo, ControllerAction.Keypad0, down); - break; - case MachineInput.NumPadHash: - SetControllerActionState(playerNo, ControllerAction.KeypadP, down); - break; - case MachineInput.Driving0: - SetControllerActionState(playerNo, ControllerAction.Driving0, true); - SetControllerActionState(playerNo, ControllerAction.Driving1, false); - SetControllerActionState(playerNo, ControllerAction.Driving2, false); - SetControllerActionState(playerNo, ControllerAction.Driving3, false); - break; - case MachineInput.Driving1: - SetControllerActionState(playerNo, ControllerAction.Driving0, false); - SetControllerActionState(playerNo, ControllerAction.Driving1, true); - SetControllerActionState(playerNo, ControllerAction.Driving2, false); - SetControllerActionState(playerNo, ControllerAction.Driving3, false); - break; - case MachineInput.Driving2: - SetControllerActionState(playerNo, ControllerAction.Driving0, false); - SetControllerActionState(playerNo, ControllerAction.Driving1, false); - SetControllerActionState(playerNo, ControllerAction.Driving2, true); - SetControllerActionState(playerNo, ControllerAction.Driving3, false); - break; - case MachineInput.Driving3: - SetControllerActionState(playerNo, ControllerAction.Driving0, false); - SetControllerActionState(playerNo, ControllerAction.Driving1, false); - SetControllerActionState(playerNo, ControllerAction.Driving2, false); - SetControllerActionState(playerNo, ControllerAction.Driving3, true); - break; - case MachineInput.Reset: - SetConsoleSwitchState(ConsoleSwitch.GameReset, down); - break; - case MachineInput.Select: - SetConsoleSwitchState(ConsoleSwitch.GameSelect, down); - break; - case MachineInput.Color: - if (down) ToggleConsoleSwitchState(ConsoleSwitch.GameBW); - break; - case MachineInput.LeftDifficulty: - if (down) ToggleConsoleSwitchState(ConsoleSwitch.LeftDifficultyA); - break; - case MachineInput.RightDifficulty: - if (down) ToggleConsoleSwitchState(ConsoleSwitch.RightDifficultyA); - break; - } - } - - public void RaisePaddleInput(int playerNo, int valMax, int val) - { - var ohms = PaddleOhmMax - (PaddleOhmMax - PaddleOhmMin) / valMax * val; - _nextInputState[OhmsIndex + (playerNo & 3)] = ohms; - } - - public void RaiseLightgunPos(int playerNo, int scanline, int hpos) - { - var i = LightgunPositionIndex + ((playerNo & 1) << 1); - _nextInputState[i++] = scanline; - _nextInputState[i] = hpos; - } - - public void ClearAllInput() - { - _nextInputState[ConsoleSwitchIndex] = 0; - ClearLeftJackInput(); - ClearRightJackInput(); - } - - // For Bizhawk - // Emu7800's client does not call Clear input every frame so console switches behave like switches - // Bizhawk needs to call a clear input function every frame, if we put switches in there, they would behave like buttons - public void ClearControllerInput() - { - ClearLeftJackInput(); - ClearRightJackInput(); - } - - public void ClearInputByPlayer(int playerNo) - { - _nextInputState[OhmsIndex + (playerNo & 3)] = 0; - _nextInputState[ControllerActionStateIndex + (playerNo & 3)] = 0; - _nextInputState[LightgunPositionIndex + ((playerNo & 1) << 1)] = _nextInputState[LightgunPositionIndex + ((playerNo & 1) << 1) + 1] = 0; - } - - public void ClearLeftJackInput() - { - _nextInputState[OhmsIndex] = _nextInputState[OhmsIndex + 1] = 0; - _nextInputState[ControllerActionStateIndex] = 0; - switch (LeftControllerJack) - { - case Controller.Paddles: - _nextInputState[ControllerActionStateIndex] = _nextInputState[ControllerActionStateIndex + 1] = 0; - break; - default: - _nextInputState[ControllerActionStateIndex] = 0; - break; - } - _nextInputState[LightgunPositionIndex] = _nextInputState[LightgunPositionIndex + 1] = 0; - } - - public void ClearRightJackInput() - { - _nextInputState[OhmsIndex + 2] = _nextInputState[OhmsIndex + 3] = 0; - switch (RightControllerJack) - { - case Controller.Paddles: - _nextInputState[ControllerActionStateIndex + 2] = _nextInputState[ControllerActionStateIndex + 3] = 0; - break; - default: - _nextInputState[ControllerActionStateIndex + 1] = 0; - break; - } - _nextInputState[LightgunPositionIndex + 2] = _nextInputState[LightgunPositionIndex + 3] = 0; - } - - #endregion - - #region Serialization Members - - public InputState() - { - } - - public InputState(DeserializationContext input) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(2); - _rotState = input.ReadIntegers(2); - _nextInputState = input.ReadIntegers(InputStateSize); - _inputState = input.ReadIntegers(InputStateSize); - _lagged = input.ReadBoolean(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(2); - output.Write(_rotState); - output.Write(_nextInputState); - output.Write(_inputState); - output.Write(_lagged); - } - - #endregion - - #region Internal Members - - internal bool SampleCapturedConsoleSwitchState(ConsoleSwitch consoleSwitch) - { - _lagged = false; - return (_inputState[ConsoleSwitchIndex] & (1 << (int)consoleSwitch)) != 0; - } - - internal bool SampleCapturedControllerActionState(int playerno, ControllerAction action) - { - _lagged = false; - return (_inputState[ControllerActionStateIndex + (playerno & 3)] & (1 << (int)action)) != 0; - } - - internal int SampleCapturedOhmState(int playerNo) - { - _lagged = false; - return _inputState[OhmsIndex + (playerNo & 3)]; - } - - internal void SampleCapturedLightGunPosition(int playerNo, out int scanline, out int hpos) - { - _lagged = false; - var i = LightgunPositionIndex + ((playerNo & 1) << 1); - scanline = _inputState[i++]; - hpos = _inputState[i]; - } - - internal byte SampleCapturedDrivingState(int playerNo) - { - _lagged = false; - if (SampleCapturedControllerActionState(playerNo, ControllerAction.Driving0)) - _rotState[playerNo] = 0; - else if (SampleCapturedControllerActionState(playerNo, ControllerAction.Driving1)) - _rotState[playerNo] = 1; - else if (SampleCapturedControllerActionState(playerNo, ControllerAction.Driving2)) - _rotState[playerNo] = 2; - else if (SampleCapturedControllerActionState(playerNo, ControllerAction.Driving3)) - _rotState[playerNo] = 3; - return _rotGrayCodes[_rotState[playerNo]]; - } - - #endregion - - #region Object Overrides - - public override string ToString() - { - return GetType().Name; - } - - #endregion - - #region Helpers - - void SetControllerActionState(int playerNo, ControllerAction action, bool value) - { - if (value) - { - _nextInputState[ControllerActionStateIndex + (playerNo & 3)] |= (1 << (int)action); - } - else - { - _nextInputState[ControllerActionStateIndex + (playerNo & 3)] &= ~(1 << (int)action); - } - } - - void SetConsoleSwitchState(ConsoleSwitch consoleSwitch, bool value) - { - if (value) - { - _nextInputState[ConsoleSwitchIndex] |= (byte)(1 << (byte)consoleSwitch); - } - else - { - _nextInputState[ConsoleSwitchIndex] &= (byte)~(1 << (byte)consoleSwitch); - } - } - - void ToggleConsoleSwitchState(ConsoleSwitch consoleSwitch) - { - var consoleSwitchState = (_nextInputState[ConsoleSwitchIndex] & (1 << (int) consoleSwitch)) != 0; - SetConsoleSwitchState(consoleSwitch, !consoleSwitchState); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/LICENSE.TXT b/EMU7800/Core/LICENSE.TXT deleted file mode 100644 index d5354cb734..0000000000 --- a/EMU7800/Core/LICENSE.TXT +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19yy name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/EMU7800/Core/M6502.cs b/EMU7800/Core/M6502.cs deleted file mode 100644 index a8fb28db38..0000000000 --- a/EMU7800/Core/M6502.cs +++ /dev/null @@ -1,1099 +0,0 @@ -/* - * M6502.cs - * - * CPU emulator for the MOS Technology 6502 microprocessor. - * - * Copyright © 2003-2005 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class M6502 - { - delegate void OpcodeHandler(); - - OpcodeHandler[] Opcodes; - - const ushort - // non-maskable interrupt vector - NMI_VEC = 0xfffa, - // reset vector - RST_VEC = 0xfffc, - // interrupt request vector - IRQ_VEC = 0xfffe; - - readonly MachineBase M; - AddressSpace Mem { get { return M.Mem; } } - - public ulong Clock { get; set; } - public int RunClocks { get; set; } - public int RunClocksMultiple { get; private set; } - - public bool EmulatorPreemptRequest { get; set; } - public bool Jammed { get; set; } - public bool IRQInterruptRequest { get; set; } - public bool NMIInterruptRequest { get; set; } - - // 16-bit register - // program counter - public ushort PC { get; set; } - - // 8-bit registers - // accumulator - public byte A { get; set; } - // x index register - public byte X { get; set; } - // y index register - public byte Y { get; set; } - // stack pointer - public byte S { get; set; } - // processor status - public byte P { get; set; } - - public void Reset() - { - Jammed = false; - - // clear the stack - S = 0xff; - - fI = fZ = true; - - // reset the program counter - PC = WORD(Mem[RST_VEC], Mem[RST_VEC + 1]); - - clk(6); - - Log("{0} (PC:${1:x4}) reset", this, PC); - } - - public override String ToString() - { - return "M6502 CPU"; - } - - public void Execute() - { - EmulatorPreemptRequest = false; - - while (RunClocks > 0 && !EmulatorPreemptRequest && !Jammed) - { - if (NMIInterruptRequest) - { - InterruptNMI(); - NMIInterruptRequest = false; - } - else if (IRQInterruptRequest) - { - InterruptIRQ(); - IRQInterruptRequest = false; - } - else - { - Opcodes[Mem[PC++]](); - } - } - } - - private M6502() - { - InstallOpcodes(); - - Clock = 0; - RunClocks = 0; - RunClocksMultiple = 1; - - // initialize processor status, bit 5 is always set - P = 1 << 5; - } - - public M6502(MachineBase m, int runClocksMultiple) : this() - { - if (m == null) - throw new ArgumentNullException("m"); - if (runClocksMultiple <= 0) - throw new ArgumentException("runClocksMultiple must be greater than zero."); - - M = m; - RunClocksMultiple = runClocksMultiple; - } - - static byte MSB(ushort u16) - { - return (byte)(u16 >> 8); - } - - static byte LSB(ushort u16) - { - return (byte)u16; - } - - static ushort WORD(byte lsb, byte msb) - { - return (ushort)(lsb | msb << 8); - } - - // Processor Status Flag Bits - // - - // Flag bit setters and getters - void fset(byte flag, bool value) - { - P = (byte)(value ? P | flag : P & ~flag); - } - - bool fget(byte flag) - { - return (P & flag) != 0; - } - - // Carry: set if the add produced a carry, if the subtraction - // produced a borrow. Also used in shift instructions. - public bool fC - { - get { return fget(1 << 0); } - private set { fset(1 << 0, value); } - } - - // Zero: set if the result of the last operation was zero - public bool fZ - { - get { return fget(1 << 1); } - private set { fset(1 << 1, value); } - } - - // Irq Disable: set if maskable interrupts are disabled - public bool fI - { - get { return fget(1 << 2); } - private set { fset(1 << 2, value); } - } - - // Decimal Mode: set if decimal mode active - public bool fD - { - get { return fget(1 << 3); } - private set { fset(1 << 3, value); } - } - - // Brk: set if an interrupt caused by a BRK instruction, - // reset if caused by an internal interrupt - public bool fB - { - get { return fget(1 << 4); } - private set { fset(1 << 4, value); } - } - - // Overflow: set if the addition of two-like-signed numbers - // or the subtraction of two unlike-signed numbers - // produces a result greater than +127 or less than -128. - public bool fV - { - get { return fget(1 << 6); } - private set { fset(1 << 6, value); } - } - - // Negative: set if bit 7 of the accumulator is set - public bool fN - { - get { return fget(1 << 7); } - private set { fset(1 << 7, value); } - } - - void set_fNZ(byte u8) - { - fN = (u8 & 0x80) != 0; - fZ = (u8 & 0xff) == 0; - } - - byte pull() - { - S++; - return Mem[(ushort)(0x0100 + S)]; - } - - void push(byte data) - { - Mem[(ushort)(0x0100 + S)] = data; - S--; - } - - void clk(int ticks) - { - Clock += (ulong)ticks; - RunClocks -= (ticks*RunClocksMultiple); - } - - void InterruptNMI() - { - push(MSB(PC)); - push(LSB(PC)); - fB = false; - push(P); - fI = true; - PC = WORD(Mem[NMI_VEC], Mem[NMI_VEC + 1]); - clk(7); - } - - void InterruptIRQ() - { - if (IRQInterruptRequest && !fI) - { - push(MSB(PC)); - push(LSB(PC)); - fB = false; - push(P); - fI = true; - PC = WORD(Mem[IRQ_VEC], Mem[IRQ_VEC + 1]); - } - clk(7); - } - - void br(bool cond, ushort ea) - { - if (cond) - { - clk( (MSB(PC) == MSB(ea)) ? 1 : 2 ); - PC = ea; - } - } - - - // Relative: Bxx $aa (branch instructions only) - ushort aREL() - { - var bo = (sbyte)Mem[PC]; - PC++; - return (ushort)(PC + bo); - } - - // Zero Page: $aa - ushort aZPG() - { - return WORD(Mem[PC++], 0x00); - } - - // Zero Page Indexed,X: $aa,X - ushort aZPX() - { - return WORD((byte)(Mem[PC++] + X), 0x00); - } - - // Zero Page Indexed,Y: $aa,Y - ushort aZPY() - { - return WORD((byte)(Mem[PC++] + Y), 0x00); - } - - // Absolute: $aaaa - ushort aABS() - { - var lsb = Mem[PC++]; - var msb = Mem[PC++]; - return WORD(lsb, msb); - } - - // Absolute Indexed,X: $aaaa,X - ushort aABX(int eclk) - { - var ea = aABS(); - if (LSB(ea) + X > 0xff) - { - clk(eclk); - } - return (ushort)(ea + X); - } - - // Absolute Indexed,Y: $aaaa,Y - ushort aABY(int eclk) - { - var ea = aABS(); - if (LSB(ea) + Y > 0xff) - { - clk(eclk); - } - return (ushort)(ea + Y); - } - - // Indexed Indirect: ($aa,X) - ushort aIDX() - { - var zpa = (byte)(Mem[PC++] + X); - var lsb = Mem[zpa++]; - var msb = Mem[zpa]; - return WORD(lsb, msb); - } - - // Indirect Indexed: ($aa),Y - ushort aIDY(int eclk) - { - var zpa = Mem[PC++]; - var lsb = Mem[zpa++]; - var msb = Mem[zpa]; - if (lsb + Y > 0xff) - { - clk(eclk); - } - return (ushort)(WORD(lsb, msb) + Y); - } - - // Indirect Absolute: ($aaaa) (only used by JMP) - ushort aIND() - { - var ea = aABS(); - var lsb = Mem[ea]; - ea = WORD((byte)(LSB(ea) + 1), MSB(ea)); // NMOS 6502/7 quirk: does not fetch across page boundaries - var msb = Mem[ea]; - return WORD(lsb, msb); - } - - // aACC = Accumulator - // aIMM = Immediate - // aIMP = Implied - - // ADC: Add with carry - void iADC(byte mem) - { - var c = fC ? 1 : 0; - var sum = A + mem + c; - fV = (~(A ^ mem) & (A ^ (sum & 0xff)) & 0x80) != 0; - if (fD) - { - // NMOS 6502/7 quirk: The N, V, and Z flags reflect the binary result, not the BCD result - var lo = (A & 0xf) + (mem & 0xf) + c; - var hi = (A >> 4) + (mem >> 4); - if (lo > 9) - { - lo += 6; - hi++; - } - if (hi > 9) - { - hi += 6; - } - A = (byte)((lo & 0xf) | (hi << 4)); - fC = (hi & 0x10) != 0; - } - else - { - A = (byte)sum; - fC = (sum & 0x100) != 0; - } - set_fNZ((byte)sum); - } - - // AND: Logical and - void iAND(byte mem) - { - A &= mem; - set_fNZ(A); - } - - // ASL: Arithmetic shift left: C <- [7][6][5][4][3][2][1][0] <- 0 - byte iASL(byte mem) - { - fC = (mem & 0x80) != 0; - mem <<= 1; - set_fNZ(mem); - return mem; - } - - // BIT: Bit test - void iBIT(byte mem) - { - fN = (mem & 0x80) != 0; - fV = (mem & 0x40) != 0; - fZ = (mem & A) == 0; - } - - // BRK Force Break (cause software interrupt) - void iBRK() - { - PC++; - fB = true; - push(MSB(PC)); - push(LSB(PC)); - push(P); - fI = true; - var lsb = Mem[IRQ_VEC]; - var msb = Mem[IRQ_VEC+1]; - PC = WORD(lsb, msb); - } - - // CLC: Clear carry flag - void iCLC() - { - fC = false; - } - - // CLD: Clear decimal mode - void iCLD() - { - fD = false; - } - - // CLI: Clear interrupt disable */ - void iCLI() - { - fI = false; - } - - // CLV: Clear overflow flag - void iCLV() - { - fV = false; - } - - // CMP: Compare accumulator - void iCMP(byte mem) - { - fC = A >= mem; - set_fNZ((byte)(A - mem)); - } - - // CPX: Compare index X - void iCPX(byte mem) - { - fC = X >= mem; - set_fNZ((byte)(X - mem)); - } - - // CPY: Compare index Y - void iCPY(byte mem) - { - fC = Y >= mem; - set_fNZ((byte)(Y - mem)); - } - - // DEC: Decrement memory - byte iDEC(byte mem) - { - mem--; - set_fNZ(mem); - return mem; - } - - // DEX: Decrement index x - void iDEX() - { - X--; - set_fNZ(X); - } - - // DEY: Decrement index y - void iDEY() - { - Y--; - set_fNZ(Y); - } - - // EOR: Logical exclusive or - void iEOR(byte mem) - { - A ^= mem; - set_fNZ(A); - } - - // INC: Increment memory - byte iINC(byte mem) - { - mem++; - set_fNZ(mem); - return mem; - } - - // INX: Increment index x - void iINX() - { - X++; - set_fNZ(X); - } - - // INY: Increment index y - void iINY() - { - Y++; - set_fNZ(Y); - } - - // JMP Jump to address - void iJMP(ushort ea) - { - PC = ea; - } - - // JSR Jump to subroutine - void iJSR(ushort ea) - { - PC--; // NMOS 6502/7 quirk: iRTS compensates - push(MSB(PC)); - push(LSB(PC)); - PC = ea; - } - - // LDA: Load accumulator - void iLDA(byte mem) - { - A = mem; - set_fNZ(A); - } - - // LDX: Load index X - void iLDX(byte mem) - { - X = mem; - set_fNZ(X); - } - - // LDY: Load index Y - void iLDY(byte mem) - { - Y = mem; - set_fNZ(Y); - } - - // LSR: Logic shift right: 0 -> [7][6][5][4][3][2][1][0] -> C - byte iLSR(byte mem) - { - fC = (mem & 0x01) != 0; - mem >>= 1; - set_fNZ(mem); - return mem; - } - - // NOP: No operation - void iNOP() - { - if (M.NOPRegisterDumping) - { - Log("NOP: {0}", M6502DASM.GetRegisters(this)); - } - } - - // ORA: Logical inclusive or - void iORA(byte mem) - { - A |= mem; - set_fNZ(A); - } - - // PHA: Push accumulator - void iPHA() - { - push(A); - } - - // PHP: Push processor status (flags) - void iPHP() - { - push(P); - } - - // PLA: Pull accumuator - void iPLA() - { - A = pull(); - set_fNZ(A); - } - - // PLP: Pull processor status (flags) - void iPLP() - { - P = pull(); - fB = true; - } - - // ROL: Rotate left: new C <- [7][6][5][4][3][2][1][0] <- C - byte iROL(byte mem) - { - var d0 = (byte)(fC ? 0x01 : 0x00); - - fC = (mem & 0x80) != 0; - mem <<= 1; - mem |= d0; - set_fNZ(mem); - return mem; - } - - // ROR: Rotate right: C -> [7][6][5][4][3][2][1][0] -> new C - byte iROR(byte mem) - { - var d7 = (byte)(fC ? 0x80 : 0x00); - - fC = (mem & 0x01) != 0; - mem >>= 1; - mem |= d7; - set_fNZ(mem); - return mem; - } - - // RTI: Return from interrupt - void iRTI() - { - P = pull(); - var lsb = pull(); - var msb = pull(); - PC = WORD(lsb, msb); - fB = true; - } - - // RTS: Return from subroutine - void iRTS() - { - var lsb = pull(); - var msb = pull(); - PC = WORD(lsb, msb); - PC++; // NMOS 6502/7 quirk: iJSR compensates - } - - // SBC: Subtract with carry (borrow) - void iSBC(byte mem) - { - var c = fC ? 0 : 1; - var sum = A - mem - c; - fV = ((A ^ mem) & (A ^ (sum & 0xff)) & 0x80) != 0; - if (fD) - { - // NMOS 6502/7 quirk: The N, V, and Z flags reflect the binary result, not the BCD result - var lo = (A & 0xf) - (mem & 0xf) - c; - var hi = (A >> 4) - (mem >> 4); - if ((lo & 0x10) != 0) - { - lo -= 6; - hi--; - } - if ((hi & 0x10) != 0) - { - hi -= 6; - } - A = (byte)((lo & 0xf) | (hi << 4)); - } - else - { - A = (byte)sum; - } - fC = (sum & 0x100) == 0; - set_fNZ((byte)sum); - } - - // SEC: Set carry flag - void iSEC() - { - fC = true; - } - - // SED: Set decimal mode - void iSED() - { - fD = true; - } - - // SEI: Set interrupt disable - void iSEI() - { - fI = true; - } - - // STA: Store accumulator - byte iSTA() - { - return A; - } - - // STX: Store index X - byte iSTX() - { - return X; - } - - // STY: Store index Y - byte iSTY() - { - return Y; - } - - // TAX: Transfer accumlator to index X - void iTAX() - { - X = A; - set_fNZ(X); - } - - // TAY: Transfer accumlator to index Y - void iTAY() - { - Y = A; - set_fNZ(Y); - } - - // TSX: Transfer stack to index X - void iTSX() - { - X = S; - set_fNZ(X); - } - - // TXA: Transfer index X to accumlator - void iTXA() - { - A = X; - set_fNZ(A); - } - - // TXS: Transfer index X to stack - void iTXS() - { - S = X; - // No flags set..! Weird, huh? - } - - // TYA: Transfer index Y to accumulator - void iTYA() - { - A = Y; - set_fNZ(A); - } - - // Illegal opcodes - - // KIL: Jam the processor - void iKIL() - { - Jammed = true; - Log("{0}: Processor jammed!", this); - } - - // LAX: Load accumulator and index x - void iLAX(byte mem) - { - A = X = mem; - set_fNZ(A); - } - - // ISB: Increment and subtract with carry - void iISB(byte mem) - { - mem++; - iSBC(mem); - } - - // RLA: Rotate left and logical and accumulator - // new C <- [7][6][5][4][3][2][1][0] <- C - void iRLA(byte mem) - { - var d0 = (byte)(fC ? 0x01 : 0x00); - - fC = (mem & 0x80) != 0; - mem <<= 1; - mem |= d0; - - A &= mem; - set_fNZ(A); - } - - // SAX: logical and accumulator with index X and store - byte iSAX() - { - return (byte)(A & X); - } - - void InstallOpcodes() - { - Opcodes = new OpcodeHandler[0x100]; - ushort EA; - - Opcodes[0x65] = delegate { EA = aZPG(); clk(3); iADC(Mem[EA]); }; - Opcodes[0x75] = delegate { EA = aZPX(); clk(4); iADC(Mem[EA]); }; - Opcodes[0x61] = delegate { EA = aIDX(); clk(6); iADC(Mem[EA]); }; - Opcodes[0x71] = delegate { EA = aIDY(1); clk(5); iADC(Mem[EA]); }; - Opcodes[0x79] = delegate { EA = aABY(1); clk(4); iADC(Mem[EA]); }; - Opcodes[0x6d] = delegate { EA = aABS(); clk(4); iADC(Mem[EA]); }; - Opcodes[0x7d] = delegate { EA = aABX(1); clk(4); iADC(Mem[EA]); }; - Opcodes[0x69] = delegate { /*aIMM*/ clk(2); iADC(Mem[PC++]); }; - - Opcodes[0x25] = delegate { EA = aZPG(); clk(3); iAND(Mem[EA]); }; // may be 2 clk - Opcodes[0x35] = delegate { EA = aZPX(); clk(4); iAND(Mem[EA]); }; // may be 3 clk - Opcodes[0x21] = delegate { EA = aIDX(); clk(6); iAND(Mem[EA]); }; - Opcodes[0x31] = delegate { EA = aIDY(1); clk(5); iAND(Mem[EA]); }; - Opcodes[0x2d] = delegate { EA = aABS(); clk(4); iAND(Mem[EA]); }; - Opcodes[0x39] = delegate { EA = aABY(1); clk(4); iAND(Mem[EA]); }; - Opcodes[0x3d] = delegate { EA = aABX(1); clk(4); iAND(Mem[EA]); }; - Opcodes[0x29] = delegate { /*aIMM*/ clk(2); iAND(Mem[PC++]); }; - - Opcodes[0x06] = delegate { EA = aZPG(); clk(5); Mem[EA] = iASL(Mem[EA]); }; - Opcodes[0x16] = delegate { EA = aZPX(); clk(6); Mem[EA] = iASL(Mem[EA]); }; - Opcodes[0x0e] = delegate { EA = aABS(); clk(6); Mem[EA] = iASL(Mem[EA]); }; - Opcodes[0x1e] = delegate { EA = aABX(0); clk(7); Mem[EA] = iASL(Mem[EA]); }; - Opcodes[0x0a] = delegate { /*aACC*/ clk(2); A = iASL(A); }; - - Opcodes[0x24] = delegate { EA = aZPG(); clk(3); iBIT(Mem[EA]); }; - Opcodes[0x2c] = delegate { EA = aABS(); clk(4); iBIT(Mem[EA]); }; - - Opcodes[0x10] = delegate { EA = aREL(); clk(2); br(!fN, EA); /* BPL */ }; - Opcodes[0x30] = delegate { EA = aREL(); clk(2); br( fN, EA); /* BMI */ }; - Opcodes[0x50] = delegate { EA = aREL(); clk(2); br(!fV, EA); /* BVC */ }; - Opcodes[0x70] = delegate { EA = aREL(); clk(2); br( fV, EA); /* BVS */ }; - Opcodes[0x90] = delegate { EA = aREL(); clk(2); br(!fC, EA); /* BCC */ }; - Opcodes[0xb0] = delegate { EA = aREL(); clk(2); br( fC, EA); /* BCS */ }; - Opcodes[0xd0] = delegate { EA = aREL(); clk(2); br(!fZ, EA); /* BNE */ }; - Opcodes[0xf0] = delegate { EA = aREL(); clk(2); br( fZ, EA); /* BEQ */ }; - - Opcodes[0x00] = delegate { /*aIMP*/ clk(7); iBRK(); }; - - Opcodes[0x18] = delegate { /*aIMP*/ clk(2); iCLC(); }; - - Opcodes[0xd8] = delegate { /*aIMP*/ clk(2); iCLD(); }; - - Opcodes[0x58] = delegate { /*aIMP*/ clk(2); iCLI(); }; - - Opcodes[0xb8] = delegate { /*aIMP*/ clk(2); iCLV(); }; - - Opcodes[0xc5] = delegate { EA = aZPG(); clk(3); iCMP(Mem[EA]); }; - Opcodes[0xd5] = delegate { EA = aZPX(); clk(4); iCMP(Mem[EA]); }; - Opcodes[0xc1] = delegate { EA = aIDX(); clk(6); iCMP(Mem[EA]); }; - Opcodes[0xd1] = delegate { EA = aIDY(1); clk(5); iCMP(Mem[EA]); }; - Opcodes[0xcd] = delegate { EA = aABS(); clk(4); iCMP(Mem[EA]); }; - Opcodes[0xdd] = delegate { EA = aABX(1); clk(4); iCMP(Mem[EA]); }; - Opcodes[0xd9] = delegate { EA = aABY(1); clk(4); iCMP(Mem[EA]); }; - Opcodes[0xc9] = delegate { /*aIMM*/ clk(2); iCMP(Mem[PC++]); }; - - Opcodes[0xe4] = delegate { EA = aZPG(); clk(3); iCPX(Mem[EA]); }; - Opcodes[0xec] = delegate { EA = aABS(); clk(4); iCPX(Mem[EA]); }; - Opcodes[0xe0] = delegate { /*aIMM*/ clk(2); iCPX(Mem[PC++]); }; - - Opcodes[0xc4] = delegate { EA = aZPG(); clk(3); iCPY(Mem[EA]); }; - Opcodes[0xcc] = delegate { EA = aABS(); clk(4); iCPY(Mem[EA]); }; - Opcodes[0xc0] = delegate { /*aIMM*/ clk(2); iCPY(Mem[PC++]); }; - - Opcodes[0xc6] = delegate { EA = aZPG(); clk(5); Mem[EA] = iDEC(Mem[EA]); }; - Opcodes[0xd6] = delegate { EA = aZPX(); clk(6); Mem[EA] = iDEC(Mem[EA]); }; - Opcodes[0xce] = delegate { EA = aABS(); clk(6); Mem[EA] = iDEC(Mem[EA]); }; - Opcodes[0xde] = delegate { EA = aABX(0); clk(7); Mem[EA] = iDEC(Mem[EA]); }; - - Opcodes[0xca] = delegate { /*aIMP*/ clk(2); iDEX(); }; - - Opcodes[0x88] = delegate { /*aIMP*/ clk(2); iDEY(); }; - - Opcodes[0x45] = delegate { EA = aZPG(); clk(3); iEOR(Mem[EA]); }; - Opcodes[0x55] = delegate { EA = aZPX(); clk(4); iEOR(Mem[EA]); }; - Opcodes[0x41] = delegate { EA = aIDX(); clk(6); iEOR(Mem[EA]); }; - Opcodes[0x51] = delegate { EA = aIDY(1); clk(5); iEOR(Mem[EA]); }; - Opcodes[0x4d] = delegate { EA = aABS(); clk(4); iEOR(Mem[EA]); }; - Opcodes[0x5d] = delegate { EA = aABX(1); clk(4); iEOR(Mem[EA]); }; - Opcodes[0x59] = delegate { EA = aABY(1); clk(4); iEOR(Mem[EA]); }; - Opcodes[0x49] = delegate { /*aIMM*/ clk(2); iEOR(Mem[PC++]); }; - - Opcodes[0xe6] = delegate { EA = aZPG(); clk(5); Mem[EA] = iINC(Mem[EA]); }; - Opcodes[0xf6] = delegate { EA = aZPX(); clk(6); Mem[EA] = iINC(Mem[EA]); }; - Opcodes[0xee] = delegate { EA = aABS(); clk(6); Mem[EA] = iINC(Mem[EA]); }; - Opcodes[0xfe] = delegate { EA = aABX(0); clk(7); Mem[EA] = iINC(Mem[EA]); }; - - Opcodes[0xe8] = delegate { /*aIMP*/ clk(2); iINX(); }; - - Opcodes[0xc8] = delegate { /*aIMP*/ clk(2); iINY(); }; - - Opcodes[0xa5] = delegate { EA = aZPG(); clk(3); iLDA(Mem[EA]); }; - Opcodes[0xb5] = delegate { EA = aZPX(); clk(4); iLDA(Mem[EA]); }; - Opcodes[0xa1] = delegate { EA = aIDX(); clk(6); iLDA(Mem[EA]); }; - Opcodes[0xb1] = delegate { EA = aIDY(1); clk(5); iLDA(Mem[EA]); }; - Opcodes[0xad] = delegate { EA = aABS(); clk(4); iLDA(Mem[EA]); }; - Opcodes[0xbd] = delegate { EA = aABX(1); clk(4); iLDA(Mem[EA]); }; - Opcodes[0xb9] = delegate { EA = aABY(1); clk(4); iLDA(Mem[EA]); }; - Opcodes[0xa9] = delegate { /*aIMM*/ clk(2); iLDA(Mem[PC++]); }; - - Opcodes[0xa6] = delegate { EA = aZPG(); clk(3); iLDX(Mem[EA]); }; - Opcodes[0xb6] = delegate { EA = aZPY(); clk(4); iLDX(Mem[EA]); }; - Opcodes[0xae] = delegate { EA = aABS(); clk(4); iLDX(Mem[EA]); }; - Opcodes[0xbe] = delegate { EA = aABY(1); clk(4); iLDX(Mem[EA]); }; - Opcodes[0xa2] = delegate { /*aIMM*/ clk(2); iLDX(Mem[PC++]); }; - - Opcodes[0xa4] = delegate { EA = aZPG(); clk(3); iLDY(Mem[EA]); }; - Opcodes[0xb4] = delegate { EA = aZPX(); clk(4); iLDY(Mem[EA]); }; - Opcodes[0xac] = delegate { EA = aABS(); clk(4); iLDY(Mem[EA]); }; - Opcodes[0xbc] = delegate { EA = aABX(1); clk(4); iLDY(Mem[EA]); }; - Opcodes[0xa0] = delegate { /*aIMM*/ clk(2); iLDY(Mem[PC++]); }; - - Opcodes[0x46] = delegate { EA = aZPG(); clk(5); Mem[EA] = iLSR(Mem[EA]); }; - Opcodes[0x56] = delegate { EA = aZPX(); clk(6); Mem[EA] = iLSR(Mem[EA]); }; - Opcodes[0x4e] = delegate { EA = aABS(); clk(6); Mem[EA] = iLSR(Mem[EA]); }; - Opcodes[0x5e] = delegate { EA = aABX(0); clk(7); Mem[EA] = iLSR(Mem[EA]); }; - Opcodes[0x4a] = delegate { /*aACC*/ clk(2); A = iLSR(A); }; - - Opcodes[0x4c] = delegate { EA = aABS(); clk(3); iJMP(EA); }; - Opcodes[0x6c] = delegate { EA = aIND(); clk(5); iJMP(EA); }; - - Opcodes[0x20] = delegate { EA = aABS(); clk(6); iJSR(EA); }; - - Opcodes[0xea] = delegate { /*aIMP*/ clk(2); iNOP(); }; - - Opcodes[0x05] = delegate { EA = aZPG(); clk(3); iORA(Mem[EA]); }; // may be 2 clk - Opcodes[0x15] = delegate { EA = aZPX(); clk(4); iORA(Mem[EA]); }; // may be 3 clk - Opcodes[0x01] = delegate { EA = aIDX(); clk(6); iORA(Mem[EA]); }; - Opcodes[0x11] = delegate { EA = aIDY(1); clk(5); iORA(Mem[EA]); }; - Opcodes[0x0d] = delegate { EA = aABS(); clk(4); iORA(Mem[EA]); }; - Opcodes[0x1d] = delegate { EA = aABX(1); clk(4); iORA(Mem[EA]); }; - Opcodes[0x19] = delegate { EA = aABY(1); clk(4); iORA(Mem[EA]); }; - Opcodes[0x09] = delegate { /*aIMM*/ clk(2); iORA(Mem[PC++]); }; - - Opcodes[0x48] = delegate { /*aIMP*/ clk(3); iPHA(); }; - - Opcodes[0x68] = delegate { /*aIMP*/ clk(4); iPLA(); }; - - Opcodes[0x08] = delegate { /*aIMP*/ clk(3); iPHP(); }; - - Opcodes[0x28] = delegate { /*aIMP*/ clk(4); iPLP(); }; - - Opcodes[0x26] = delegate { EA = aZPG(); clk(5); Mem[EA] = iROL(Mem[EA]); }; - Opcodes[0x36] = delegate { EA = aZPX(); clk(6); Mem[EA] = iROL(Mem[EA]); }; - Opcodes[0x2e] = delegate { EA = aABS(); clk(6); Mem[EA] = iROL(Mem[EA]); }; - Opcodes[0x3e] = delegate { EA = aABX(0); clk(7); Mem[EA] = iROL(Mem[EA]); }; - Opcodes[0x2a] = delegate { /*aACC*/ clk(2); A = iROL(A); }; - - Opcodes[0x66] = delegate { EA = aZPG(); clk(5); Mem[EA] = iROR(Mem[EA]); }; - Opcodes[0x76] = delegate { EA = aZPX(); clk(6); Mem[EA] = iROR(Mem[EA]); }; - Opcodes[0x6e] = delegate { EA = aABS(); clk(6); Mem[EA] = iROR(Mem[EA]); }; - Opcodes[0x7e] = delegate { EA = aABX(0); clk(7); Mem[EA] = iROR(Mem[EA]); }; - Opcodes[0x6a] = delegate { /*aACC*/ clk(2); A = iROR(A); }; - - Opcodes[0x40] = delegate { /*aIMP*/ clk(6); iRTI(); }; - - Opcodes[0x60] = delegate { /*aIMP*/ clk(6); iRTS(); }; - - Opcodes[0xe5] = delegate { EA = aZPG(); clk(3); iSBC(Mem[EA]); }; - Opcodes[0xf5] = delegate { EA = aZPX(); clk(4); iSBC(Mem[EA]); }; - Opcodes[0xe1] = delegate { EA = aIDX(); clk(6); iSBC(Mem[EA]); }; - Opcodes[0xf1] = delegate { EA = aIDY(1); clk(5); iSBC(Mem[EA]); }; - Opcodes[0xed] = delegate { EA = aABS(); clk(4); iSBC(Mem[EA]); }; - Opcodes[0xfd] = delegate { EA = aABX(1); clk(4); iSBC(Mem[EA]); }; - Opcodes[0xf9] = delegate { EA = aABY(1); clk(4); iSBC(Mem[EA]); }; - Opcodes[0xe9] = delegate { /*aIMM*/ clk(2); iSBC(Mem[PC++]); }; - - Opcodes[0x38] = delegate { /*aIMP*/ clk(2); iSEC(); }; - - Opcodes[0xf8] = delegate { /*aIMP*/ clk(2); iSED(); }; - - Opcodes[0x78] = delegate { /*aIMP*/ clk(2); iSEI(); }; - - Opcodes[0x85] = delegate { EA = aZPG(); clk(3); Mem[EA] = iSTA(); }; - Opcodes[0x95] = delegate { EA = aZPX(); clk(4); Mem[EA] = iSTA(); }; - Opcodes[0x81] = delegate { EA = aIDX(); clk(6); Mem[EA] = iSTA(); }; - Opcodes[0x91] = delegate { EA = aIDY(0); clk(6); Mem[EA] = iSTA(); }; - Opcodes[0x8d] = delegate { EA = aABS(); clk(4); Mem[EA] = iSTA(); }; - Opcodes[0x99] = delegate { EA = aABY(0); clk(5); Mem[EA] = iSTA(); }; - Opcodes[0x9d] = delegate { EA = aABX(0); clk(5); Mem[EA] = iSTA(); }; - - Opcodes[0x86] = delegate { EA = aZPG(); clk(3); Mem[EA] = iSTX(); }; - Opcodes[0x96] = delegate { EA = aZPY(); clk(4); Mem[EA] = iSTX(); }; - Opcodes[0x8e] = delegate { EA = aABS(); clk(4); Mem[EA] = iSTX(); }; - - Opcodes[0x84] = delegate { EA = aZPG(); clk(3); Mem[EA] = iSTY(); }; - Opcodes[0x94] = delegate { EA = aZPX(); clk(4); Mem[EA] = iSTY(); }; - Opcodes[0x8c] = delegate { EA = aABS(); clk(4); Mem[EA] = iSTY(); }; - - Opcodes[0xaa] = delegate { /*aIMP*/ clk(2); iTAX(); }; - - Opcodes[0xa8] = delegate { /*aIMP*/ clk(2); iTAY(); }; - - Opcodes[0xba] = delegate { /*aIMP*/ clk(2); iTSX(); }; - - Opcodes[0x8a] = delegate { /*aIMP*/ clk(2); iTXA(); }; - - Opcodes[0x9a] = delegate { /*aIMP*/ clk(2); iTXS(); }; - - Opcodes[0x98] = delegate { /*aIMP*/ clk(2); iTYA(); }; - - // Illegal opcodes - foreach (int opCode in new ushort[] { 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x92, 0xb2, 0xd2, 0xf2 }) - { - Opcodes[opCode] = delegate { clk(2); iKIL(); }; - } - Opcodes[0x3f] = delegate { EA = aABX(0); clk(4); iRLA(Mem[EA]); }; - Opcodes[0xa7] = delegate { EA = aZPX(); clk(3); iLAX(Mem[EA]); }; - Opcodes[0xb3] = delegate { EA = aIDY(0); clk(6); iLAX(Mem[EA]); }; - Opcodes[0xef] = delegate { EA = aABS(); clk(6); iISB(Mem[EA]); }; - Opcodes[0x0c] = delegate { EA = aABS(); clk(2); iNOP(); }; - foreach (int opCode in new ushort[] { 0x1c, 0x3c, 0x5c, 0x7c, 0x9c, 0xdc, 0xfc }) - { - Opcodes[opCode] = delegate { EA = aABX(0); clk(2); iNOP(); }; - } - Opcodes[0x83] = delegate { EA = aIDX(); clk(6); Mem[EA] = iSAX(); }; - Opcodes[0x87] = delegate { EA = aZPG(); clk(3); Mem[EA] = iSAX(); }; - Opcodes[0x8f] = delegate { EA = aABS(); clk(4); Mem[EA] = iSAX(); }; - Opcodes[0x97] = delegate { EA = aZPY(); clk(4); Mem[EA] = iSAX(); }; - Opcodes[0xa3] = delegate { EA = aIDX(); clk(6); iLAX(Mem[EA]); }; - Opcodes[0xb7] = delegate { EA = aZPY(); clk(4); iLAX(Mem[EA]); }; - Opcodes[0xaf] = delegate { EA = aABS(); clk(5); iLAX(Mem[EA]); }; - Opcodes[0xbf] = delegate { EA = aABY(0); clk(6); iLAX(Mem[EA]); }; - Opcodes[0xff] = delegate { EA = aABX(0); clk(7); iISB(Mem[EA]); }; - - OpcodeHandler opNULL = () => Log("{0}:**UNKNOWN OPCODE: ${1:x2} at ${2:x4}\n", this, Mem[(ushort)(PC - 1)], PC - 1); - - for (var i=0; i < Opcodes.Length; i++) - { - if (Opcodes[i] == null) - { - Opcodes[i] = opNULL; - } - } - } - - #region Serialization Members - - public M6502(DeserializationContext input, MachineBase m, int runClocksMultiple) : this(m, runClocksMultiple) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - Clock = input.ReadUInt64(); - RunClocks = input.ReadInt32(); - RunClocksMultiple = input.ReadInt32(); - EmulatorPreemptRequest = input.ReadBoolean(); - Jammed = input.ReadBoolean(); - IRQInterruptRequest = input.ReadBoolean(); - NMIInterruptRequest = input.ReadBoolean(); - PC = input.ReadUInt16(); - A = input.ReadByte(); - X = input.ReadByte(); - Y = input.ReadByte(); - S = input.ReadByte(); - P = input.ReadByte(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(Clock); - output.Write(RunClocks); - output.Write(RunClocksMultiple); - output.Write(EmulatorPreemptRequest); - output.Write(Jammed); - output.Write(IRQInterruptRequest); - output.Write(NMIInterruptRequest); - output.Write(PC); - output.Write(A); - output.Write(X); - output.Write(Y); - output.Write(S); - output.Write(P); - } - - #endregion - - #region Helpers - - void Log(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/M6502DASM.cs b/EMU7800/Core/M6502DASM.cs deleted file mode 100644 index 4f36060edc..0000000000 --- a/EMU7800/Core/M6502DASM.cs +++ /dev/null @@ -1,242 +0,0 @@ -/* - * M6502DASM.cs - * - * Provides disassembly services. - * - * Copyright © 2003, 2004 Mike Murphy - * - */ -using System; -using System.Text; - -namespace EMU7800.Core -{ - public static class M6502DASM - { - // Instruction Mnemonics - enum m : uint - { - ADC = 1, AND, ASL, - BIT, BCC, BCS, BEQ, BMI, BNE, BPL, BRK, BVC, BVS, - CLC, CLD, CLI, CLV, CMP, CPX, CPY, - DEC, DEX, DEY, - EOR, - INC, INX, INY, - JMP, JSR, - LDA, LDX, LDY, LSR, - NOP, - ORA, - PLA, PLP, PHA, PHP, - ROL, ROR, RTI, RTS, - SEC, SEI, STA, SBC, SED, STX, STY, - TAX, TAY, TSX, TXA, TXS, TYA, - - // Illegal/undefined opcodes - isb, - kil, - lax, - rla, - sax, - top - } - - // Addressing Modes - enum a : uint - { - REL, // Relative: $aa (branch instructions only) - ZPG, // Zero Page: $aa - ZPX, // Zero Page Indexed X: $aa,X - ZPY, // Zero Page Indexed Y: $aa,Y - ABS, // Absolute: $aaaa - ABX, // Absolute Indexed X: $aaaa,X - ABY, // Absolute Indexed Y: $aaaa,Y - IDX, // Indexed Indirect: ($aa,X) - IDY, // Indirect Indexed: ($aa),Y - IND, // Indirect Absolute: ($aaaa) (JMP only) - IMM, // Immediate: #aa - IMP, // Implied - ACC // Accumulator - } - - static readonly m[] MnemonicMatrix = { -// 0 1 2 3 4 5 6 7 8 9 A B C D E F -/*0*/ m.BRK, m.ORA, m.kil, 0, 0, m.ORA, m.ASL, 0, m.PHP, m.ORA, m.ASL, 0, m.top, m.ORA, m.ASL, 0,/*0*/ -/*1*/ m.BPL, m.ORA, m.kil, 0, 0, m.ORA, m.ASL, 0, m.CLC, m.ORA, 0, 0, m.top, m.ORA, m.ASL, 0,/*1*/ -/*2*/ m.JSR, m.AND, m.kil, 0, m.BIT, m.AND, m.ROL, 0, m.PLP, m.AND, m.ROL, 0, m.BIT, m.AND, m.ROL, 0,/*2*/ -/*3*/ m.BMI, m.AND, m.kil, 0, 0, m.AND, m.ROL, 0, m.SEC, m.AND, 0, 0, m.top, m.AND, m.ROL, m.rla,/*3*/ -/*4*/ m.RTI, m.EOR, m.kil, 0, 0, m.EOR, m.LSR, 0, m.PHA, m.EOR, m.LSR, 0, m.JMP, m.EOR, m.LSR, 0,/*4*/ -/*5*/ m.BVC, m.EOR, m.kil, 0, 0, m.EOR, m.LSR, 0, m.CLI, m.EOR, 0, 0, m.top, m.EOR, m.LSR, 0,/*5*/ -/*6*/ m.RTS, m.ADC, m.kil, 0, 0, m.ADC, m.ROR, 0, m.PLA, m.ADC, m.ROR, 0, m.JMP, m.ADC, m.ROR, 0,/*6*/ -/*7*/ m.BVS, m.ADC, m.kil, 0, 0, m.ADC, m.ROR, 0, m.SEI, m.ADC, 0, 0, m.top, m.ADC, m.ROR, 0,/*7*/ -/*8*/ 0, m.STA, 0, m.sax, m.STY, m.STA, m.STX, m.sax, m.DEY, 0, m.TXA, 0, m.STY, m.STA, m.STX, m.sax,/*8*/ -/*9*/ m.BCC, m.STA, m.kil, 0, m.STY, m.STA, m.STX, m.sax, m.TYA, m.STA, m.TXS, 0, m.top, m.STA, 0, 0,/*9*/ -/*A*/ m.LDY, m.LDA, m.LDX, m.lax, m.LDY, m.LDA, m.LDX, m.lax, m.TAY, m.LDA, m.TAX, 0, m.LDY, m.LDA, m.LDX, m.lax,/*A*/ -/*B*/ m.BCS, m.LDA, m.kil, m.lax, m.LDY, m.LDA, m.LDX, m.lax, m.CLV, m.LDA, m.TSX, 0, m.LDY, m.LDA, m.LDX, m.lax,/*B*/ -/*C*/ m.CPY, m.CMP, 0, 0, m.CPY, m.CMP, m.DEC, 0, m.INY, m.CMP, m.DEX, 0, m.CPY, m.CMP, m.DEC, 0,/*C*/ -/*D*/ m.BNE, m.CMP, m.kil, 0, 0, m.CMP, m.DEC, 0, m.CLD, m.CMP, 0, 0, m.top, m.CMP, m.DEC, 0,/*D*/ -/*E*/ m.CPX, m.SBC, 0, 0, m.CPX, m.SBC, m.INC, 0, m.INX, m.SBC, m.NOP, 0, m.CPX, m.SBC, m.INC, m.isb,/*E*/ -/*F*/ m.BEQ, m.SBC, m.kil, 0, 0, m.SBC, m.INC, 0, m.SED, m.SBC, 0, 0, m.top, m.SBC, m.INC, m.isb /*F*/ -}; - - static readonly a[] AddressingModeMatrix = { -// 0 1 2 3 4 5 6 7 8 9 A B C D E F -/*0*/ a.IMP, a.IDX, a.IMP, 0, 0, a.ZPG, a.ZPG, 0, a.IMP, a.IMM, a.ACC, 0, a.ABS, a.ABS, a.ABS, 0,/*0*/ -/*1*/ a.REL, a.IDY, a.IMP, 0, 0, a.ZPG, a.ZPG, 0, a.IMP, a.ABY, 0, 0, a.ABS, a.ABX, a.ABX, 0,/*1*/ -/*2*/ a.ABS, a.IDX, a.IMP, 0, a.ZPG, a.ZPG, a.ZPG, 0, a.IMP, a.IMM, a.ACC, 0, a.ABS, a.ABS, a.ABS, 0,/*2*/ -/*3*/ a.REL, a.IDY, a.IMP, 0, 0, a.ZPG, a.ZPG, 0, a.IMP, a.ABY, 0, 0, a.ABS, a.ABX, a.ABX, a.ABX,/*3*/ -/*4*/ a.IMP, a.IDY, a.IMP, 0, 0, a.ZPG, a.ZPG, 0, a.IMP, a.IMM, a.ACC, 0, a.ABS, a.ABS, a.ABS, 0,/*4*/ -/*5*/ a.REL, a.IDY, a.IMP, 0, 0, a.ZPG, a.ZPG, 0, a.IMP, a.ABY, 0, 0, a.ABS, a.ABX, a.ABX, 0,/*5*/ -/*6*/ a.IMP, a.IDX, a.IMP, 0, 0, a.ZPG, a.ZPG, 0, a.IMP, a.IMM, a.ACC, 0, a.IND, a.ABS, a.ABS, 0,/*6*/ -/*7*/ a.REL, a.IDY, a.IMP, 0, 0, a.ZPX, a.ZPX, 0, a.IMP, a.ABY, 0, 0, a.ABS, a.ABX, a.ABX, 0,/*7*/ -/*8*/ 0, a.IDY, 0, a.IDX, a.ZPG, a.ZPG, a.ZPG, a.ZPG, a.IMP, 0, a.IMP, 0, a.ABS, a.ABS, a.ABS, a.ABS,/*8*/ -/*9*/ a.REL, a.IDY, a.IMP, 0, a.ZPX, a.ZPX, a.ZPY, a.ZPY, a.IMP, a.ABY, a.IMP, 0, a.ABS, a.ABX, 0, 0,/*9*/ -/*A*/ a.IMM, a.IND, a.IMM, a.IDX, a.ZPG, a.ZPG, a.ZPG, a.ZPX, a.IMP, a.IMM, a.IMP, 0, a.ABS, a.ABS, a.ABS, a.ABS,/*A*/ -/*B*/ a.REL, a.IDY, a.IMP, a.IDY, a.ZPX, a.ZPX, a.ZPY, a.ZPY, a.IMP, a.ABY, a.IMP, 0, a.ABX, a.ABX, a.ABY, a.ABY,/*B*/ -/*C*/ a.IMM, a.IDX, 0, 0, a.ZPG, a.ZPG, a.ZPG, 0, a.IMP, a.IMM, a.IMP, 0, a.ABS, a.ABS, a.ABS, 0,/*C*/ -/*D*/ a.REL, a.IDY, a.IMP, 0, 0, a.ZPX, a.ZPX, 0, a.IMP, a.ABY, 0, 0, a.ABS, a.ABX, a.ABX, 0,/*D*/ -/*E*/ a.IMM, a.IDX, 0, 0, a.ZPG, a.ZPG, a.ZPG, 0, a.IMP, a.IMM, a.IMP, 0, a.ABS, a.ABS, a.ABS, a.ABS,/*E*/ -/*F*/ a.REL, a.IDY, a.IMP, 0, 0, a.ZPX, a.ZPX, 0, a.IMP, a.ABY, 0, 0, a.ABS, a.ABX, a.ABX, a.ABX /*F*/ -}; - - public static string GetRegisters(M6502 cpu) - { - var dSB = new StringBuilder(); - dSB.Append(String.Format( - "PC:{0:x4} A:{1:x2} X:{2:x2} Y:{3:x2} S:{4:x2} P:", - cpu.PC, cpu.A, cpu.X, cpu.Y, cpu.S)); - - const string flags = "nv0bdizcNV1BDIZC"; - - for (var i = 0; i < 8; i++) - { - dSB.Append(((cpu.P & (1 << (7 - i))) == 0) ? flags[i] : flags[i + 8]); - } - return dSB.ToString(); - } - - public static string Disassemble(AddressSpace addrSpace, ushort atAddr, ushort untilAddr) - { - var dSB = new StringBuilder(); - var dPC = atAddr; - while (atAddr < untilAddr) - { - dSB.AppendFormat("{0:x4}: ", dPC); - var len = GetInstructionLength(addrSpace, dPC); - for (var i = 0; i < 3; i++) - { - if (i < len) - { - dSB.AppendFormat("{0:x2} ", addrSpace[atAddr++]); - } - else - { - dSB.Append(" "); - } - } - dSB.AppendFormat("{0,-15}{1}", RenderOpCode(addrSpace, dPC), Environment.NewLine); - dPC += (ushort)len; - } - if (dSB.Length > 0) - { - dSB.Length--; // Trim trailing newline - } - return dSB.ToString(); - } - - public static string MemDump(AddressSpace addrSpace, ushort atAddr, ushort untilAddr) - { - var dSB = new StringBuilder(); - var len = untilAddr - atAddr; - while (len-- >= 0) - { - dSB.AppendFormat("{0:x4}: ", atAddr); - for (var i = 0; i < 8; i++) - { - dSB.AppendFormat("{0:x2} ", addrSpace[atAddr++]); - if (i == 3) - { - dSB.Append(" "); - } - } - dSB.Append("\n"); - } - if (dSB.Length > 0) - { - dSB.Length--; // Trim trailing newline - } - return dSB.ToString(); - } - - public static string RenderOpCode(AddressSpace addrSpace, ushort PC) - { - var num_operands = GetInstructionLength(addrSpace, PC) - 1; - var PC1 = (ushort)(PC + 1); - string addrmodeStr; - - switch (AddressingModeMatrix[addrSpace[PC]]) - { - case a.REL: - addrmodeStr = String.Format("${0:x4}", (ushort)(PC + (sbyte)(addrSpace[PC1]) + 2)); - break; - case a.ZPG: - case a.ABS: - addrmodeStr = RenderEA(addrSpace, PC1, num_operands); - break; - case a.ZPX: - case a.ABX: - addrmodeStr = RenderEA(addrSpace, PC1, num_operands) + ",X"; - break; - case a.ZPY: - case a.ABY: - addrmodeStr = RenderEA(addrSpace, PC1, num_operands) + ",Y"; - break; - case a.IDX: - addrmodeStr = "(" + RenderEA(addrSpace, PC1, num_operands) + ",X)"; - break; - case a.IDY: - addrmodeStr = "(" + RenderEA(addrSpace, PC1, num_operands) + "),Y"; - break; - case a.IND: - addrmodeStr = "(" + RenderEA(addrSpace, PC1, num_operands) + ")"; - break; - case a.IMM: - addrmodeStr = "#" + RenderEA(addrSpace, PC1, num_operands); - break; - default: - // a.IMP, a.ACC - addrmodeStr = string.Empty; - break; - } - - return string.Format("{0} {1}", MnemonicMatrix[addrSpace[PC]], addrmodeStr); - } - - static int GetInstructionLength(AddressSpace addrSpace, ushort PC) - { - switch (AddressingModeMatrix[addrSpace[PC]]) - { - case a.ACC: - case a.IMP: - return 1; - case a.REL: - case a.ZPG: - case a.ZPX: - case a.ZPY: - case a.IDX: - case a.IDY: - case a.IMM: - return 2; - default: - return 3; - } - } - - static string RenderEA(AddressSpace addrSpace, ushort PC, int bytes) - { - var lsb = addrSpace[PC]; - var msb = (bytes == 2) ? addrSpace[(ushort)(PC + 1)] : (byte)0; - var ea = (ushort)(lsb | (msb << 8)); - return string.Format((bytes == 1) ? "${0:x2}" : "${0:x4}", ea); - } - } -} \ No newline at end of file diff --git a/EMU7800/Core/Machine2600.cs b/EMU7800/Core/Machine2600.cs deleted file mode 100644 index bb62a02692..0000000000 --- a/EMU7800/Core/Machine2600.cs +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Machine2600.cs - * - * The realization of a 2600 machine. - * - * Copyright © 2003, 2004 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public class Machine2600 : MachineBase - { - #region Fields - - protected TIA TIA { get; set; } - - #endregion - - public override void Reset() - { - base.Reset(); - TIA.Reset(); - PIA.Reset(); - CPU.Reset(); - } - - public override void ComputeNextFrame(FrameBuffer frameBuffer) - { - base.ComputeNextFrame(frameBuffer); - TIA.StartFrame(); - CPU.RunClocks = (FrameBuffer.Scanlines + 3) * 76; - while (CPU.RunClocks > 0 && !CPU.Jammed) - { - if (TIA.WSYNCDelayClocks > 0) - { - CPU.Clock += (ulong)TIA.WSYNCDelayClocks / 3; - CPU.RunClocks -= TIA.WSYNCDelayClocks / 3; - TIA.WSYNCDelayClocks = 0; - } - if (TIA.EndOfFrame) - { - break; - } - CPU.Execute(); - } - TIA.EndFrame(); - } - - public Machine2600(Cart cart, ILogger logger, int slines, int startl, int fHZ, int sRate, int[] p) - : base(logger, slines, startl, fHZ, sRate, p, 160) - { - Mem = new AddressSpace(this, 13, 6); // 2600: 13bit, 64byte pages - - CPU = new M6502(this, 1); - - TIA = new TIA(this); - for (ushort i = 0; i < 0x1000; i += 0x100) - { - Mem.Map(i, 0x0080, TIA); - } - - PIA = new PIA(this); - for (ushort i = 0x0080; i < 0x1000; i += 0x100) - { - Mem.Map(i, 0x0080, PIA); - } - - Cart = cart; - Mem.Map(0x1000, 0x1000, Cart); - } - - #region Serialization Members - - public Machine2600(DeserializationContext input, int[] palette) : base(input, palette) - { - input.CheckVersion(1); - - Mem = input.ReadAddressSpace(this, 13, 6); // 2600: 13bit, 64byte pages - - CPU = input.ReadM6502(this, 1); - - TIA = input.ReadTIA(this); - for (ushort i = 0; i < 0x1000; i += 0x100) - { - Mem.Map(i, 0x0080, TIA); - } - - PIA = input.ReadPIA(this); - for (ushort i = 0x0080; i < 0x1000; i += 0x100) - { - Mem.Map(i, 0x0080, PIA); - } - - Cart = input.ReadCart(this); - Mem.Map(0x1000, 0x1000, Cart); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(Mem); - output.Write(CPU); - output.Write(TIA); - output.Write(PIA); - output.Write(Cart); - } - - #endregion - } -} diff --git a/EMU7800/Core/Machine2600NTSC.cs b/EMU7800/Core/Machine2600NTSC.cs deleted file mode 100644 index 52c5a5b395..0000000000 --- a/EMU7800/Core/Machine2600NTSC.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace EMU7800.Core -{ - public sealed class Machine2600NTSC : Machine2600 - { - public override string ToString() - { - return GetType().Name; - } - - public Machine2600NTSC(Cart cart, ILogger logger) - : base(cart, logger, 262, 16, 60, 31440 /* NTSC_SAMPLES_PER_SEC */, TIATables.NTSCPalette) - { - } - - #region Serialization Members - - public Machine2600NTSC(DeserializationContext input) : base(input, TIATables.NTSCPalette) - { - input.CheckVersion(1); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - output.WriteVersion(1); - } - - #endregion - } -} diff --git a/EMU7800/Core/Machine2600PAL.cs b/EMU7800/Core/Machine2600PAL.cs deleted file mode 100644 index ab32b28ba5..0000000000 --- a/EMU7800/Core/Machine2600PAL.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace EMU7800.Core -{ - public sealed class Machine2600PAL : Machine2600 - { - public override string ToString() - { - return GetType().Name; - } - - public Machine2600PAL(Cart cart, ILogger logger) - : base(cart, logger, 312, 32, 50, 31200 /* PAL_SAMPLES_PER_SEC */, TIATables.PALPalette) - { - } - - #region Serialization Members - - public Machine2600PAL(DeserializationContext input) : base(input, TIATables.PALPalette) - { - input.CheckVersion(1); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - output.WriteVersion(1); - } - - #endregion - } -} diff --git a/EMU7800/Core/Machine7800.cs b/EMU7800/Core/Machine7800.cs deleted file mode 100644 index 7da3da1fbd..0000000000 --- a/EMU7800/Core/Machine7800.cs +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Machine7800.cs - * - * The realization of a 7800 machine. - * - * Copyright © 2003-2005 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public class Machine7800 : MachineBase - { - #region Fields - - protected Maria Maria { get; set; } - public RAM6116 RAM1 { get; protected set; } - public RAM6116 RAM2 { get; protected set; } - public Bios7800 BIOS { get; private set; } - public HSC7800 HSC { get; private set; } - public bool using_bios=true; - - #endregion - - public void SwapInBIOS() - { - if (BIOS == null) - return; - Mem.Map((ushort)(0x10000 - BIOS.Size), BIOS.Size, BIOS); - using_bios = true; - } - - public void SwapOutBIOS() - { - if (BIOS == null) - return; - Mem.Map((ushort)(0x10000 - BIOS.Size), BIOS.Size, Cart); - using_bios = false; - } - - public override void Reset() - { - base.Reset(); - SwapInBIOS(); - if (HSC != null) - HSC.Reset(); - Cart.Reset(); - Maria.Reset(); - PIA.Reset(); - CPU.Reset(); - } - - public override void ComputeNextFrame(FrameBuffer frameBuffer) - { - base.ComputeNextFrame(frameBuffer); - - AssertDebug(CPU.Jammed || CPU.RunClocks <= 0 && (CPU.RunClocks % CPU.RunClocksMultiple) == 0); - AssertDebug(CPU.Jammed || ((CPU.Clock + (ulong)(CPU.RunClocks / CPU.RunClocksMultiple)) % (114 * (ulong)FrameBuffer.Scanlines)) == 0); - - ulong startOfScanlineCpuClock = 0; - - Maria.StartFrame(); - Cart.StartFrame(); - for (var i = 0; i < FrameBuffer.Scanlines && !CPU.Jammed; i++) - { - AssertDebug(CPU.RunClocks <= 0 && (CPU.RunClocks % CPU.RunClocksMultiple) == 0); - var newStartOfScanlineCpuClock = CPU.Clock + (ulong)(CPU.RunClocks / CPU.RunClocksMultiple); - - AssertDebug(startOfScanlineCpuClock == 0 || newStartOfScanlineCpuClock == startOfScanlineCpuClock + 114); - startOfScanlineCpuClock = newStartOfScanlineCpuClock; - - CPU.RunClocks += (7 * CPU.RunClocksMultiple); - var remainingRunClocks = (114 - 7) * CPU.RunClocksMultiple; - - CPU.Execute(); - if (CPU.Jammed) - break; - if (CPU.EmulatorPreemptRequest) - { - Maria.DoDMAProcessing(); - var remainingCpuClocks = 114 - (CPU.Clock - startOfScanlineCpuClock); - CPU.Clock += remainingCpuClocks; - CPU.RunClocks = 0; - continue; - } - - var dmaClocks = Maria.DoDMAProcessing(); - - // CHEAT: Ace of Aces: Title screen has a single scanline flicker without this. Maria DMA clock counting probably not 100% accurate. - if (i == 203 && FrameBuffer.Scanlines == 262 /*NTSC*/ || i == 228 && FrameBuffer.Scanlines == 312 /*PAL*/) - if (dmaClocks == 152 && remainingRunClocks == 428 && (CPU.RunClocks == -4 || CPU.RunClocks == -8)) - dmaClocks -= 4; - - // Unsure exactly what to do if Maria DMA processing extends past the current scanline. - // For now, throw away half remaining until we are within the current scanline. - // KLAX initialization starts DMA without initializing the DLL data structure. - // Maria processing then runs away causing an invalid CPU opcode to be executed that jams the machine. - // So Maria must give up at some point, but not clear exactly how. - // Anyway, this makes KLAX work without causing breakage elsewhere. - while ((CPU.RunClocks + remainingRunClocks) < dmaClocks) - { - dmaClocks >>= 1; - } - - // Assume the CPU waits until the next div4 boundary to proceed after DMA processing. - if ((dmaClocks & 3) != 0) - { - dmaClocks += 4; - dmaClocks -= (dmaClocks & 3); - } - - CPU.Clock += (ulong)(dmaClocks / CPU.RunClocksMultiple); - CPU.RunClocks -= dmaClocks; - - CPU.RunClocks += remainingRunClocks; - - CPU.Execute(); - if (CPU.Jammed) - break; - if (CPU.EmulatorPreemptRequest) - { - var remainingCpuClocks = 114 - (CPU.Clock - startOfScanlineCpuClock); - CPU.Clock += remainingCpuClocks; - CPU.RunClocks = 0; - } - } - Cart.EndFrame(); - Maria.EndFrame(); - } - - public Machine7800(Cart cart, Bios7800 bios, HSC7800 hsc, ILogger logger, int scanlines, int startl, int fHZ, int sRate, int[] p) - : base(logger, scanlines, startl, fHZ, sRate, p, 320) - { - Mem = new AddressSpace(this, 16, 6); // 7800: 16bit, 64byte pages - - CPU = new M6502(this, 4); - - Maria = new Maria(this, scanlines); - Mem.Map(0x0000, 0x0040, Maria); - Mem.Map(0x0100, 0x0040, Maria); - Mem.Map(0x0200, 0x0040, Maria); - Mem.Map(0x0300, 0x0040, Maria); - - PIA = new PIA(this); - Mem.Map(0x0280, 0x0080, PIA); - Mem.Map(0x0480, 0x0080, PIA); - Mem.Map(0x0580, 0x0080, PIA); - - RAM1 = new RAM6116(); - RAM2 = new RAM6116(); - Mem.Map(0x1800, 0x0800, RAM1); - Mem.Map(0x2000, 0x0800, RAM2); - - Mem.Map(0x0040, 0x00c0, RAM2); // page 0 shadow - Mem.Map(0x0140, 0x00c0, RAM2); // page 1 shadow - Mem.Map(0x2800, 0x0800, RAM2); // shadow1 - Mem.Map(0x3000, 0x0800, RAM2); // shadow2 - Mem.Map(0x3800, 0x0800, RAM2); // shadow3 - - BIOS = bios; - HSC = hsc; - - if (HSC != null) - { - Mem.Map(0x1000, 0x800, HSC.SRAM); - Mem.Map(0x3000, 0x1000, HSC); - Logger.WriteLine("7800 Highscore Cartridge Installed"); - } - - Cart = cart; - Mem.Map(0x4000, 0xc000, Cart); - } - - #region Serialization Members - - public Machine7800(DeserializationContext input, int[] palette, int scanlines) : base(input, palette) - { - input.CheckVersion(1); - - Mem = input.ReadAddressSpace(this, 16, 6); // 7800: 16bit, 64byte pages - - CPU = input.ReadM6502(this, 4); - - Maria = input.ReadMaria(this, scanlines); - Mem.Map(0x0000, 0x0040, Maria); - Mem.Map(0x0100, 0x0040, Maria); - Mem.Map(0x0200, 0x0040, Maria); - Mem.Map(0x0300, 0x0040, Maria); - - PIA = input.ReadPIA(this); - Mem.Map(0x0280, 0x0080, PIA); - Mem.Map(0x0480, 0x0080, PIA); - Mem.Map(0x0580, 0x0080, PIA); - - RAM1 = input.ReadRAM6116(); - RAM2 = input.ReadRAM6116(); - Mem.Map(0x1800, 0x0800, RAM1); - Mem.Map(0x2000, 0x0800, RAM2); - - Mem.Map(0x0040, 0x00c0, RAM2); // page 0 shadow - Mem.Map(0x0140, 0x00c0, RAM2); // page 1 shadow - Mem.Map(0x2800, 0x0800, RAM2); // shadow1 - Mem.Map(0x3000, 0x0800, RAM2); // shadow2 - Mem.Map(0x3800, 0x0800, RAM2); // shadow3 - - BIOS = input.ReadOptionalBios7800(); - HSC = input.ReadOptionalHSC7800(); - - if (HSC != null) - { - Mem.Map(0x1000, 0x800, HSC.SRAM); - Mem.Map(0x3000, 0x1000, HSC); - } - - Cart = input.ReadCart(this); - Mem.Map(0x4000, 0xc000, Cart); - - using_bios = input.ReadBoolean(); - - if (using_bios && BIOS != null) - { - Mem.Map((ushort)(0x10000 - BIOS.Size), BIOS.Size, BIOS); - } - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - - output.WriteVersion(1); - output.Write(Mem); - output.Write(CPU); - output.Write(Maria); - output.Write(PIA); - output.Write(RAM1); - output.Write(RAM2); - output.WriteOptional(BIOS); - output.WriteOptional(HSC); - output.Write(Cart); - output.Write(using_bios); - } - - #endregion - - #region Helpers - - [System.Diagnostics.Conditional("DEBUG")] - void AssertDebug(bool cond) - { - if (!cond) - System.Diagnostics.Debugger.Break(); - } - - #endregion - } -} diff --git a/EMU7800/Core/Machine7800NTSC.cs b/EMU7800/Core/Machine7800NTSC.cs deleted file mode 100644 index 933336740f..0000000000 --- a/EMU7800/Core/Machine7800NTSC.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace EMU7800.Core -{ - public sealed class Machine7800NTSC : Machine7800 - { - public override string ToString() - { - return GetType().Name; - } - - public Machine7800NTSC(Cart cart, Bios7800 bios, HSC7800 hsc, ILogger logger) - : base(cart, bios, hsc, logger, 262, 16, 60, 31440 /* NTSC_SAMPLES_PER_SEC */, MariaTables.NTSCPalette) - { - } - - #region Serialization Members - - public Machine7800NTSC(DeserializationContext input) : base(input, MariaTables.NTSCPalette, 262) - { - input.CheckVersion(1); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - output.WriteVersion(1); - } - - #endregion - } -} diff --git a/EMU7800/Core/Machine7800PAL.cs b/EMU7800/Core/Machine7800PAL.cs deleted file mode 100644 index 4de452f892..0000000000 --- a/EMU7800/Core/Machine7800PAL.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace EMU7800.Core -{ - public sealed class Machine7800PAL : Machine7800 - { - public override string ToString() - { - return GetType().Name; - } - - public Machine7800PAL(Cart cart, Bios7800 bios, HSC7800 hsc, ILogger logger) - : base(cart, bios, hsc, logger, 312, 34, 50, 31200 /* PAL_SAMPLES_PER_SEC */, MariaTables.PALPalette) - { - } - - #region Serialization Members - - public Machine7800PAL(DeserializationContext input) : base(input, MariaTables.PALPalette, 312) - { - input.CheckVersion(1); - } - - public override void GetObjectData(SerializationContext output) - { - base.GetObjectData(output); - output.WriteVersion(1); - } - - #endregion - } -} diff --git a/EMU7800/Core/MachineBase.cs b/EMU7800/Core/MachineBase.cs deleted file mode 100644 index 832258d11c..0000000000 --- a/EMU7800/Core/MachineBase.cs +++ /dev/null @@ -1,331 +0,0 @@ -/* -/* - * MachineBase.cs - * - * Abstraction of an emulated machine. - * - * Copyright © 2003, 2004 Mike Murphy - * - */ -using System; -using System.IO; -using System.Reflection; - -namespace EMU7800.Core -{ - public abstract class MachineBase - { - #region Fields - - ILogger _Logger; - FrameBuffer _FrameBuffer; - - bool _MachineHalt; - int _FrameHZ; - readonly int _VisiblePitch, _Scanlines; - - protected Cart Cart { get; set; } - - #endregion - - #region Internal Properties - - internal FrameBuffer FrameBuffer - { - get - { - AssertDebug(_FrameBuffer != null); - return _FrameBuffer; - } - } - - #endregion - - #region Public Properties - - /// - /// The machine's Central Processing Unit. - /// - public M6502 CPU { get; protected set; } - - /// - /// The machine's Address Space. - /// - public AddressSpace Mem { get; protected set; } - - /// - /// The machine's Peripheral Interface Adaptor device. - /// - public PIA PIA { get; protected set; } - - /// - /// Reports whether the machine has been halted due to an internal condition or error. - /// - public bool MachineHalt - { - get { return _MachineHalt; } - internal set { if (value) _MachineHalt = true; } - } - - /// - /// The machine input state. - /// - public InputState InputState { get; private set; } - - /// - /// The current frame number. - /// - public long FrameNumber { get; private set; } - - /// - /// The first scanline that is visible. - /// - public int FirstScanline { get; private set; } - - /// - /// Frame rate. - /// - public int FrameHZ - { - get { return _FrameHZ < 1 ? 1 : _FrameHZ; } - set { _FrameHZ = value < 1 ? 1 : value; } - } - - /// - /// Number of sound samples per second. - /// - public int SoundSampleFrequency { get; private set; } - - /// - /// The color palette for the configured machine. - /// - public int[] Palette { get; internal set; } - - /// - /// Dumps CPU registers to the log when NOP instructions are encountered. - /// - public bool NOPRegisterDumping { get; set; } - - /// - /// The configured logger sink. - /// - public ILogger Logger - { - get { return _Logger ?? (_Logger = new NullLogger()); } - set { _Logger = value; } - } - - #endregion - - #region Public Methods - - /// - /// Creates an instance of the specified machine. - /// - /// - /// - /// 7800 BIOS, optional. - /// 7800 High Score cart, optional. - /// Left controller, optional. - /// Right controller, optional. - /// - /// Cart must not be null. - /// Specified MachineType is unexpected. - public static MachineBase Create(MachineType machineType, Cart cart, Bios7800 bios, HSC7800 hsc, Controller p1, Controller p2, ILogger logger) - { - if (cart == null) - throw new ArgumentNullException("cart"); - - MachineBase m; - switch (machineType) - { - case MachineType.A2600NTSC: - m = new Machine2600NTSC(cart, logger); - break; - case MachineType.A2600PAL: - m = new Machine2600PAL(cart, logger); - break; - case MachineType.A7800NTSC: - m = new Machine7800NTSC(cart, bios, hsc, logger); - break; - case MachineType.A7800PAL: - m = new Machine7800PAL(cart, bios, hsc, logger); - break; - default: - throw new Emu7800Exception("Unexpected MachineType: " + machineType); - } - - m.InputState.LeftControllerJack = p1; - m.InputState.RightControllerJack = p2; - - m.Reset(); - - return m; - } - - /// - /// Deserialize a from the specified stream. - /// - /// - /// - /// - public static MachineBase Deserialize(BinaryReader binaryReader) - { - var context = new DeserializationContext(binaryReader); - MachineBase m; - try - { - m = context.ReadMachine(); - } - catch (Emu7800SerializationException) - { - throw; - } - catch (TargetInvocationException ex) - { - // TargetInvocationException wraps exceptions that unwind an Activator.CreateInstance() frame. - throw new Emu7800SerializationException("Serialization stream does not describe a valid machine.", ex.InnerException); - } - catch (Exception ex) - { - throw new Emu7800SerializationException("Serialization stream does not describe a valid machine.", ex); - } - return m; - } - - /// - /// Resets the state of the machine. - /// - public virtual void Reset() - { - Logger.WriteLine("Machine {0} reset ({1} HZ {2} scanlines)", this, FrameHZ, _Scanlines); - FrameNumber = 0; - _MachineHalt = false; - InputState.ClearAllInput(); - } - - /// - /// Computes the next machine frame, updating contents of the provided . - /// - /// The framebuffer to contain the computed output. - /// - /// frameBuffer is incompatible with machine. - public virtual void ComputeNextFrame(FrameBuffer frameBuffer) - { - if (MachineHalt) - return; - - InputState.CaptureInputState(); - - _FrameBuffer = frameBuffer; - FrameNumber++; - - for (var i = 0; i < _FrameBuffer.SoundBufferByteLength; i++) - _FrameBuffer.SoundBuffer[i] = 0; - } - - /// - /// Create a with compatible dimensions for this machine. - /// - public FrameBuffer CreateFrameBuffer() - { - var fb = new FrameBuffer(_VisiblePitch, _Scanlines); - return fb; - } - - /// - /// Serialize the state of the machine to the specified stream. - /// - /// - /// - /// - public void Serialize(BinaryWriter binaryWriter) - { - var context = new SerializationContext(binaryWriter); - try - { - context.Write(this); - } - catch (Emu7800SerializationException) - { - throw; - } - catch (Exception ex) - { - throw new Emu7800SerializationException("Problem serializing specified machine.", ex); - } - } - - #endregion - - #region Constructors - - private MachineBase() - { - } - - protected MachineBase(ILogger logger, int scanLines, int firstScanline, int fHZ, int soundSampleFreq, int[] palette, int vPitch) : this() - { - InputState = new InputState(); - Logger = logger; - _Scanlines = scanLines; - FirstScanline = firstScanline; - FrameHZ = fHZ; - SoundSampleFrequency = soundSampleFreq; - Palette = palette; - _VisiblePitch = vPitch; - } - - #endregion - - #region Serialization Members - - protected MachineBase(DeserializationContext input, int[] palette) - { - if (input == null) - throw new ArgumentNullException("input"); - if (palette == null) - throw new ArgumentNullException("palette"); - if (palette.Length != 0x100) - throw new ArgumentException("palette incorrect size, must be 256."); - - input.CheckVersion(1); - _MachineHalt = input.ReadBoolean(); - _FrameHZ = input.ReadInt32(); - _VisiblePitch = input.ReadInt32(); - _Scanlines = input.ReadInt32(); - FirstScanline = input.ReadInt32(); - SoundSampleFrequency = input.ReadInt32(); - NOPRegisterDumping = input.ReadBoolean(); - InputState = input.ReadInputState(); - - Palette = palette; - Logger = null; - } - - public virtual void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(_MachineHalt); - output.Write(_FrameHZ); - output.Write(_VisiblePitch); - output.Write(_Scanlines); - output.Write(FirstScanline); - output.Write(SoundSampleFrequency); - output.Write(NOPRegisterDumping); - output.Write(InputState); - } - - #endregion - - [System.Diagnostics.Conditional("DEBUG")] - void AssertDebug(bool cond) - { - if (!cond) - System.Diagnostics.Debugger.Break(); - } - } -} diff --git a/EMU7800/Core/MachineInput.cs b/EMU7800/Core/MachineInput.cs deleted file mode 100644 index 05fe19c556..0000000000 --- a/EMU7800/Core/MachineInput.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* - * HostInput.cs - * - * Copyright © 2009 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public enum MachineInput - { - End, - Pause, - Mute, - Fire, - Fire2, - Left, - Right, - Up, - Down, - NumPad1, NumPad2, NumPad3, - NumPad4, NumPad5, NumPad6, - NumPad7, NumPad8, NumPad9, - NumPadMult, NumPad0, NumPadHash, - Driving0, Driving1, Driving2, Driving3, - Reset, - Select, - Color, - LeftDifficulty, - RightDifficulty, - SetKeyboardToPlayer1, - SetKeyboardToPlayer2, - SetKeyboardToPlayer3, - SetKeyboardToPlayer4, - PanLeft, PanRight, PanUp, PanDown, - SaveMachine, - TakeScreenshot, - LeftPaddleSwap, - GameControllerSwap, - RightPaddleSwap, - ShowFrameStats, - } -} diff --git a/EMU7800/Core/MachineType.cs b/EMU7800/Core/MachineType.cs deleted file mode 100644 index 0fcfdd2d52..0000000000 --- a/EMU7800/Core/MachineType.cs +++ /dev/null @@ -1,19 +0,0 @@ -/* - * MachineType.cs - * - * The set of known machines. - * - * Copyright © 2010 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public enum MachineType - { - None, - A2600NTSC, - A2600PAL, - A7800NTSC, - A7800PAL - }; -} diff --git a/EMU7800/Core/Maria.cs b/EMU7800/Core/Maria.cs deleted file mode 100644 index 682e3a0bc9..0000000000 --- a/EMU7800/Core/Maria.cs +++ /dev/null @@ -1,1151 +0,0 @@ -/* - * Maria.cs - * - * The Maria display device. - * - * Derived from much of Dan Boris' work with 7800 emulation - * within the MESS emulator. - * - * Thanks to Matthias Luedtke for correcting - * the BuildLineRAM320B() method to correspond closer to real hardware. - * (Matthias credited an insightful response by Eckhard Stolberg on a forum on - * Atari Age circa June 2005.) - * - * Copyright © 2004-2012 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class Maria : IDevice - { - #region Constants - - const int - INPTCTRL= 0x01, // Write: input port control (VBLANK in TIA) - INPT0 = 0x08, // Read pot port: D7 - INPT1 = 0x09, // Read pot port: D7 - INPT2 = 0x0a, // Read pot port: D7 - INPT3 = 0x0b, // Read pot port: D7 - INPT4 = 0x0c, // Read P1 joystick trigger: D7 - INPT5 = 0x0d, // Read P2 joystick trigger: D7 - AUDC0 = 0x15, // Write: audio control 0 (D3-0) - AUDC1 = 0x16, // Write: audio control 1 (D4-0) - AUDF0 = 0x17, // Write: audio frequency 0 (D4-0) - AUDF1 = 0x18, // Write: audio frequency 1 (D3-0) - AUDV0 = 0x19, // Write: audio volume 0 (D3-0) - AUDV1 = 0x1a, // Write: audio volume 1 (D3-0) - - BACKGRND= 0x20, // Background color - P0C1 = 0x21, // Palette 0 - color 1 - P0C2 = 0x22, // Palette 0 - color 2 - P0C3 = 0x23, // Palette 0 - color 3 - WSYNC = 0x24, // Wait for sync - P1C1 = 0x25, // Palette 1 - color 1 - P1C2 = 0x26, // Palette 1 - color 2 - P1C3 = 0x27, // Palette 1 - color 3 - MSTAT = 0x28, // Maria status - P2C1 = 0x29, // Palette 2 - color 1 - P2C2 = 0x2a, // Palette 2 - color 2 - P2C3 = 0x2b, // Palette 2 - color 3 - DPPH = 0x2c, // Display list list point high - P3C1 = 0x2d, // Palette 3 - color 1 - P3C2 = 0x2e, // Palette 3 - color 2 - P3C3 = 0x2f, // Palette 3 - color 3 - DPPL = 0x30, // Display list list point low - P4C1 = 0x31, // Palette 4 - color 1 - P4C2 = 0x32, // Palette 4 - color 2 - P4C3 = 0x33, // Palette 4 - color 3 - CHARBASE= 0x34, // Character base address - P5C1 = 0x35, // Palette 5 - color 1 - P5C2 = 0x36, // Palette 5 - color 2 - P5C3 = 0x37, // Palette 5 - color 3 - OFFSET = 0x38, // Future expansion (store zero here) - P6C1 = 0x39, // Palette 6 - color 1 - P6C2 = 0x3a, // Palette 6 - color 2 - P6C3 = 0x3b, // Palette 6 - color 3 - CTRL = 0x3c, // Maria control register - P7C1 = 0x3d, // Palette 7 - color 1 - P7C2 = 0x3e, // Palette 7 - color 2 - P7C3 = 0x3f; // Palette 7 - color 3 - - const int CPU_TICKS_PER_AUDIO_SAMPLE = 57; - - #endregion - - #region Fields - - readonly byte[] LineRAM = new byte[0x200]; - readonly byte[] Registers = new byte[0x40]; - - readonly Machine7800 M; - readonly TIASound TIASound; - - ulong _startOfFrameCpuClock; - int Scanline { get { return (int)(M.CPU.Clock - _startOfFrameCpuClock) / 114; } } - int HPos { get { return (int)(M.CPU.Clock - _startOfFrameCpuClock) % 114; } } - - int FirstVisibleScanline, LastVisibleScanline; - int _dmaClocks; - bool _isPal; - - // For lightgun emulation. - // Transient state, serialization unnecessary. - ulong _lightgunFirstSampleCpuClock; - int _lightgunFrameSamples, _lightgunSampledScanline, _lightgunSampledVisibleHpos; - - bool WM; - ushort DLL; - ushort DL; - int Offset; - int Holey; - int Width; - byte HPOS; - int PaletteNo; - bool INDMode; - - bool CtrlLock; - - // MARIA CNTL - bool DMAEnabled; - bool ColorKill; - bool CWidth; - bool BCntl; - bool Kangaroo; - byte RM; - - #endregion - - #region Public Members - - public void Reset() - { - CtrlLock = false; - - DMAEnabled = false; - ColorKill = false; - CWidth = false; - BCntl = false; - Kangaroo = false; - RM = 0; - - TIASound.Reset(); - - Log("{0} reset", this); - } - - public byte this[ushort addr] - { - get { return peek(addr); } - set { poke(addr, value); } - } - - public override string ToString() - { - return GetType().Name; - } - - public void StartFrame() - { - _startOfFrameCpuClock = M.CPU.Clock + (ulong)(M.CPU.RunClocks / M.CPU.RunClocksMultiple); - _lightgunFirstSampleCpuClock = 0; - - AssertDebug(M.CPU.RunClocks <= 0 && (M.CPU.RunClocks % M.CPU.RunClocksMultiple) == 0); - AssertDebug((_startOfFrameCpuClock % (114 * (ulong)M.FrameBuffer.Scanlines)) == 0); - - TIASound.StartFrame(); - } - - public int DoDMAProcessing() - { - OutputLineRAM(); - - var sl = Scanline; - - if (!DMAEnabled || sl < FirstVisibleScanline || sl >= LastVisibleScanline) - return 0; - - _dmaClocks = 0; - - if (DMAEnabled && sl == FirstVisibleScanline) - { - // DMA TIMING: End of VBLANK: DMA Startup + long shutdown - _dmaClocks += 15; - - DLL = WORD(Registers[DPPL], Registers[DPPH]); - - ConsumeNextDLLEntry(); - } - - // DMA TIMING: DMA Startup, 5-9 cycles - _dmaClocks += 5; - - BuildLineRAM(); - - if (--Offset < 0) - { - ConsumeNextDLLEntry(); - - // DMA TIMING: DMA Shutdown: Last line of zone, 10-13 cycles - _dmaClocks += 10; - } - else - { - // DMA TIMING: DMA Shutdown: Other line of zone, 4-7 cycles - _dmaClocks += 4; - } - - return _dmaClocks; - } - - public void EndFrame() - { - TIASound.EndFrame(); - } - - #endregion - - #region Constructors - - private Maria() - { - } - - public Maria(Machine7800 m, int scanlines) - { - if (m == null) - throw new ArgumentNullException("m"); - - M = m; - InitializeVisibleScanlineValues(scanlines); - TIASound = new TIASound(M, CPU_TICKS_PER_AUDIO_SAMPLE); - } - - #endregion - - #region Scanline Builders - - void BuildLineRAM() - { - var dl = DL; - - // Iterate through Display List (DL) - while (true) - { - var modeByte = DmaRead(dl + 1); - if ((modeByte & 0x5f) == 0) - break; - - INDMode = false; - ushort graphaddr; - - if ((modeByte & 0x1f) == 0) - { - // Extended DL header - var dl0 = DmaRead(dl++); // low address - var dl1 = DmaRead(dl++); // mode - var dl2 = DmaRead(dl++); // high address - var dl3 = DmaRead(dl++); // palette(7-5)/width(4-0) - var dl4 = DmaRead(dl++); // horizontal position - - graphaddr = WORD(dl0, dl2); - WM = (dl1 & 0x80) != 0; - INDMode = (dl1 & 0x20) != 0; - PaletteNo = (dl3 & 0xe0) >> 3; - Width = (~dl3 & 0x1f) + 1; - HPOS = dl4; - - // DMA TIMING: DL 5 byte header - _dmaClocks += 10; - } - else - { - // Normal DL header - var dl0 = DmaRead(dl++); // low address - var dl1 = DmaRead(dl++); // palette(7-5)/width(4-0) - var dl2 = DmaRead(dl++); // high address - var dl3 = DmaRead(dl++); // horizontal position - - graphaddr = WORD(dl0, dl2); - PaletteNo = (dl1 & 0xe0) >> 3; - Width = (~dl1 & 0x1f) + 1; - HPOS = dl3; - - // DMA TIMING: DL 4 byte header - _dmaClocks += 8; - } - - // DMA TIMING: Graphic reads - if (RM != 1) - _dmaClocks += (Width * (INDMode ? (CWidth ? 9 : 6) : 3)); - - switch (RM) - { - case 0: - if (WM) BuildLineRAM160B(graphaddr); else BuildLineRAM160A(graphaddr); - break; - case 1: - continue; - case 2: - if (WM) BuildLineRAM320B(graphaddr); else BuildLineRAM320D(graphaddr); - break; - case 3: - if (WM) BuildLineRAM320C(graphaddr); else BuildLineRAM320A(graphaddr); - break; - } - } - } - - void BuildLineRAM160A(ushort graphaddr) - { - var indbytes = (INDMode && CWidth) ? 2 : 1; - var hpos = HPOS << 1; - var dataaddr = (ushort)(graphaddr + (Offset << 8)); - - for (var i=0; i < Width; i++) - { - if (INDMode) - { - dataaddr = WORD(DmaRead(graphaddr + i), Registers[CHARBASE] + Offset); - } - - for (var j=0; j < indbytes; j++) - { - if (Holey == 0x02 && ((dataaddr & 0x9000) == 0x9000) || Holey == 0x01 && ((dataaddr & 0x8800) == 0x8800)) - { - hpos += 8; - dataaddr++; - AssertDebug(!Kangaroo); - continue; - } - - int d = DmaRead(dataaddr++); - - var c = (d & 0xc0) >> 6; - if (c != 0) - { - var val = (byte)(PaletteNo | c); - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = val; - } - AssertDebug(c != 0 || c == 0 && !Kangaroo); - - hpos += 2; - - c = (d & 0x30) >> 4; - if (c != 0) - { - var val = (byte)(PaletteNo | c); - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = val; - } - AssertDebug(c != 0 || c == 0 && !Kangaroo); - - hpos += 2; - - c = (d & 0x0c) >> 2; - if (c != 0) - { - var val = (byte)(PaletteNo | c); - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = val; - } - AssertDebug(c != 0 || c == 0 && !Kangaroo); - - hpos += 2; - - c = d & 0x03; - if (c != 0) - { - var val = (byte)(PaletteNo | c); - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = val; - } - AssertDebug(c != 0 || c == 0 && !Kangaroo); - - hpos += 2; - } - } - } - - void BuildLineRAM160B(ushort graphaddr) - { - var indbytes = (INDMode && CWidth) ? 2 : 1; - var hpos = HPOS << 1; - var dataaddr = (ushort)(graphaddr + (Offset << 8)); - - for (var i = 0; i < Width; i++) - { - if (INDMode) - { - dataaddr = WORD(DmaRead(graphaddr + i), Registers[CHARBASE] + Offset); - } - - for (var j=0; j < indbytes; j++) - { - if (Holey == 0x02 && ((dataaddr & 0x9000) == 0x9000) || Holey == 0x01 && ((dataaddr & 0x8800) == 0x8800)) - { - hpos += 4; - dataaddr++; - continue; - } - - int d = DmaRead(dataaddr++); - - var c = (d & 0xc0) >> 6; - if (c != 0) - { - var p = ((PaletteNo >> 2) & 0x04) | ((d & 0x0c) >> 2); - var val = (byte)((p << 2) | c); - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = val; - } - else if (Kangaroo) - { - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = 0; - } - - hpos += 2; - - c = (d & 0x30) >> 4; - if (c != 0) - { - var p = ((PaletteNo >> 2) & 0x04) | (d & 0x03); - var val = (byte)((p << 2) | c); - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = val; - } - else if (Kangaroo) - { - LineRAM[hpos & 0x1ff] = LineRAM[(hpos+1) & 0x1ff] = 0; - } - - hpos += 2; - } - } - } - - void BuildLineRAM320A(ushort graphaddr) - { - var color = (byte)(PaletteNo | 2); - var hpos = HPOS << 1; - var dataaddr = (ushort)(graphaddr + (Offset << 8)); - - AssertDebug(!CWidth); - - for (var i = 0; i < Width; i++) - { - if (INDMode) - { - dataaddr = WORD(DmaRead(graphaddr + i), Registers[CHARBASE] + Offset); - } - - if (Holey == 0x02 && ((dataaddr & 0x9000) == 0x9000) || Holey == 0x01 && ((dataaddr & 0x8800) == 0x8800)) - { - hpos += 8; - dataaddr++; - continue; - } - - int d = DmaRead(dataaddr++); - - if ((d & 0x80) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x40) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x20) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x10) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x08) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x04) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x02) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x01) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - } - } - - void BuildLineRAM320B(ushort graphaddr) - { - var indbytes = (INDMode && CWidth) ? 2 : 1; - var hpos = HPOS << 1; - var dataaddr = (ushort)(graphaddr + (Offset << 8)); - - for (var i = 0; i < Width; i++) - { - if (INDMode) - { - dataaddr = WORD(DmaRead(graphaddr + i), Registers[CHARBASE] + Offset); - } - - for (var j=0; j < indbytes; j++) - { - if (Holey == 0x02 && ((dataaddr & 0x9000) == 0x9000) || Holey == 0x01 && ((dataaddr & 0x8800) == 0x8800)) - { - hpos += 4; - dataaddr++; - continue; - } - - int d = DmaRead(dataaddr++); - - var c = ((d & 0x80) >> 6) | ((d & 0x08) >> 3); - if (c != 0) - { - if ((d & 0xc0) != 0 || Kangaroo) - LineRAM[hpos & 0x1ff] = (byte)(PaletteNo | c); - } - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - else if ((d & 0xcc) != 0) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x40) >> 5) | ((d & 0x04) >> 2); - if (c != 0) - { - if ((d & 0xc0) != 0 || Kangaroo) - LineRAM[hpos & 0x1ff] = (byte)(PaletteNo | c); - } - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - else if ((d & 0xcc) != 0) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x20) >> 4) | ((d & 0x02) >> 1); - if (c != 0) - { - if ((d & 0x30) != 0 || Kangaroo) - LineRAM[hpos & 0x1ff] = (byte)(PaletteNo | c); - } - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - else if ((d & 0x33) != 0) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x10) >> 3) | (d & 0x01); - if (c != 0) - { - if ((d & 0x30) != 0 || Kangaroo) - LineRAM[hpos & 0x1ff] = (byte)(PaletteNo | c); - } - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - else if ((d & 0x33) != 0) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - } - } - } - - void BuildLineRAM320C(ushort graphaddr) - { - var hpos = HPOS << 1; - var dataaddr = (ushort)(graphaddr + (Offset << 8)); - - AssertDebug(!CWidth); - - for (var i = 0; i < Width; i++) - { - if (INDMode) - { - dataaddr = WORD(DmaRead(graphaddr + i), Registers[CHARBASE] + Offset); - } - - if (Holey == 0x02 && ((dataaddr & 0x9000) == 0x9000) || Holey == 0x01 && ((dataaddr & 0x8800) == 0x8800)) - { - hpos += 4; - dataaddr++; - continue; - } - - int d = DmaRead(dataaddr++); - - var color = (byte)(((((d & 0x0c) >> 2) | ((PaletteNo >> 2) & 0x04)) << 2) | 2); - - if ((d & 0x80) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x40) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - color = (byte)((((d & 0x03) | ((PaletteNo >> 2) & 0x04)) << 2) | 2); - - if ((d & 0x20) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - if ((d & 0x10) != 0) - LineRAM[hpos & 0x1ff] = color; - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - } - } - - void BuildLineRAM320D(ushort graphaddr) - { - var indbytes = (INDMode && CWidth) ? 2 : 1; - var hpos = HPOS << 1; - var dataaddr = (ushort)(graphaddr + (Offset << 8)); - - for (var i = 0; i < Width; i++) - { - if (INDMode) - { - dataaddr = WORD(DmaRead(graphaddr + i), Registers[CHARBASE] + Offset); - } - - for (var j=0; j < indbytes; j++) - { - if (Holey == 0x02 && ((dataaddr & 0x9000) == 0x9000) || Holey == 0x01 && ((dataaddr & 0x8800) == 0x8800)) - { - hpos += 8; - dataaddr++; - continue; - } - - int d = DmaRead(dataaddr++); - - var c = ((d & 0x80) >> 6) | (((PaletteNo >> 2) & 2) >> 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x40) >> 5) | ((PaletteNo >> 2) & 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x20) >> 4) | (((PaletteNo >> 2) & 2) >> 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x10) >> 3) | ((PaletteNo >> 2) & 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x08) >> 2) | (((PaletteNo >> 2) & 2) >> 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x04) >> 1) | ((PaletteNo >> 2) & 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = (d & 0x02) | (((PaletteNo >> 2) & 2) >> 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - - c = ((d & 0x01) << 1) | ((PaletteNo >> 2) & 1); - if (c != 0) - LineRAM[hpos & 0x1ff] = (byte)((PaletteNo & 0x10) | c); - else if (Kangaroo) - LineRAM[hpos & 0x1ff] = 0; - - hpos++; - } - } - } - - void OutputLineRAM() - { - var fbi = ((Scanline + 1) * M.FrameBuffer.VisiblePitch) % M.FrameBuffer.VideoBufferByteLength; - - for (int i = 0; i < M.FrameBuffer.VisiblePitch; i++) - { - var colorIndex = LineRAM[i]; - M.FrameBuffer.VideoBuffer[fbi++] = Registers[BACKGRND + ((colorIndex & 3) == 0 ? 0 : colorIndex)]; - if (fbi == M.FrameBuffer.VideoBufferByteLength) - fbi = 0; - } - - for (var i = 0; i < LineRAM.Length; i++) - { - LineRAM[i] = 0; - } - } - - #endregion - - #region Maria Peek - - byte peek(ushort addr) - { - addr &= 0x3f; - var mi = M.InputState; - - switch(addr) - { - case MSTAT: - var sl = Scanline; - return (sl < FirstVisibleScanline || sl >= LastVisibleScanline) - ? (byte)0x80 // VBLANK ON - : (byte)0; // VBLANK OFF - case INPT0: return mi.SampleCapturedControllerActionState(0, ControllerAction.Trigger) ? (byte)0x80 : (byte)0; // player1,button R - case INPT1: return mi.SampleCapturedControllerActionState(0, ControllerAction.Trigger2) ? (byte)0x80 : (byte)0; // player1,button L - case INPT2: return mi.SampleCapturedControllerActionState(1, ControllerAction.Trigger) ? (byte)0x80 : (byte)0; // player2,button R - case INPT3: return mi.SampleCapturedControllerActionState(1, ControllerAction.Trigger2) ? (byte)0x80 : (byte)0; // player2,button L - case INPT4: return SampleINPTLatched(4) ? (byte)0 : (byte)0x80; // player1,button L/R - case INPT5: return SampleINPTLatched(5) ? (byte)0 : (byte)0x80; // player2,button L/R - default: - LogDebug("Maria: Unhandled peek at ${0:x4}, PC=${1:x4}", addr, M.CPU.PC); - var retval = Registers[addr]; - return retval; - } - } - - #endregion - - #region Maria Poke - - void poke(ushort addr, byte data) - { - addr &= 0x3f; - - switch (addr) - { - // INPUT PORT CONTROL - // Only the first four bits of INPTCTRL are used: - // D0: lock mode (after this bit has been set high, no more mode changes can be done until the console is turned off) - // D1: 0=disable MARIA (only RIOT RAM is available); 1=enable MARIA (also enables system RAM) - // D2: 0=enable BIOS at $8000-$FFFF (actually NTSC only uses 4KB and PAL uses 16KB); 1=disable BIOS and enable cartridge - // D3: 0=disable TIA video pull-ups (video output is MARIA instead of TIA); 1=enable TIA video pull-ups (video output is TIA instead of MARIA) - // - case INPTCTRL: - if (CtrlLock) - { - Log("Maria: INPTCTRL: LOCKED: Ignoring: ${0:x2}, PC=${1:x4}", data, M.CPU.PC); - break; - } - - CtrlLock = (data & (1 << 0)) != 0; - var mariaEnable = (data & (1 << 1)) != 0; - var biosDisable = (data & (1 << 2)) != 0; - var tiaopEnable = (data & (1 << 3)) != 0; - - Log("Maria: INPTCTRL: ${0:x2}, PC=${1:x4}, lockMode={2}, mariaEnable={3} biosDisable={4} tiaOutput={5}", - data, M.CPU.PC, CtrlLock, mariaEnable, biosDisable, tiaopEnable); - - if (biosDisable) - { - M.SwapOutBIOS(); - } - else - { - M.SwapInBIOS(); - } - break; - case WSYNC: - // Request a CPU preemption to service the delay request - M.CPU.EmulatorPreemptRequest = true; - break; - case CTRL: - ColorKill = (data & 0x80) != 0; - DMAEnabled = (data & 0x60) == 0x40; - CWidth = (data & 0x10) != 0; - BCntl = (data & 0x08) != 0; - Kangaroo = (data & 0x04) != 0; - RM = (byte)(data & 0x03); - break; - case MSTAT: - break; - case CHARBASE: - case DPPH: - case DPPL: - Registers[addr] = data; - break; - case BACKGRND: - case P0C1: - case P0C2: - case P0C3: - case P1C1: - case P1C2: - case P1C3: - case P2C1: - case P2C2: - case P2C3: - case P3C1: - case P3C2: - case P3C3: - case P4C1: - case P4C2: - case P4C3: - case P5C1: - case P5C2: - case P5C3: - case P6C1: - case P6C2: - case P6C3: - case P7C1: - case P7C2: - case P7C3: - Registers[addr] = data; - break; - case AUDC0: - case AUDC1: - case AUDF0: - case AUDF1: - case AUDV0: - case AUDV1: - TIASound.Update(addr, data); - break; - case OFFSET: - Log("Maria: OFFSET: ROM wrote ${0:x2}, PC=${1:x4} (reserved for future expansion)", data, M.CPU.PC); - break; - default: - Registers[addr] = data; - LogDebug("Maria: Unhandled poke:${0:x4} w/${1:x2}, PC=${2:x4}", addr, data, M.CPU.PC); - break; - } - } - - #endregion - - #region Input Helpers - - bool SampleINPTLatched(int inpt) - { - var mi = M.InputState; - var playerNo = inpt - 4; - - switch (playerNo == 0 ? mi.LeftControllerJack : mi.RightControllerJack) - { - case Controller.Joystick: - return mi.SampleCapturedControllerActionState(playerNo, ControllerAction.Trigger); - case Controller.ProLineJoystick: - var portbline = 4 << (playerNo << 1); - if ((M.PIA.DDRB & portbline) != 0 && (M.PIA.WrittenPortB & portbline) == 0) - return false; - return mi.SampleCapturedControllerActionState(playerNo, ControllerAction.Trigger) - || mi.SampleCapturedControllerActionState(playerNo, ControllerAction.Trigger2); - case Controller.Lightgun: - - // This is one area where always running fixed at the faster CPU frequency creates emulation challenges. - // Fortunately since lightgun sampling is a dedicated activity on a frame, the job of compensating is tractable. - - // Track the number of samples this frame, the time of the first sample, and capture the lightgun location. - if (_lightgunFirstSampleCpuClock == 0) - { - _lightgunFirstSampleCpuClock = M.CPU.Clock; - _lightgunFrameSamples = 0; - mi.SampleCapturedLightGunPosition(playerNo, out _lightgunSampledScanline, out _lightgunSampledVisibleHpos); - } - _lightgunFrameSamples++; - - // Magic Adjustment Factor - // Seems sufficient to account for the timing impact of successive lightrun reads (i.e., 'slow' memory accesses.) - // Obtained through through trial-and-error. - const float magicAdjustmentFactor = 2.135f; - - var firstLightgunSampleMariaFrameClock = (int)((_lightgunFirstSampleCpuClock - _startOfFrameCpuClock) << 2); - var mariaClocksSinceFirstLightgunSample = (int)((M.CPU.Clock - _lightgunFirstSampleCpuClock) << 2); - var adjustmentMariaClocks = (int)Math.Round(_lightgunFrameSamples * magicAdjustmentFactor); - var actualMariaFrameClock = firstLightgunSampleMariaFrameClock + mariaClocksSinceFirstLightgunSample + adjustmentMariaClocks; - var actualScanline = actualMariaFrameClock / 456; - var actualHpos = actualMariaFrameClock % 456; - - // Lightgun sampling looks intended to begin at the start of the scanline. - // Compensate with another magic constant since we're always off by a fixed amount. - actualHpos -= 62; - if (actualHpos < 0) - { - actualHpos += 456; - actualScanline--; - } - - var sampledScanline = _lightgunSampledScanline; - var sampledVisibleHpos = _lightgunSampledVisibleHpos; - - // Seems reasonable the gun sees more than a single pixel (more like a circle or oval) and triggers sooner accordingly. - // These adjustments were obtained through trial-and-error. - if (_isPal) - { - sampledScanline -= 19; - } - else - { - sampledScanline -= 16; - sampledVisibleHpos += 4; - } - return (actualScanline >= sampledScanline) && (actualHpos >= (sampledVisibleHpos + 136 /* HBLANK clocks */)); - } - return false; - } - - #endregion - - #region Serialization Members - - public Maria(DeserializationContext input, Machine7800 m, int scanlines) - { - if (input == null) - throw new ArgumentNullException("input"); - if (m == null) - throw new ArgumentNullException("m"); - - M = m; - InitializeVisibleScanlineValues(scanlines); - TIASound = new TIASound(input, M, CPU_TICKS_PER_AUDIO_SAMPLE); - - var version = input.CheckVersion(1, 2); - LineRAM = input.ReadExpectedBytes(512); - if (version == 1) - { - // formerly persisted values, MariaPalette[8,4] - for (var i = 0; i < 32; i++) - input.ReadByte(); - } - Registers = input.ReadExpectedBytes(0x40); - if (version == 1) - { - // formerly persisted value, Scanline - input.ReadInt32(); - } - switch (version) - { - case 1: - WM = (input.ReadByte() != 0); - break; - case 2: - WM = input.ReadBoolean(); - break; - } - DLL = input.ReadUInt16(); - DL = input.ReadUInt16(); - Offset = input.ReadInt32(); - Holey = input.ReadInt32(); - Width = input.ReadInt32(); - HPOS = input.ReadByte(); - PaletteNo = input.ReadByte(); - INDMode = input.ReadBoolean(); - if (version == 1) - { - // formerly persisted value (DLI) - input.ReadBoolean(); - } - CtrlLock = input.ReadBoolean(); - if (version == 1) - { - // formerly persisted value (VBLANK) - input.ReadByte(); - } - DMAEnabled = input.ReadBoolean(); - if (version == 1) - { - // formerly persisted value (DMAOn) - input.ReadBoolean(); - } - ColorKill = input.ReadBoolean(); - CWidth = input.ReadBoolean(); - BCntl = input.ReadBoolean(); - Kangaroo = input.ReadBoolean(); - RM = input.ReadByte(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.Write(TIASound); - - output.WriteVersion(2); - output.Write(LineRAM); - output.Write(Registers); - output.Write(WM); - output.Write(DLL); - output.Write(DL); - output.Write(Offset); - output.Write(Holey); - output.Write(Width); - output.Write(HPOS); - output.Write((byte)PaletteNo); - output.Write(INDMode); - output.Write(CtrlLock); - output.Write(DMAEnabled); - output.Write(ColorKill); - output.Write(CWidth); - output.Write(BCntl); - output.Write(Kangaroo); - output.Write(RM); - } - - #endregion - - #region Helpers - - void ConsumeNextDLLEntry() - { - // Display List List (DLL) entry - var dll0 = DmaRead(DLL++); // DLI, Holey, Offset - var dll1 = DmaRead(DLL++); // High DL address - var dll2 = DmaRead(DLL++); // Low DL address - - var dli = (dll0 & 0x80) != 0; - Holey = (dll0 & 0x60) >> 5; - Offset = dll0 & 0x0f; - - // Update current Display List (DL) - DL = WORD(dll2, dll1); - - if (dli) - { - M.CPU.NMIInterruptRequest = true; - - // DMA TIMING: One tick between DMA Shutdown and DLI - _dmaClocks += 1; - } - } - - void InitializeVisibleScanlineValues(int scanlines) - { - switch (scanlines) - { - case 262: // NTSC - FirstVisibleScanline = 11; - LastVisibleScanline = FirstVisibleScanline + 242; - _isPal = false; - break; - case 312: // PAL - FirstVisibleScanline = 11; - LastVisibleScanline = FirstVisibleScanline + 292; - _isPal = true; - break; - default: - throw new ArgumentException("scanlines must be 262 or 312."); - } - } - - void Log(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - // convenience overload - static ushort WORD(int lsb, int msb) - { - return WORD((byte)lsb, (byte)msb); - } - - static ushort WORD(byte lsb, byte msb) - { - return (ushort)(lsb | msb << 8); - } - - // convenience overload - byte DmaRead(int addr) - { - return DmaRead((ushort)addr); - } - - byte DmaRead(ushort addr) - { -#if DEBUG - if (addr < 0x1800) - LogDebug("Maria: Questionable DMA read at ${0:x4} by PC=${1:x4}", addr, M.CPU.PC); -#endif - return M.Mem[addr]; - } - - [System.Diagnostics.Conditional("DEBUG")] - void LogDebug(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - [System.Diagnostics.Conditional("DEBUG")] - void AssertDebug(bool cond) - { - if (!cond) - System.Diagnostics.Debugger.Break(); - } - - #endregion - } -} diff --git a/EMU7800/Core/MariaTables.cs b/EMU7800/Core/MariaTables.cs deleted file mode 100644 index aa8745ee64..0000000000 --- a/EMU7800/Core/MariaTables.cs +++ /dev/null @@ -1,180 +0,0 @@ -/* - * MariaTables.cs - * - * Palette tables for the Maria class. - * All derived from Dan Boris' 7800/MAME code. - * - * Copyright © 2004 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public static class MariaTables - { - 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 - }; - } -} diff --git a/EMU7800/Core/NullDevice.cs b/EMU7800/Core/NullDevice.cs deleted file mode 100644 index d0c691543d..0000000000 --- a/EMU7800/Core/NullDevice.cs +++ /dev/null @@ -1,78 +0,0 @@ -/* - * NullDevice.cs - * - * Default memory mappable device. - * - * Copyright © 2003, 2004 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class NullDevice : IDevice - { - MachineBase M { get; set; } - - #region IDevice Members - - public void Reset() - { - Log("{0} reset", this); - } - - public byte this[ushort addr] - { - get - { - LogDebug("NullDevice: Peek at ${0:x4}, PC=${1:x4}", addr, M.CPU.PC); - return 0; - } - set - { - LogDebug("NullDevice: Poke at ${0:x4},${1:x2}, PC=${2:x4}", addr, value, M.CPU.PC); - } - } - - #endregion - - public override String ToString() - { - return "NullDevice"; - } - - #region Constructors - - private NullDevice() - { - } - - public NullDevice(MachineBase m) - { - if (m == null) - throw new ArgumentNullException("m"); - M = m; - } - - #endregion - - #region Helpers - - void Log(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - [System.Diagnostics.Conditional("DEBUG")] - void LogDebug(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/NullLogger.cs b/EMU7800/Core/NullLogger.cs deleted file mode 100644 index 1604d3b883..0000000000 --- a/EMU7800/Core/NullLogger.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace EMU7800.Core -{ - public class NullLogger : ILogger - { - public void WriteLine(string format, params object[] args) - { - } - - public void WriteLine(object value) - { - } - - public void Write(string format, params object[] args) - { - } - - public void Write(object value) - { - } - } -} diff --git a/EMU7800/Core/PIA.cs b/EMU7800/Core/PIA.cs deleted file mode 100644 index 1da65519db..0000000000 --- a/EMU7800/Core/PIA.cs +++ /dev/null @@ -1,348 +0,0 @@ -/* - * PIA.cs - * - * The Peripheral Interface Adapter (6532) device. - * a.k.a. RIOT (RAM I/O Timer?) - * - * Copyright © 2003, 2004, 2012 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class PIA : IDevice - { - readonly MachineBase M; - - readonly byte[] RAM = new byte[0x80]; - - ulong TimerTarget; - int TimerShift; - bool IRQEnabled, IRQTriggered; - - public byte DDRA { get; private set; } - public byte DDRB { get; private set; } - - public byte WrittenPortA { get; private set; } - public byte WrittenPortB { get; private set; } - - #region IDevice Members - - public void Reset() - { - // Some games will loop/hang on $0284 if these are initialized to zero - TimerShift = 10; - TimerTarget = M.CPU.Clock + (ulong)(0xff << TimerShift); - - IRQEnabled = false; - IRQTriggered = false; - - DDRA = 0; - - Log("{0} reset", this); - } - - public byte this[ushort addr] - { - get { return peek(addr); } - set { poke(addr, value); } - } - - #endregion - - public override string ToString() - { - return "PIA/RIOT M6532"; - } - - #region Constructors - - private PIA() - { - } - - public PIA(MachineBase m) - { - if (m == null) - throw new ArgumentNullException("m"); - M = m; - } - - #endregion - - byte peek(ushort addr) - { - if ((addr & 0x200) == 0) - { - return RAM[addr & 0x7f]; - } - - switch ((byte)(addr & 7)) - { - case 0: // SWCHA: Controllers - return ReadPortA(); - case 1: // SWCHA DDR: 0=input, 1=output - return DDRA; - case 2: // SWCHB: Console switches (on 7800, PB2 & PB4 are used) - return ReadPortB(); - case 3: // SWCHB DDR: 0=input, 1=output - return 0; - case 4: // INTIM - case 6: - return ReadTimerRegister(); - case 5: // INTFLG - case 7: - return ReadInterruptFlag(); - default: - LogDebug("PIA: Unhandled peek ${0:x4}, PC=${1:x4}", addr, M.CPU.PC); - return 0; - } - } - - void poke(ushort addr, byte data) - { - if ((addr & 0x200) == 0) - { - RAM[addr & 0x7f] = data; - return; - } - - // A2 Distinguishes I/O registers from the Timer - if ((addr & 0x04) != 0) - { - if ((addr & 0x10) != 0) - { - IRQEnabled = (addr & 0x08) != 0; - SetTimerRegister(data, addr & 3); - } - else - { - LogDebug("PIA: Timer: Unhandled poke ${0:x4} w/${1:x2}, PC=${2:x4}", addr, data, M.CPU.PC); - } - } - else - { - switch ((byte)(addr & 3)) - { - case 0: // SWCHA: Port A - WritePortA(data); - break; - case 1: // SWACNT: Port A DDR - DDRA = data; - break; - case 2: // SWCHB: Port B - WritePortB(data); - break; - case 3: // SWBCNT: Port B DDR - DDRB = data; - break; - } - } - } - - // 0: TIM1T: set 1 clock interval ( 838 nsec/interval) - // 1: TIM8T: set 8 clock interval ( 6.7 usec/interval) - // 2: TIM64T: set 64 clock interval ( 53.6 usec/interval) - // 3: T1024T: set 1024 clock interval (858.2 usec/interval) - void SetTimerRegister(byte data, int interval) - { - IRQTriggered = false; - TimerShift = new[] { 0, 3, 6, 10 }[interval]; - TimerTarget = M.CPU.Clock + (ulong)(data << TimerShift); - } - - byte ReadTimerRegister() - { - IRQTriggered = false; - var delta = (int)(TimerTarget - M.CPU.Clock); - if (delta >= 0) - { - return (byte)(delta >> TimerShift); - } - if (delta != -1) - { - IRQTriggered = true; - } - return (byte)(delta >= -256 ? delta : 0); - } - - byte ReadInterruptFlag() - { - var delta = (int)(TimerTarget - M.CPU.Clock); - return (byte)((delta >= 0 || IRQEnabled && IRQTriggered) ? 0x00 : 0x80); - } - - // PortA: Controller Jacks - // - // Left Jack Right Jack - // ------------- ------------- - // \ 1 2 3 4 5 / \ 1 2 3 4 5 / - // \ 6 7 8 9 / \ 6 7 8 9 / - // --------- --------- - // - // pin 1 D4 PIA SWCHA D0 PIA SWCHA - // pin 2 D5 PIA SWCHA D1 PIA SWCHA - // pin 3 D6 PIA SWCHA D2 PIA SWCHA - // pin 4 D7 PIA SWCHA D3 PIA SWCHA - // pin 5 D7 TIA INPT1 (Dumped) D7 TIA INPT3 (Dumped) 7800: Right Fire - // pin 6 D7 TIA INPT4 (Latched) D7 TIA INPT5 (Latched) 2600: Fire - // pin 7 +5 +5 - // pin 8 GND GND - // pin 9 D7 TIA INPT0 (Dumped) D7 TIA INPT2 (Dumped) 7800: Left Fire - // - byte ReadPortA() - { - var porta = 0; - var mi = M.InputState; - - switch (mi.LeftControllerJack) - { - case Controller.Joystick: - case Controller.ProLineJoystick: - case Controller.BoosterGrip: - porta |= mi.SampleCapturedControllerActionState(0, ControllerAction.Up) ? 0 : (1 << 4); - porta |= mi.SampleCapturedControllerActionState(0, ControllerAction.Down) ? 0 : (1 << 5); - porta |= mi.SampleCapturedControllerActionState(0, ControllerAction.Left) ? 0 : (1 << 6); - porta |= mi.SampleCapturedControllerActionState(0, ControllerAction.Right) ? 0 : (1 << 7); - break; - case Controller.Driving: - porta |= mi.SampleCapturedDrivingState(0) << 4; - break; - case Controller.Paddles: - porta |= mi.SampleCapturedControllerActionState(0, ControllerAction.Trigger) ? 0 : (1 << 7); - porta |= mi.SampleCapturedControllerActionState(1, ControllerAction.Trigger) ? 0 : (1 << 6); - break; - case Controller.Lightgun: - porta |= mi.SampleCapturedControllerActionState(0, ControllerAction.Trigger) ? (1 << 4) : 0; - break; - } - - switch (mi.RightControllerJack) - { - case Controller.Joystick: - case Controller.ProLineJoystick: - case Controller.BoosterGrip: - porta |= mi.SampleCapturedControllerActionState(1, ControllerAction.Up) ? 0 : (1 << 0); - porta |= mi.SampleCapturedControllerActionState(1, ControllerAction.Down) ? 0 : (1 << 1); - porta |= mi.SampleCapturedControllerActionState(1, ControllerAction.Left) ? 0 : (1 << 2); - porta |= mi.SampleCapturedControllerActionState(1, ControllerAction.Right) ? 0 : (1 << 3); - break; - case Controller.Driving: - porta |= mi.SampleCapturedDrivingState(1); - break; - case Controller.Paddles: - porta |= mi.SampleCapturedControllerActionState(2, ControllerAction.Trigger) ? 0 : (1 << 3); - porta |= mi.SampleCapturedControllerActionState(3, ControllerAction.Trigger) ? 0 : (1 << 2); - break; - case Controller.Lightgun: - porta |= mi.SampleCapturedControllerActionState(1, ControllerAction.Trigger) ? (1 << 0) : 0; - break; - } - - return (byte)porta; - } - - void WritePortA(byte porta) - { - WrittenPortA = (byte)((porta & DDRA) | (WrittenPortA & (~DDRA))); - } - - void WritePortB(byte portb) - { - WrittenPortB = (byte)((portb & DDRB) | (WrittenPortB & (~DDRB))); - } - - // PortB: Console Switches - // - // D0 Game Reset 0=on - // D1 Game Select 0=on - // D2 (used on 7800) - // D3 Console Color 1=Color, 0=B/W - // D4 (used on 7800) - // D5 (unused) - // D6 Left Difficulty A 1=A (pro), 0=B (novice) - // D7 Right Difficulty A 1=A (pro), 0=B (novice) - // - byte ReadPortB() - { - var portb = 0; - var mi = M.InputState; - - portb |= mi.SampleCapturedConsoleSwitchState(ConsoleSwitch.GameReset) ? 0 : (1 << 0); - portb |= mi.SampleCapturedConsoleSwitchState(ConsoleSwitch.GameSelect) ? 0 : (1 << 1); - portb |= mi.SampleCapturedConsoleSwitchState(ConsoleSwitch.GameBW) ? 0 : (1 << 3); - portb |= mi.SampleCapturedConsoleSwitchState(ConsoleSwitch.LeftDifficultyA) ? (1 << 6) : 0; - portb |= mi.SampleCapturedConsoleSwitchState(ConsoleSwitch.RightDifficultyA) ? (1 << 7) : 0; - - return (byte)portb; - } - - #region Serialization Members - - public PIA(DeserializationContext input, MachineBase m) : this(m) - { - if (input == null) - throw new ArgumentNullException("input"); - - var version = input.CheckVersion(1, 2); - RAM = input.ReadExpectedBytes(0x80); - TimerTarget = input.ReadUInt64(); - TimerShift = input.ReadInt32(); - IRQEnabled = input.ReadBoolean(); - IRQTriggered = input.ReadBoolean(); - DDRA = input.ReadByte(); - WrittenPortA = input.ReadByte(); - if (version > 1) - { - DDRB = input.ReadByte(); - WrittenPortB = input.ReadByte(); - } - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(2); - output.Write(RAM); - output.Write(TimerTarget); - output.Write(TimerShift); - output.Write(IRQEnabled); - output.Write(IRQTriggered); - output.Write(DDRA); - output.Write(WrittenPortA); - output.Write(DDRB); - output.Write(WrittenPortB); - } - - #endregion - - #region Helpers - - void Log(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - [System.Diagnostics.Conditional("DEBUG")] - void LogDebug(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - [System.Diagnostics.Conditional("DEBUG")] - void AssertDebug(bool cond) - { - if (!cond) - System.Diagnostics.Debugger.Break(); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/PokeySound.cs b/EMU7800/Core/PokeySound.cs deleted file mode 100644 index fe09ecfdd1..0000000000 --- a/EMU7800/Core/PokeySound.cs +++ /dev/null @@ -1,437 +0,0 @@ -/* - * PokeySound.cs - * - * Emulation of the audio features of the Atari Pot Keyboard Integrated Circuit (POKEY, C012294). - * - * Implementation inspired by prior works of Greg Stanton (ProSystem Emulator) and Ron Fries. - * - * Copyright © 2012 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class PokeySound - { - #region Constants and Tables - - const int - AUDF1 = 0x00, // write reg: channel 1 frequency - AUDC1 = 0x01, // write reg: channel 1 generator - AUDF2 = 0x02, // write reg: channel 2 frequency - AUDC2 = 0x03, // write reg: channel 2 generator - AUDF3 = 0x04, // write reg: channel 3 frequency - AUDC3 = 0x05, // write reg: channel 3 generator - AUDF4 = 0x06, // write reg: channel 4 frequency - AUDC4 = 0x07, // write reg: channel 4 generator - AUDCTL = 0x08, // write reg: control over audio channels - SKCTL = 0x0f, // write reg: control over serial port - RANDOM = 0x0a; // read reg: random number generator value - - const int - AUDCTL_POLY9 = 0x80, // make 17-bit poly counter into a 9-bit poly counter - AUDCTL_CH1_179 = 0x40, // clocks channel 1 with 1.79 MHz, instead of 64 kHz - AUDCTL_CH3_179 = 0x20, // clocks channel 3 with 1.79 MHz, instead of 64 kHz - AUDCTL_CH1_CH2 = 0x10, // clock channel 2 with channel 1, instead of 64 kHz (16-bit) - AUDCTL_CH3_CH4 = 0x08, // clock channel 4 with channel 3, instead of 64 kHz (16-bit) - AUDCTL_CH1_FILTER = 0x04, // inserts high-pass filter into channel 1, clocked by channel 3 - AUDCTL_CH2_FILTER = 0x02, // inserts high-pass filter into channel 2, clocked by channel 4 - AUDCTL_CLOCK_15 = 0x01; // change normal clock base from 64 kHz to 15 kHz - - const int - AUDC_NOTPOLY5 = 0x80, - AUDC_POLY4 = 0x40, - AUDC_PURE = 0x20, - AUDC_VOLUME_ONLY = 0x10, - AUDC_VOLUME_MASK = 0x0f; - - const int - DIV_64 = 28, - DIV_15 = 114, - POLY9_SIZE = 0x01ff, - POLY17_SIZE = 0x0001ffff, - POKEY_FREQ = 1787520, - SKCTL_RESET = 3; - - const int CPU_TICKS_PER_AUDIO_SAMPLE = 57; - - readonly byte[] _poly04 = { 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; - readonly byte[] _poly05 = { 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1 }; - readonly byte[] _poly17 = new byte[POLY9_SIZE]; // should be POLY17_SIZE, but instead wrapping around to conserve storage - - readonly Random _random = new Random(); - - #endregion - - #region Object State - - readonly MachineBase M; - - readonly int _pokeyTicksPerSample; - int _pokeyTicks; - - ulong _lastUpdateCpuClock; - int _bufferIndex; - - readonly byte[] _audf = new byte[4]; - readonly byte[] _audc = new byte[4]; - byte _audctl, _skctl; - - int _baseMultiplier; - int _poly04Counter; - int _poly05Counter; - int _poly17Counter, _poly17Size; - - readonly int[] _divideMax = new int[4]; - readonly int[] _divideCount = new int[4]; - readonly byte[] _output = new byte[4]; - readonly byte[] _outvol = new byte[4]; - - #endregion - - #region Public Members - - public void Reset() - { - _poly04Counter = _poly05Counter = _poly17Counter = _audctl = _skctl = 0; - - _baseMultiplier = DIV_64; - _poly17Size = POLY17_SIZE; - - _pokeyTicks = 0; - - for (var ch = 0; ch < 4; ch++) - { - _outvol[ch] = _output[ch] = _audc[ch] = _audf[ch] = 0; - _divideCount[ch] = Int32.MaxValue; - _divideMax[ch] = Int32.MaxValue; - } - } - - public void StartFrame() - { - _lastUpdateCpuClock = M.CPU.Clock; - _bufferIndex = 0; - } - - public void EndFrame() - { - RenderSamples(M.FrameBuffer.SoundBufferByteLength - _bufferIndex); - } - - public byte Read(ushort addr) - { - addr &= 0xf; - - switch (addr) - { - // If the 2 least significant bits of SKCTL are 0, the random number generator is disabled (return all 1s.) - // Ballblazer music relies on this. - case RANDOM: - return (_skctl & SKCTL_RESET) == 0 ? (byte)0xff : (byte)_random.Next(0xff); - default: - return 0; - } - } - - public void Update(ushort addr, byte data) - { - if (M.CPU.Clock > _lastUpdateCpuClock) - { - var updCpuClocks = (int)(M.CPU.Clock - _lastUpdateCpuClock); - var samples = updCpuClocks / CPU_TICKS_PER_AUDIO_SAMPLE; - RenderSamples(samples); - _lastUpdateCpuClock += (ulong)(samples * CPU_TICKS_PER_AUDIO_SAMPLE); - } - - addr &= 0xf; - - switch (addr) - { - case AUDF1: - _audf[0] = data; - ResetChannel1(); - if ((_audctl & AUDCTL_CH1_CH2) != 0) - ResetChannel2(); - break; - case AUDC1: - _audc[0] = data; - ResetChannel1(); - break; - case AUDF2: - _audf[1] = data; - ResetChannel2(); - break; - case AUDC2: - _audc[1] = data; - ResetChannel2(); - break; - case AUDF3: - _audf[2] = data; - ResetChannel3(); - if ((_audctl & AUDCTL_CH3_CH4) != 0) - ResetChannel4(); - break; - case AUDC3: - _audc[2] = data; - ResetChannel3(); - break; - case AUDF4: - _audf[3] = data; - ResetChannel4(); - break; - case AUDC4: - _audc[3] = data; - ResetChannel4(); - break; - case AUDCTL: - _audctl = data; - _poly17Size = ((_audctl & AUDCTL_POLY9) != 0) ? POLY9_SIZE : POLY17_SIZE; - _baseMultiplier = ((_audctl & AUDCTL_CLOCK_15) != 0) ? DIV_15 : DIV_64; - ResetChannel1(); - ResetChannel2(); - ResetChannel3(); - ResetChannel4(); - break; - case SKCTL: - _skctl = data; - break; - } - } - - #endregion - - #region Constructors - - private PokeySound() - { - _random.NextBytes(_poly17); - for (var i = 0; i < _poly17.Length; i++) - _poly17[i] &= 0x01; - - Reset(); - } - - public PokeySound(MachineBase m) : this() - { - if (m == null) - throw new ArgumentNullException("m"); - - M = m; - - // Add 8-bits of fractional representation to reduce distortion on output - _pokeyTicksPerSample = (POKEY_FREQ << 8) / M.SoundSampleFrequency; - } - - #endregion - - #region Serialization Members - - public PokeySound(DeserializationContext input, MachineBase m) : this(m) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - _lastUpdateCpuClock = input.ReadUInt64(); - _bufferIndex = input.ReadInt32(); - _audf = input.ReadBytes(); - _audc = input.ReadBytes(); - _audctl = input.ReadByte(); - _skctl = input.ReadByte(); - _output = input.ReadBytes(); - _outvol = input.ReadBytes(); - _divideMax = input.ReadIntegers(4); - _divideCount = input.ReadIntegers(4); - _pokeyTicks = input.ReadInt32(); - _pokeyTicksPerSample = input.ReadInt32(); - _baseMultiplier = input.ReadInt32(); - _poly04Counter = input.ReadInt32(); - _poly05Counter = input.ReadInt32(); - _poly17Counter = input.ReadInt32(); - _poly17Size = input.ReadInt32(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(_lastUpdateCpuClock); - output.Write(_bufferIndex); - output.Write(_audf); - output.Write(_audc); - output.Write(_audctl); - output.Write(_skctl); - output.Write(_output); - output.Write(_outvol); - output.Write(_divideMax); - output.Write(_divideCount); - output.Write(_pokeyTicks); - output.Write(_pokeyTicksPerSample); - output.Write(_baseMultiplier); - output.Write(_poly04Counter); - output.Write(_poly05Counter); - output.Write(_poly17Counter); - output.Write(_poly17Size); - } - - #endregion - - #region Helpers - - void RenderSamples(int count) - { - const int POKEY_SAMPLE = 4; - var poly17Length = (_poly17Size > _poly17.Length ? _poly17.Length : _poly17Size); - - while (count > 0 && _bufferIndex < M.FrameBuffer.SoundBufferByteLength) - { - var nextEvent = POKEY_SAMPLE; - var wholeTicksToConsume = (_pokeyTicks >> 8); - - for (var ch = 0; ch < 4; ch++) - { - if (_divideCount[ch] <= wholeTicksToConsume) - { - wholeTicksToConsume = _divideCount[ch]; - nextEvent = ch; - } - } - - for (var ch = 0; ch < 4; ch++) - _divideCount[ch] -= wholeTicksToConsume; - - _pokeyTicks -= (wholeTicksToConsume << 8); - - if (nextEvent == POKEY_SAMPLE) - { - _pokeyTicks += _pokeyTicksPerSample; - - byte sample = 0; - for (var ch = 0; ch < 4; ch++) - sample += _outvol[ch]; - - M.FrameBuffer.SoundBuffer[_bufferIndex++] += sample; - count--; - - continue; - } - - _divideCount[nextEvent] += _divideMax[nextEvent]; - - _poly04Counter += wholeTicksToConsume; - _poly04Counter %= _poly04.Length; - - _poly05Counter += wholeTicksToConsume; - _poly05Counter %= _poly05.Length; - - _poly17Counter += wholeTicksToConsume; - _poly17Counter %= poly17Length; - - if ((_audc[nextEvent] & AUDC_NOTPOLY5) != 0 || _poly05[_poly05Counter] != 0) - { - if ((_audc[nextEvent] & AUDC_PURE) != 0) - _output[nextEvent] ^= 1; - else if ((_audc[nextEvent] & AUDC_POLY4) != 0) - _output[nextEvent] = _poly04[_poly04Counter]; - else - _output[nextEvent] = _poly17[_poly17Counter]; - } - - _outvol[nextEvent] = (_output[nextEvent] != 0) ? (byte)(_audc[nextEvent] & AUDC_VOLUME_MASK) : (byte)0; - } - } - - // As defined in the manual, the exact divider values are different depending on the frequency and resolution: - // 64 kHz or 15 kHz AUDF + 1 - // 1 MHz, 8-bit AUDF + 4 - // 1 MHz, 16-bit AUDF[CHAN1] + 256 * AUDF[CHAN2] + 7 - - void ResetChannel1() - { - var val = ((_audctl & AUDCTL_CH1_179) != 0) ? (_audf[0] + 4) : ((_audf[0] + 1) * _baseMultiplier); - if (val != _divideMax[0]) - { - _divideMax[0] = val; - if (val < _divideCount[0]) - _divideCount[0] = val; - } - UpdateVolumeSettingsForChannel(0); - } - - void ResetChannel2() - { - int val; - if ((_audctl & AUDCTL_CH1_CH2) != 0) - { - val = ((_audctl & AUDCTL_CH1_179) != 0) ? (_audf[1] * 256 + _audf[0] + 7) : ((_audf[1] * 256 + _audf[0] + 1) * _baseMultiplier); - } - else - { - val = ((_audf[1] + 1) * _baseMultiplier); - } - if (val != _divideMax[1]) - { - _divideMax[1] = val; - if (val < _divideCount[1]) - _divideCount[1] = val; - } - UpdateVolumeSettingsForChannel(1); - } - - void ResetChannel3() - { - var val = ((_audctl & AUDCTL_CH3_179) != 0) ? (_audf[2] + 4) : ((_audf[2] + 1) * _baseMultiplier); - if (val != _divideMax[2]) - { - _divideMax[2] = val; - if (val < _divideCount[2]) - _divideCount[2] = val; - } - UpdateVolumeSettingsForChannel(2); - } - - void ResetChannel4() - { - int val; - if ((_audctl & AUDCTL_CH3_CH4) != 0) - { - val = ((_audctl & AUDCTL_CH3_179) != 0) ? (_audf[3] * 256 + _audf[2] + 7) : ((_audf[3] * 256 + _audf[2] + 1) * _baseMultiplier); - } - else - { - val = ((_audf[3] + 1) * _baseMultiplier); - } - if (val != _divideMax[3]) - { - _divideMax[3] = val; - if (val < _divideCount[3]) - _divideCount[3] = val; - } - UpdateVolumeSettingsForChannel(3); - } - - void UpdateVolumeSettingsForChannel(int ch) - { - if (((_audc[ch] & AUDC_VOLUME_ONLY) != 0) || ((_audc[ch] & AUDC_VOLUME_MASK) == 0) || (_divideMax[ch] < (_pokeyTicksPerSample >> 8))) - { - _outvol[ch] = (byte)(_audc[ch] & AUDC_VOLUME_MASK); - _divideCount[ch] = Int32.MaxValue; - _divideMax[ch] = Int32.MaxValue; - } - } - - [System.Diagnostics.Conditional("DEBUG")] - void LogDebug(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - #endregion - } -} diff --git a/EMU7800/Core/RAM6116.cs b/EMU7800/Core/RAM6116.cs deleted file mode 100644 index 66d5296f99..0000000000 --- a/EMU7800/Core/RAM6116.cs +++ /dev/null @@ -1,65 +0,0 @@ -/* - * RAM6116.cs - * - * Implements a 6116 RAM device found in the 7800. - * - * Copyright © 2004 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - public sealed class RAM6116 : IDevice - { - readonly byte[] RAM; - - #region IDevice Members - - public void Reset() {} - - public byte this[ushort addr] - { - get { return RAM[addr & 0x07ff]; } - set { RAM[addr & 0x07ff] = value; } - } - - #endregion - - #region Constructors - - public RAM6116() - { - RAM = new byte[0x800]; - } - - public RAM6116(byte[] ram) - { - RAM = ram; - } - - #endregion - - #region Serialization Members - - public RAM6116(DeserializationContext input) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - RAM = input.ReadExpectedBytes(0x800); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(RAM); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/SerializationContext.cs b/EMU7800/Core/SerializationContext.cs deleted file mode 100644 index 2ff20a40d7..0000000000 --- a/EMU7800/Core/SerializationContext.cs +++ /dev/null @@ -1,232 +0,0 @@ -using System; -using System.IO; - -namespace EMU7800.Core -{ - /// - /// A context for serializing objects. - /// - public class SerializationContext - { - #region Fields - - readonly BinaryWriter _binaryWriter; - - #endregion - - public void Write(byte value) - { - _binaryWriter.Write(value); - } - - public void Write(ushort value) - { - _binaryWriter.Write(value); - } - - public void Write(int value) - { - _binaryWriter.Write(value); - } - - public void Write(uint value) - { - _binaryWriter.Write(value); - } - - public void Write(long value) - { - _binaryWriter.Write(value); - } - - public void Write(ulong value) - { - _binaryWriter.Write(value); - } - - public void Write(bool value) - { - _binaryWriter.Write(value); - } - - public void Write(double value) - { - _binaryWriter.Write(value); - } - - /* - public void Write(BufferElement bufferElement) - { - for (var i = 0; i < BufferElement.SIZE; i++) - Write(bufferElement[i]); - } - */ - - public void Write(byte[] bytes) - { - _binaryWriter.Write(bytes.Length); - if (bytes.Length > 0) - _binaryWriter.Write(bytes); - } - - public void Write(ushort[] ushorts) - { - var bytes = new byte[ushorts.Length << 1]; - Buffer.BlockCopy(ushorts, 0, bytes, 0, bytes.Length); - Write(bytes); - } - - public void Write(int[] ints) - { - var bytes = new byte[ints.Length << 2]; - Buffer.BlockCopy(ints, 0, bytes, 0, bytes.Length); - Write(bytes); - } - - public void Write(uint[] uints) - { - var bytes = new byte[uints.Length << 2]; - Buffer.BlockCopy(uints, 0, bytes, 0, bytes.Length); - Write(bytes); - } - - public void Write(bool[] booleans) - { - var bytes = new byte[booleans.Length]; - for (var i = 0; i < bytes.Length; i++) - { - bytes[i] = (byte)(booleans[i] ? 0xff : 0x00); - } - Write(bytes); - } - - public void Write(MachineBase m) - { - WriteTypeName(m); - m.GetObjectData(this); - } - - public void Write(AddressSpace mem) - { - mem.GetObjectData(this); - } - - public void Write(M6502 cpu) - { - cpu.GetObjectData(this); - } - - public void Write(PIA pia) - { - pia.GetObjectData(this); - } - - public void Write(TIA tia) - { - tia.GetObjectData(this); - } - - public void Write(TIASound tiaSound) - { - tiaSound.GetObjectData(this); - } - - public void Write(Maria maria) - { - maria.GetObjectData(this); - } - - public void Write(Cart cart) - { - WriteTypeName(cart); - cart.GetObjectData(this); - } - - public void Write(RAM6116 ram6116) - { - ram6116.GetObjectData(this); - } - - public void Write(InputState inputState) - { - inputState.GetObjectData(this); - } - - public void WriteVersion(int version) - { - Write(0x78000087); - Write(version); - } - - public void WriteOptional(byte[] bytes) - { - var hasBytes = (bytes != null); - _binaryWriter.Write(hasBytes); - if (!hasBytes) - return; - _binaryWriter.Write(bytes.Length); - if (bytes.Length > 0) - _binaryWriter.Write(bytes); - } - - public void WriteOptional(HSC7800 hsc7800) - { - var exist = (hsc7800 != null); - Write(exist); - if (!exist) - return; - hsc7800.GetObjectData(this); - } - - public void WriteOptional(Bios7800 bios7800) - { - var exist = (bios7800 != null); - Write(exist); - if (!exist) - return; - bios7800.GetObjectData(this); - } - - public void WriteOptional(PokeySound pokeySound) - { - var exist = (pokeySound != null); - Write(exist); - if (!exist) - return; - pokeySound.GetObjectData(this); - } - - #region Constructors - - private SerializationContext() - { - } - - /// - /// Instantiates a new instance of . - /// - /// - internal SerializationContext(BinaryWriter binaryWriter) - { - if (binaryWriter == null) - throw new ArgumentNullException("binaryWriter"); - _binaryWriter = binaryWriter; - } - - #endregion - - #region Helpers - - void WriteTypeName(object o) - { - if (o == null) - throw new Emu7800SerializationException("Type unexpectedly null."); - var typeName = o.GetType().FullName; - if (string.IsNullOrWhiteSpace(typeName)) - throw new Emu7800SerializationException("Unable to discover type name."); - _binaryWriter.Write(typeName); - } - - #endregion - } -} diff --git a/EMU7800/Core/TIA.cs b/EMU7800/Core/TIA.cs deleted file mode 100644 index 5612afe624..0000000000 --- a/EMU7800/Core/TIA.cs +++ /dev/null @@ -1,1350 +0,0 @@ -/* - * TIA.cs - * - * The Television Interface Adaptor device. - * - * Copyright © 2003-2008 Mike Murphy - * - */ -using System; - -namespace EMU7800.Core -{ - #region Collision Flags - - [Flags] - public enum TIACxFlags - { - PF = 1 << 0, - BL = 1 << 1, - M0 = 1 << 2, - M1 = 1 << 3, - P0 = 1 << 4, - P1 = 1 << 5 - }; - - [Flags] - public enum TIACxPairFlags - { - M0P1 = 1 << 0, - M0P0 = 1 << 1, - M1P0 = 1 << 2, - M1P1 = 1 << 3, - P0PF = 1 << 4, - P0BL = 1 << 5, - P1PF = 1 << 6, - P1BL = 1 << 7, - M0PF = 1 << 8, - M0BL = 1 << 9, - M1PF = 1 << 10, - M1BL = 1 << 11, - BLPF = 1 << 12, - P0P1 = 1 << 13, - M0M1 = 1 << 14 - }; - - #endregion - - public sealed class TIA : IDevice - { - #region Constants - - const int - VSYNC = 0x00, // Write: vertical sync set-clear (D1) - VBLANK = 0x01, // Write: vertical blank set-clear (D7-6,D1) - WSYNC = 0x02, // Write: wait for leading edge of hrz. blank (strobe) - RSYNC = 0x03, // Write: reset hrz. sync counter (strobe) - NUSIZ0 = 0x04, // Write: number-size player-missle 0 (D5-0) - NUSIZ1 = 0x05, // Write: number-size player-missle 1 (D5-0) - COLUP0 = 0x06, // Write: color-lum player 0 (D7-1) - COLUP1 = 0x07, // Write: color-lum player 1 (D7-1) - COLUPF = 0x08, // Write: color-lum playfield (D7-1) - COLUBK = 0x09, // Write: color-lum background (D7-1) - CTRLPF = 0x0a, // Write: cntrl playfield ballsize & coll. (D5-4,D2-0) - REFP0 = 0x0b, // Write: reflect player 0 (D3) - REFP1 = 0x0c, // Write: reflect player 1 (D3) - PF0 = 0x0d, // Write: playfield register byte 0 (D7-4) - PF1 = 0x0e, // Write: playfield register byte 1 (D7-0) - PF2 = 0x0f, // Write: playfield register byte 2 (D7-0) - RESP0 = 0x10, // Write: reset player 0 (strobe) - RESP1 = 0x11, // Write: reset player 1 (strobe) - RESM0 = 0x12, // Write: reset missle 0 (strobe) - RESM1 = 0x13, // Write: reset missle 1 (strobe) - RESBL = 0x14, // Write: reset ball (strobe) - AUDC0 = 0x15, // Write: audio control 0 (D3-0) - AUDC1 = 0x16, // Write: audio control 1 (D4-0) - AUDF0 = 0x17, // Write: audio frequency 0 (D4-0) - AUDF1 = 0x18, // Write: audio frequency 1 (D3-0) - AUDV0 = 0x19, // Write: audio volume 0 (D3-0) - AUDV1 = 0x1a, // Write: audio volume 1 (D3-0) - GRP0 = 0x1b, // Write: graphics player 0 (D7-0) - GRP1 = 0x1c, // Write: graphics player 1 (D7-0) - ENAM0 = 0x1d, // Write: graphics (enable) missle 0 (D1) - ENAM1 = 0x1e, // Write: graphics (enable) missle 1 (D1) - ENABL = 0x1f, // Write: graphics (enable) ball (D1) - HMP0 = 0x20, // Write: horizontal motion player 0 (D7-4) - HMP1 = 0x21, // Write: horizontal motion player 1 (D7-4) - HMM0 = 0x22, // Write: horizontal motion missle 0 (D7-4) - HMM1 = 0x23, // Write: horizontal motion missle 1 (D7-4) - HMBL = 0x24, // Write: horizontal motion ball (D7-4) - VDELP0 = 0x25, // Write: vertical delay player 0 (D0) - VDELP1 = 0x26, // Write: vertical delay player 1 (D0) - VDELBL = 0x27, // Write: vertical delay ball (D0) - RESMP0 = 0x28, // Write: reset missle 0 to player 0 (D1) - RESMP1 = 0x29, // Write: reset missle 1 to player 1 (D1) - HMOVE = 0x2a, // Write: apply horizontal motion (strobe) - HMCLR = 0x2b, // Write: clear horizontal motion registers (strobe) - CXCLR = 0x2c, // Write: clear collision latches (strobe) - - CXM0P = 0x00, // Read collision: D7=(M0,P1); D6=(M0,P0) - CXM1P = 0x01, // Read collision: D7=(M1,P0); D6=(M1,P1) - CXP0FB = 0x02, // Read collision: D7=(P0,PF); D6=(P0,BL) - CXP1FB = 0x03, // Read collision: D7=(P1,PF); D6=(P1,BL) - CXM0FB = 0x04, // Read collision: D7=(M0,PF); D6=(M0,BL) - CXM1FB = 0x05, // Read collision: D7=(M1,PF); D6=(M1,BL) - CXBLPF = 0x06, // Read collision: D7=(BL,PF); D6=(unused) - CXPPMM = 0x07, // Read collision: D7=(P0,P1); D6=(M0,M1) - INPT0 = 0x08, // Read pot port: D7 - INPT1 = 0x09, // Read pot port: D7 - INPT2 = 0x0a, // Read pot port: D7 - INPT3 = 0x0b, // Read pot port: D7 - INPT4 = 0x0c, // Read P1 joystick trigger: D7 - INPT5 = 0x0d; // Read P2 joystick trigger: D7 - - const int CPU_TICKS_PER_AUDIO_SAMPLE = 38; - - #endregion - - #region Data Structures - - readonly byte[] RegW = new byte[0x40]; - readonly MachineBase M; - readonly TIASound TIASound; - - delegate void PokeOpTyp(ushort addr, byte data); - - PokeOpTyp[] PokeOp; - - #endregion - - #region Position Counters - - // backing fields for properties--dont reference directly - int _HSync, _P0, _P1, _M0, _M1, _BL, _HMoveCounter; - - // Horizontal Sync Counter - // this represents HSync of the last rendered CLK - // has period of 57 counts, 0-56, at 1/4 CLK (57*4=228 CLK) - // provide all horizontal timing for constructing a valid TV signal - // other movable object counters can be reset out-of-phase with HSync, hence %228 and not %57 - int HSync - { - get { return _HSync; } - set { _HSync = value % 228; } - } - - // determines the difference between HSync and PokeOpHSync - int PokeOpHSyncDelta - { - get { return (int)(Clock - LastEndClock); } - } - - // this represents the current HSync - int PokeOpHSync - { - get { return (HSync + PokeOpHSyncDelta) % 228; } - } - - // scanline last rendered to - int ScanLine; - - // current position in the frame buffer - int FrameBufferIndex; - - // bytes are batched here for writing to the FrameBuffer - //BufferElement FrameBufferElement; - - // signals when to start an HMOVE - ulong StartHMOVEClock; - - // indicates where in the HMOVE operation it is - int HMoveCounter - { - get { return _HMoveCounter; } - set { _HMoveCounter = value < 0 ? -1 : value & 0xf; } - } - - // true when there is an HMOVE executing on the current scanline - bool HMoveLatch; - - // represents the TIA color clock (CLK) - // computed off of the CPU clock, but in real life, the CPU is driven by the color CLK signal - ulong Clock - { - get { return 3 * M.CPU.Clock; } - } - - // represents the first CLK of the unrendered scanline segment - ulong StartClock; - - // represents the last CLK of the previously rendered scanline segment - ulong LastEndClock - { - get { return StartClock - 1; } - } - - #endregion - - #region Player 0 Object - - // Player 0 Horizontal Position Counter - // has period of 40 counts, 0-39, at 1/4 CLK (40*4=160 CLK=visible scanline length) - // player position counter controls the position of the respective player graphics object on each scanline - // can be reset out-of-phase with HSync, hence %160 and not %40 - int P0 - { - get { return _P0; } - set { _P0 = value % 160; } - } - - // HMOVE "more motion required" latch - bool P0mmr; - - // Player 0 graphics registers - byte EffGRP0, OldGRP0; - - // Player 0 stretch mode - int P0type; - - // 1=currently suppressing copy 1 on Player 0 - int P0suppress; - - #endregion - - #region Player 1 Object - - // Player 1 Horizontal Position Counter (identical to P0) - int P1 - { - get { return _P1; } - set { _P1 = value % 160; } - } - - // HMOVE "more motion required" latch - bool P1mmr; - - // Player 1 graphics registers - byte EffGRP1, OldGRP1; - - // Player 1 stretch mode - int P1type; - - // 1=currently suppressing copy 1 on Player 1 - int P1suppress; - - #endregion - - #region Missile 0 Object - - // Missile 0 Horizontal Position Counter - // similar to player position counters - int M0 - { - get { return _M0; } - set { _M0 = value % 160; } - } - - // HMOVE "more motion required" latch - bool M0mmr; - - int M0type, M0size; - - bool m0on; - - #endregion - - #region Missle 1 Object - - // Missile 1 Horizontal Position Counter (identical to M0) - int M1 - { - get { return _M1; } - set { _M1 = value % 160; } - } - - // HMOVE "more motion required" latch - bool M1mmr; - - int M1type, M1size; - - bool m1on; - - #endregion - - #region Ball Object - - // Ball Horizontal Position Counter - // similar to player position counters - int BL - { - get { return _BL; } - set { _BL = value % 160; } - } - - // HMOVE "more motion required" latch - bool BLmmr; - - bool OldENABL; - - int BLsize; - - bool blon; - - #endregion - - #region Misc - - uint PF210; - int PFReflectionState; - - // color-luminance for background, playfield, player 0, player 1 - byte colubk, colupf, colup0, colup1; - - bool vblankon, scoreon, pfpriority; - - bool DumpEnabled; - ulong DumpDisabledCycle; - - TIACxPairFlags Collisions; - - #endregion - - #region Public Members - - public int WSYNCDelayClocks { get; set; } - public bool EndOfFrame { get; private set; } - - public void Reset() - { - for (var i = 0; i < RegW.Length; i++) - { - RegW[i] = 0; - } - vblankon = scoreon = pfpriority = false; - m0on = m1on = blon = false; - colubk = colupf = colup0 = colup1 = 0; - PFReflectionState = 0; - - StartClock = Clock; - HSync = -1; - P0 = P1 = M0 = M1 = BL = -1; - P0mmr = P1mmr = M0mmr = M1mmr = BLmmr = false; - StartHMOVEClock = ulong.MaxValue; - HMoveCounter = -1; - - FrameBufferIndex = 0; - - TIASound.Reset(); - - Log("{0} reset", this); - } - - public override String ToString() - { - return "TIA 1A"; - } - - public void StartFrame() - { - WSYNCDelayClocks = 0; - EndOfFrame = false; - ScanLine = 0; - FrameBufferIndex %= 160; - RenderFromStartClockTo(Clock); - TIASound.StartFrame(); - } - - public byte this[ushort addr] - { - get { return peek(addr); } - set { poke(addr, value); } - } - - public void EndFrame() - { - TIASound.EndFrame(); - } - - #endregion - - #region Constructors - - private TIA() - { - BuildPokeOpTable(); - } - - public TIA(MachineBase m) : this() - { - if (m == null) - throw new ArgumentNullException("m"); - - M = m; - TIASound = new TIASound(M, CPU_TICKS_PER_AUDIO_SAMPLE); - } - - #endregion - - #region Scanline Segment Renderer - - void RenderFromStartClockTo(ulong endClock) - { - - RenderClock: - if (StartClock >= endClock) - return; - - ++HSync; - - if (StartClock == StartHMOVEClock) - { - // turn on HMOVE - HMoveLatch = true; - HMoveCounter = 0xf; - P0mmr = P1mmr = M0mmr = M1mmr = BLmmr = true; - } - else if (HSync == 0) - { - // just wrapped around, clear late HBLANK - HMoveLatch = false; - } - - // position counters are incremented during the visible portion of the scanline - if (HSync >= 68 + (HMoveLatch ? 8 : 0)) - { - ++P0; ++P1; ++M0; ++M1; ++BL; - } - - // HMOVE compare, once every 1/4 CLK when on - if (HMoveCounter >= 0 && (HSync & 3) == 0) - { - if (((HMoveCounter ^ RegW[HMP0]) & 0xf) == 0xf) P0mmr = false; - if (((HMoveCounter ^ RegW[HMP1]) & 0xf) == 0xf) P1mmr = false; - if (((HMoveCounter ^ RegW[HMM0]) & 0xf) == 0xf) M0mmr = false; - if (((HMoveCounter ^ RegW[HMM1]) & 0xf) == 0xf) M1mmr = false; - if (((HMoveCounter ^ RegW[HMBL]) & 0xf) == 0xf) BLmmr = false; - if (HMoveCounter >= 0) HMoveCounter--; - } - - // HMOVE increment, once every 1/4 CLK, 2 CLK after first compare when on - if (HMoveCounter < 0xf && (HSync & 3) == 2) - { - if (HSync < 68 + (HMoveLatch ? 8 : 0)) - { - if (P0mmr) ++P0; - if (P1mmr) ++P1; - if (M0mmr) ++M0; - if (M1mmr) ++M1; - if (BLmmr) ++BL; - } - } - - if (HSync == 68 + 76) PFReflectionState = RegW[CTRLPF] & 0x01; - - var fbyte = (byte)0; - var fbyte_colupf = colupf; - TIACxFlags cxflags = 0; - - if (vblankon || HSync < 68 + (HMoveLatch ? 8 : 0)) goto WritePixel; - - fbyte = colubk; - - var colupfon = false; - if ((PF210 & TIATables.PFMask[PFReflectionState][HSync - 68]) != 0) - { - if (scoreon) fbyte_colupf = (HSync - 68) < 80 ? colup0 : colup1; - colupfon = true; - cxflags |= TIACxFlags.PF; - } - if (blon && BL >= 0 && TIATables.BLMask[BLsize][BL]) - { - colupfon = true; - cxflags |= TIACxFlags.BL; - } - if (!pfpriority && colupfon) - { - fbyte = fbyte_colupf; - } - if (m1on && M1 >= 0 && TIATables.MxMask[M1size][M1type][M1]) - { - fbyte = colup1; - cxflags |= TIACxFlags.M1; - } - if (P1 >= 0 && (TIATables.PxMask[P1suppress][P1type][P1] & EffGRP1) != 0) - { - fbyte = colup1; - cxflags |= TIACxFlags.P1; - } - if (m0on && M0 >= 0 && TIATables.MxMask[M0size][M0type][M0]) - { - fbyte = colup0; - cxflags |= TIACxFlags.M0; - } - if (P0 >= 0 && (TIATables.PxMask[P0suppress][P0type][P0] & EffGRP0) != 0) - { - fbyte = colup0; - cxflags |= TIACxFlags.P0; - } - if (pfpriority && colupfon) - { - fbyte = fbyte_colupf; - } - - WritePixel: - Collisions |= TIATables.CollisionMask[(int)cxflags]; - - if (HSync >= 68) - { - M.FrameBuffer.VideoBuffer[FrameBufferIndex++] = fbyte; - if (FrameBufferIndex == M.FrameBuffer.VideoBufferByteLength) - FrameBufferIndex = 0; - if (HSync == 227) - ScanLine++; - } - - if (P0 >= 156) P0suppress = 0; - if (P1 >= 156) P1suppress = 0; - - // denote this CLK has been completed by incrementing to the next - StartClock++; - - goto RenderClock; - } - - #endregion - - #region TIA Peek - - byte peek(ushort addr) - { - var retval = 0; - addr &= 0xf; - - RenderFromStartClockTo(Clock); - - switch (addr) - { - case CXM0P: - retval |= ((Collisions & TIACxPairFlags.M0P1) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.M0P0) != 0 ? 0x40 : 0); - break; - case CXM1P: - retval |= ((Collisions & TIACxPairFlags.M1P0) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.M1P1) != 0 ? 0x40 : 0); - break; - case CXP0FB: - retval |= ((Collisions & TIACxPairFlags.P0PF) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.P0BL) != 0 ? 0x40 : 0); - break; - case CXP1FB: - retval |= ((Collisions & TIACxPairFlags.P1PF) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.P1BL) != 0 ? 0x40 : 0); - break; - case CXM0FB: - retval |= ((Collisions & TIACxPairFlags.M0PF) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.M0BL) != 0 ? 0x40 : 0); - break; - case CXM1FB: - retval |= ((Collisions & TIACxPairFlags.M1PF) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.M1BL) != 0 ? 0x40 : 0); - break; - case CXBLPF: - retval |= ((Collisions & TIACxPairFlags.BLPF) != 0 ? 0x80 : 0); - break; - case CXPPMM: - retval |= ((Collisions & TIACxPairFlags.P0P1) != 0 ? 0x80 : 0); - retval |= ((Collisions & TIACxPairFlags.M0M1) != 0 ? 0x40 : 0); - break; - case INPT0: - retval = DumpedInputPort(SampleINPT(0)); - break; - case INPT1: - retval = DumpedInputPort(SampleINPT(1)); - break; - case INPT2: - retval = DumpedInputPort(SampleINPT(2)); - break; - case INPT3: - retval = DumpedInputPort(SampleINPT(3)); - break; - case INPT4: - var scanline = ScanLine; - var hpos = PokeOpHSync - 68; - if (hpos < 0) - { - hpos += 228; - scanline--; - } - if (SampleINPTLatched(4, scanline, hpos)) - { - retval &= 0x7f; - } - else - { - retval |= 0x80; - } - break; - case INPT5: - scanline = ScanLine; - hpos = PokeOpHSync - 68; - if (hpos < 0) - { - hpos += 228; - scanline--; - } - if (SampleINPTLatched(5, scanline, hpos)) - { - retval &= 0x7f; - } - else - { - retval |= 0x80; - } - break; - } - return (byte)(retval | (M.Mem.DataBusState & 0x3f)); - } - - byte DumpedInputPort(int resistance) - { - byte retval = 0; - - if (resistance == 0) - { - retval = 0x80; - } - else if (DumpEnabled || resistance == Int32.MaxValue) - { - retval = 0x00; - } - else - { - var chargeTime = 1.6 * resistance * 0.01e-6; - var needed = (ulong)(chargeTime * M.FrameBuffer.Scanlines * 228 * M.FrameHZ / 3); - if (M.CPU.Clock > DumpDisabledCycle + needed) - { - retval = 0x80; - } - } - return retval; - } - - #endregion - - #region TIA Poke - - void poke(ushort addr, byte data) - { - addr &= 0x3f; - - var endClock = Clock; - - // writes to the TIA may take a few extra CLKs to actually affect TIA state - // such a delay would seem to be applicable across all possible TIA writes - // without hardware to confirm conclusively, this is updated only as seemingly required - switch (addr) - { - case GRP0: - case GRP1: - // stem in the T in activision logo on older titles - endClock += 1; - break; - case PF0: - case PF1: - case PF2: - // +2 prevents minor notching in berzerk walls - // +4 prevents shield fragments floating in fuzz field in yars revenge, - // but creates minor artifact in chopper command - switch (PokeOpHSync & 3) - { - case 0: endClock += 4; break; - case 1: endClock += 3; break; - case 2: endClock += 2; break; - case 3: endClock += 5; break; - } - break; - } - - RenderFromStartClockTo(endClock); - - PokeOp[addr](addr, data); - } - - static void opNULL(ushort addr, byte data) - { - } - - void opVSYNC(ushort addr, byte data) - { - // Many games don't appear to supply 3 scanlines of - // VSYNC in accordance with the Atari documentation. - // Enduro turns on VSYNC, then turns it off twice. - // Centipede turns off VSYNC several times, in addition to normal usage. - // One of the Atari Bowling ROMs turns it off, but never turns it on. - // So, we always end the frame if VSYNC is turned on and then off. - // We also end the frame if VSYNC is turned off after scanline 258 to accomodate Bowling. - if ((data & 0x02) == 0) - { - if ((RegW[VSYNC] & 0x02) != 0 || ScanLine > 258) - { - EndOfFrame = true; - M.CPU.EmulatorPreemptRequest = true; - } - } - - RegW[VSYNC] = data; - } - - void opVBLANK(ushort addr, byte data) - { - if ((RegW[VBLANK] & 0x80) == 0) - { - // dump to ground is clear and will be set - // thus discharging all INPTx capacitors - if ((data & 0x80) != 0) - { - DumpEnabled = true; - } - } - else - { - // dump to ground is set and will be cleared - // thus starting all INPTx capacitors charging - if ((data & 0x80) == 0) - { - DumpEnabled = false; - DumpDisabledCycle = M.CPU.Clock; - } - } - RegW[VBLANK] = data; - vblankon = (data & 0x02) != 0; - } - - void opWSYNC(ushort addr, byte data) - { - // on scanline=44, tetris seems to occasionally not get a WSYNC in until 3 clk in on scanline=45 causing jitter - if (PokeOpHSync > 0) - { - // report the number of remaining system clocks on the scanline to delay the CPU - WSYNCDelayClocks = 228 - PokeOpHSync; - // request a CPU preemption to service the delay request (only if there is a delay necessary) - M.CPU.EmulatorPreemptRequest = true; - } - } - - void opRSYNC(ushort addr, byte data) - { - LogDebug("TIA RSYNC: frame={0} scanline={0} hsync={0}", M.FrameNumber, ScanLine, PokeOpHSync); - } - - void opNUSIZ0(ushort addr, byte data) - { - RegW[NUSIZ0] = (byte)(data & 0x37); - - M0size = (RegW[NUSIZ0] & 0x30) >> 4; - M0type = RegW[NUSIZ0] & 0x07; - P0type = M0type; - - P0suppress = 0; - } - - void opNUSIZ1(ushort addr, byte data) - { - RegW[NUSIZ1] = (byte)(data & 0x37); - - M1size = (RegW[NUSIZ1] & 0x30) >> 4; - M1type = RegW[NUSIZ1] & 0x07; - P1type = M1type; - - P1suppress = 0; - } - - void opCOLUBK(ushort addr, byte data) - { - colubk = data; - } - - void opCOLUPF(ushort addr, byte data) - { - colupf = data; - } - - void opCOLUP0(ushort addr, byte data) - { - colup0 = data; - } - - void opCOLUP1(ushort addr, byte data) - { - colup1 = data; - } - - void opCTRLPF(ushort addr, byte data) - { - RegW[CTRLPF] = data; - - BLsize = (data & 0x30) >> 4; - scoreon = (data & 0x02) != 0; - pfpriority = (data & 0x04) != 0; - } - - void SetEffGRP0() - { - var grp0 = RegW[VDELP0] != 0 ? OldGRP0 : RegW[GRP0]; - EffGRP0 = RegW[REFP0] != 0 ? TIATables.GRPReflect[grp0] : grp0; - } - - void SetEffGRP1() - { - var grp1 = RegW[VDELP1] != 0 ? OldGRP1 : RegW[GRP1]; - EffGRP1 = RegW[REFP1] != 0 ? TIATables.GRPReflect[grp1] : grp1; - } - - void Setblon() - { - blon = RegW[VDELBL] != 0 ? OldENABL : RegW[ENABL] != 0; - } - - void opREFP0(ushort addr, byte data) - { - RegW[REFP0] = (byte)(data & 0x08); - SetEffGRP0(); - } - - void opREFP1(ushort addr, byte data) - { - RegW[REFP1] = (byte)(data & 0x08); - SetEffGRP1(); - } - - void opPF(ushort addr, byte data) - { - RegW[addr] = data; - PF210 = (uint)((RegW[PF2] << 12) | (RegW[PF1] << 4) |((RegW[PF0] >> 4) & 0x0f)); - } - - void opRESP0(ushort addr, byte data) - { - if (PokeOpHSync < 68) - { - P0 = 0; - } - else if (HMoveLatch && PokeOpHSync >= 68 && PokeOpHSync < 76) - { - // this is an attempt to model observed behavior--may not be completely correct - // only three hsync values are really possible: - // 69: parkerbros actionman - // 72: activision grandprix - // 75: barnstorming, riverraid - P0 = -((PokeOpHSync - 68) >> 1); - } - else - { - P0 = -4; - } - P0 -= PokeOpHSyncDelta; - P0suppress = 1; - } - - void opRESP1(ushort addr, byte data) - { - if (PokeOpHSync < 68) - { - P1 = 0; - } - else if (HMoveLatch && PokeOpHSync >= 68 && PokeOpHSync < 76) - { - // this is an attempt to model observed behavior--may not be completely correct - // only three hsync values are really possible: - // 69: parkerbros actionman - // 72: parkerbros actionman - // 75: parkerbros actionman - P1 = -((PokeOpHSync - 68) >> 1); - } - else - { - P1 = -4; - } - P1 -= PokeOpHSyncDelta; - P1suppress = 1; - } - - void opRESM0(ushort addr, byte data) - { - // -2 to mirror M1 - M0 = PokeOpHSync < 68 ? -2 : -4; - M0 -= PokeOpHSyncDelta; - } - - void opRESM1(ushort addr, byte data) - { - // -2 cleans up edges on activision pitfall ii - M1 = PokeOpHSync < 68 ? -2 : -4; - M1 -= PokeOpHSyncDelta; - } - - void opRESBL(ushort addr, byte data) - { - // -2 cleans up edges on activision boxing - // -4 confirmed via activision choppercommand; used to clean up edges - BL = PokeOpHSync < 68 ? -2 : -4; - BL -= PokeOpHSyncDelta; - } - - void opAUD(ushort addr, byte data) - { - RegW[addr] = data; - TIASound.Update(addr, data); - } - - void opGRP0(ushort addr, byte data) - { - RegW[GRP0] = data; - OldGRP1 = RegW[GRP1]; - - SetEffGRP0(); - SetEffGRP1(); - } - - void opGRP1(ushort addr, byte data) - { - RegW[GRP1] = data; - OldGRP0 = RegW[GRP0]; - - OldENABL = RegW[ENABL] != 0; - - SetEffGRP0(); - SetEffGRP1(); - Setblon(); - } - - void opENAM0(ushort addr, byte data) - { - RegW[ENAM0] = (byte)(data & 0x02); - m0on = RegW[ENAM0] != 0 && RegW[RESMP0] == 0; - } - - void opENAM1(ushort addr, byte data) - { - RegW[ENAM1] = (byte)(data & 0x02); - m1on = RegW[ENAM1] != 0 && RegW[RESMP1] == 0; - } - - void opENABL(ushort addr, byte data) - { - RegW[ENABL] = (byte)(data & 0x02); - Setblon(); - } - - void SetHmr(int hmr, byte data) - { - // marshal via >>4 for compare convenience - RegW[hmr] = (byte)((data ^ 0x80) >> 4); - } - - void opHM(ushort addr, byte data) - { - SetHmr(addr, data); - } - - void opVDELP0(ushort addr, byte data) - { - RegW[VDELP0] = (byte)(data & 0x01); - SetEffGRP0(); - } - - void opVDELP1(ushort addr, byte data) - { - RegW[VDELP1] = (byte)(data & 0x01); - SetEffGRP1(); - } - - void opVDELBL(ushort addr, byte data) - { - RegW[VDELBL] = (byte)(data & 0x01); - Setblon(); - } - - void opRESMP0(ushort addr, byte data) - { - if (RegW[RESMP0] != 0 && (data & 0x02) == 0) - { - var middle = 4; - switch (RegW[NUSIZ0] & 0x07) - { - case 0x05: middle <<= 1; break; // double size - case 0x07: middle <<= 2; break; // quad size - } - M0 = P0 - middle; - } - RegW[RESMP0] = (byte)(data & 0x02); - m0on = RegW[ENAM0] != 0 && RegW[RESMP0] == 0; - } - - void opRESMP1(ushort addr, byte data) - { - if (RegW[RESMP1] != 0 && (data & 0x02) == 0) - { - var middle = 4; - switch (RegW[NUSIZ1] & 0x07) - { - case 0x05: middle <<= 1; break; // double size - case 0x07: middle <<= 2; break; // quad size - } - M1 = P1 - middle; - } - RegW[RESMP1] = (byte)(data & 0x02); - m1on = RegW[ENAM1] != 0 && RegW[RESMP1] == 0; - } - - void opHMOVE(ushort addr, byte data) - { - P0suppress = 0; - P1suppress = 0; - StartHMOVEClock = Clock + 3; - - // Activision Spiderfighter Cheat (Score and Logo) - // Delaying the start of the HMOVE here results in it completing on the next scanline (to have visible effect.) - // HMOVEing during the visible scanline probably has extra consequences, - // however, it seems not many carts try to do this. - if (PokeOpHSync == 201) StartHMOVEClock++; // any increment >0 works - } - - void opHMCLR(ushort addr, byte data) - { - SetHmr(HMP0, 0); - SetHmr(HMP1, 0); - SetHmr(HMM0, 0); - SetHmr(HMM1, 0); - SetHmr(HMBL, 0); - } - - void opCXCLR(ushort addr, byte data) - { - Collisions = 0; - } - - void BuildPokeOpTable() - { - PokeOp = new PokeOpTyp[64]; - for (var i = 0; i < PokeOp.Length; i++) - { - PokeOp[i] = opNULL; - } - PokeOp[VSYNC] = opVSYNC; - PokeOp[VBLANK] = opVBLANK; - PokeOp[WSYNC] = opWSYNC; - PokeOp[RSYNC] = opRSYNC; - PokeOp[NUSIZ0] = opNUSIZ0; - PokeOp[NUSIZ1] = opNUSIZ1; - PokeOp[COLUP0] = opCOLUP0; - PokeOp[COLUP1] = opCOLUP1; - PokeOp[COLUPF] = opCOLUPF; - PokeOp[COLUBK] = opCOLUBK; - PokeOp[CTRLPF] = opCTRLPF; - PokeOp[REFP0] = opREFP0; - PokeOp[REFP1] = opREFP1; - PokeOp[PF0] = opPF; - PokeOp[PF1] = opPF; - PokeOp[PF2] = opPF; - PokeOp[RESP0] = opRESP0; - PokeOp[RESP1] = opRESP1; - PokeOp[RESM0] = opRESM0; - PokeOp[RESM1] = opRESM1; - PokeOp[RESBL] = opRESBL; - PokeOp[AUDC0] = opAUD; - PokeOp[AUDC1] = opAUD; - PokeOp[AUDF0] = opAUD; - PokeOp[AUDF1] = opAUD; - PokeOp[AUDV0] = opAUD; - PokeOp[AUDV1] = opAUD; - PokeOp[GRP0] = opGRP0; - PokeOp[GRP1] = opGRP1; - PokeOp[ENAM0] = opENAM0; - PokeOp[ENAM1] = opENAM1; - PokeOp[ENABL] = opENABL; - PokeOp[HMP0] = opHM; - PokeOp[HMP1] = opHM; - PokeOp[HMM0] = opHM; - PokeOp[HMM1] = opHM; - PokeOp[HMBL] = opHM; - PokeOp[VDELP0] = opVDELP0; - PokeOp[VDELP1] = opVDELP1; - PokeOp[VDELBL] = opVDELBL; - PokeOp[RESMP0] = opRESMP0; - PokeOp[RESMP1] = opRESMP1; - PokeOp[HMOVE] = opHMOVE; - PokeOp[HMCLR] = opHMCLR; - PokeOp[CXCLR] = opCXCLR; - } - - #endregion - - #region Input Helpers - - int SampleINPT(int inpt) - { - var mi = M.InputState; - - switch (inpt <= 1 ? mi.LeftControllerJack : mi.RightControllerJack) - { - case Controller.Paddles: - // playerno = inpt - return mi.SampleCapturedOhmState(inpt & 3); - case Controller.ProLineJoystick: - // playerno = inpt/2 - switch (inpt & 3) - { - case 0: return mi.SampleCapturedControllerActionState(0, ControllerAction.Trigger) ? 0 : Int32.MaxValue; - case 1: return mi.SampleCapturedControllerActionState(0, ControllerAction.Trigger2) ? 0 : Int32.MaxValue; - case 2: return mi.SampleCapturedControllerActionState(1, ControllerAction.Trigger) ? 0 : Int32.MaxValue; - case 3: return mi.SampleCapturedControllerActionState(1, ControllerAction.Trigger2) ? 0 : Int32.MaxValue; - } - break; - case Controller.BoosterGrip: - // playerno = inpt - return mi.SampleCapturedControllerActionState(inpt & 3, ControllerAction.Trigger2) ? 0 : Int32.MaxValue; - case Controller.Keypad: - return SampleKeypadStateDumped(inpt & 3); - } - return int.MaxValue; - } - - bool SampleINPTLatched(int inpt, int scanline, int hpos) - { - var mi = M.InputState; - var playerNo = inpt - 4; - - switch (playerNo == 0 ? mi.LeftControllerJack : mi.RightControllerJack) - { - case Controller.Joystick: - case Controller.ProLineJoystick: - case Controller.Driving: - case Controller.BoosterGrip: - return mi.SampleCapturedControllerActionState(playerNo, ControllerAction.Trigger); - case Controller.Keypad: - return SampleKeypadStateLatched(playerNo); - case Controller.Lightgun: - int sampledScanline, sampledHpos; - mi.SampleCapturedLightGunPosition(playerNo, out sampledScanline, out sampledHpos); - return ((scanline - 4) >= sampledScanline && (hpos - 23) >= sampledHpos); - } - return false; - } - - bool SampleKeypadStateLatched(int deviceno) - { - ControllerAction action; - - if ((M.PIA.WrittenPortA & 0x01) == 0) - { - action = ControllerAction.Keypad3; - } - else if ((M.PIA.WrittenPortA & 0x02) == 0) - { - action = ControllerAction.Keypad6; - } - else if ((M.PIA.WrittenPortA & 0x04) == 0) - { - action = ControllerAction.Keypad9; - } - else if ((M.PIA.WrittenPortA & 0x08) == 0) - { - action = ControllerAction.KeypadP; - } - else - { - return false; - } - - return M.InputState.SampleCapturedControllerActionState(deviceno, action); - } - - int SampleKeypadStateDumped(int inpt) - { - ControllerAction action; - - if ((M.PIA.WrittenPortA & 0x01) == 0) - { - action = (inpt & 1) == 0 ? ControllerAction.Keypad1 : ControllerAction.Keypad2; - } - else if ((M.PIA.WrittenPortA & 0x02) == 0) - { - action = (inpt & 1) == 0 ? ControllerAction.Keypad4 : ControllerAction.Keypad5; - } - else if ((M.PIA.WrittenPortA & 0x04) == 0) - { - action = (inpt & 1) == 0 ? ControllerAction.Keypad7 : ControllerAction.Keypad8; - } - else if ((M.PIA.WrittenPortA & 0x08) == 0) - { - action = (inpt & 1) == 0 ? ControllerAction.KeypadA : ControllerAction.Keypad0; - } - else - { - return Int32.MaxValue; - } - - // playerno = inpt/2 - return M.InputState.SampleCapturedControllerActionState(inpt >> 1, action) ? Int32.MaxValue : 0; - } - - #endregion - - #region Serialization Members - - public TIA(DeserializationContext input, MachineBase m) : this() - { - if (input == null) - throw new ArgumentNullException("input"); - if (m == null) - throw new ArgumentNullException("m"); - - M = m; - TIASound = input.ReadTIASound(M, CPU_TICKS_PER_AUDIO_SAMPLE); - - input.CheckVersion(2); - RegW = input.ReadExpectedBytes(0x40); - HSync = input.ReadInt32(); - HMoveCounter = input.ReadInt32(); - ScanLine = input.ReadInt32(); - FrameBufferIndex = input.ReadInt32(); - //FrameBufferElement = input.ReadBufferElement(); - StartHMOVEClock = input.ReadUInt64(); - HMoveLatch = input.ReadBoolean(); - StartClock = input.ReadUInt64(); - P0 = input.ReadInt32(); - P0mmr = input.ReadBoolean(); - EffGRP0 = input.ReadByte(); - OldGRP0 = input.ReadByte(); - P0type = input.ReadInt32(); - P0suppress = input.ReadInt32(); - P1 = input.ReadInt32(); - P1mmr = input.ReadBoolean(); - EffGRP1 = input.ReadByte(); - OldGRP1 = input.ReadByte(); - P1type = input.ReadInt32(); - P1suppress = input.ReadInt32(); - M0 = input.ReadInt32(); - M0mmr = input.ReadBoolean(); - M0type = input.ReadInt32(); - M0size = input.ReadInt32(); - m0on = input.ReadBoolean(); - M1 = input.ReadInt32(); - M1mmr = input.ReadBoolean(); - M1type = input.ReadInt32(); - M1size = input.ReadInt32(); - m1on = input.ReadBoolean(); - BL = input.ReadInt32(); - BLmmr = input.ReadBoolean(); - OldENABL = input.ReadBoolean(); - BLsize = input.ReadInt32(); - blon = input.ReadBoolean(); - PF210 = input.ReadUInt32(); - PFReflectionState = input.ReadInt32(); - colubk = input.ReadByte(); - colupf = input.ReadByte(); - colup0 = input.ReadByte(); - colup1 = input.ReadByte(); - vblankon = input.ReadBoolean(); - scoreon = input.ReadBoolean(); - pfpriority = input.ReadBoolean(); - DumpEnabled = input.ReadBoolean(); - DumpDisabledCycle = input.ReadUInt64(); - Collisions = (TIACxPairFlags)input.ReadInt32(); - WSYNCDelayClocks = input.ReadInt32(); - EndOfFrame = input.ReadBoolean(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.Write(TIASound); - - output.WriteVersion(2); - output.Write(RegW); - output.Write(HSync); - output.Write(HMoveCounter); - output.Write(ScanLine); - output.Write(FrameBufferIndex); - //output.Write(FrameBufferElement); - output.Write(StartHMOVEClock); - output.Write(HMoveLatch); - output.Write(StartClock); - output.Write(P0); - output.Write(P0mmr); - output.Write(EffGRP0); - output.Write(OldGRP0); - output.Write(P0type); - output.Write(P0suppress); - output.Write(P1); - output.Write(P1mmr); - output.Write(EffGRP1); - output.Write(OldGRP1); - output.Write(P1type); - output.Write(P1suppress); - output.Write(M0); - output.Write(M0mmr); - output.Write(M0type); - output.Write(M0size); - output.Write(m0on); - output.Write(M1); - output.Write(M1mmr); - output.Write(M1type); - output.Write(M1size); - output.Write(m1on); - output.Write(BL); - output.Write(BLmmr); - output.Write(OldENABL); - output.Write(BLsize); - output.Write(blon); - output.Write(PF210); - output.Write(PFReflectionState); - output.Write(colubk); - output.Write(colupf); - output.Write(colup0); - output.Write(colup1); - output.Write(vblankon); - output.Write(scoreon); - output.Write(pfpriority); - output.Write(DumpEnabled); - output.Write(DumpDisabledCycle); - output.Write((int)Collisions); - output.Write(WSYNCDelayClocks); - output.Write(EndOfFrame); - } - - #endregion - - #region Helpers - - void Log(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - [System.Diagnostics.Conditional("DEBUG")] - void LogDebug(string format, params object[] args) - { - if (M == null || M.Logger == null) - return; - M.Logger.WriteLine(format, args); - } - - #endregion - } -} \ No newline at end of file diff --git a/EMU7800/Core/TIASound.cs b/EMU7800/Core/TIASound.cs deleted file mode 100644 index 1ee9b3ea4b..0000000000 --- a/EMU7800/Core/TIASound.cs +++ /dev/null @@ -1,361 +0,0 @@ -/* - * TIASound.cs - * - * Sound emulation for the 2600. Based upon TIASound © 1997 by Ron Fries. - * - * Copyright © 2003, 2004 Mike Murphy - * - */ - -/*****************************************************************************/ -/* */ -/* License Information and Copyright Notice */ -/* ======================================== */ -/* */ -/* TiaSound is Copyright(c) 1997 by Ron Fries */ -/* */ -/* This library is free software; you can redistribute it and/or modify it */ -/* under the terms of version 2 of the GNU Library General Public License */ -/* as published by the Free Software Foundation. */ -/* */ -/* This library is distributed in the hope that it will be useful, but */ -/* WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library */ -/* General Public License for more details. */ -/* To obtain a copy of the GNU Library General Public License, write to the */ -/* Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* */ -/* Any permitted reproduction of these routines, in whole or in part, must */ -/* bear this legend. */ -/* */ -/*****************************************************************************/ - -using System; - -namespace EMU7800.Core -{ - public sealed class TIASound - { - #region Constants and Tables - - // Clock Source Clock Modifier Source Pattern - const int - SET_TO_1 = 0x00, // 0 0 0 0 3.58 Mhz/114 none (pure) none - //POLY4 = 0x01, // 0 0 0 1 3.58 Mhz/114 none (pure) 4-bit poly - //DIV31_POLY4 = 0x02, // 0 0 1 0 3.58 Mhz/114 divide by 31 4-bit poly - //POLY5_POLY4 = 0x03, // 0 0 1 1 3.58 Mhz/114 5-bit poly 4-bit poly - //PURE = 0x04, // 0 1 0 0 3.58 Mhz/114 none (pure) pure (~Q) - //PURE2 = 0x05, // 0 1 0 1 3.58 Mhz/114 none (pure) pure (~Q) - //DIV31_PURE = 0x06, // 0 1 1 0 3.58 Mhz/114 divide by 31 pure (~Q) - //POLY5_2 = 0x07, // 0 1 1 1 3.58 Mhz/114 5-bit poly pure (~Q) - POLY9 = 0x08; // 1 0 0 0 3.58 Mhz/114 none (pure) 9-bit poly - //POLY5 = 0x09, // 1 0 0 1 3.58 Mhz/114 none (pure) 5-bit poly - //DIV31_POLY5 = 0x0a, // 1 0 1 0 3.58 Mhz/114 divide by 31 5-bit poly - //POLY5_POLY5 = 0x0b, // 1 0 1 1 3.58 Mhz/114 5-bit poly 5-bit poly - //DIV3_PURE = 0x0c, // 1 1 0 0 1.19 Mhz/114 none (pure) pure (~Q) - //DIV3_PURE2 = 0x0d, // 1 1 0 1 1.19 Mhz/114 none (pure) pure (~Q) - //DIV93_PURE = 0x0e, // 1 1 1 0 1.19 Mhz/114 divide by 31 pure (~Q) - //DIV3_POLY5 = 0x0f; // 1 1 1 1 1.19 Mhz/114 5-bit poly pure (~Q) - - const int - AUDC0 = 0x15, // audio control 0 (D3-0) - AUDC1 = 0x16, // audio control 1 (D4-0) - AUDF0 = 0x17, // audio frequency 0 (D4-0) - AUDF1 = 0x18, // audio frequency 1 (D3-0) - AUDV0 = 0x19, // audio volume 0 (D3-0) - AUDV1 = 0x1a; // audio volume 1 (D3-0) - - // The 4bit and 5bit patterns are the identical ones used in the tia chip. - readonly byte[] Bit4 = new byte[] { 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0 }; // 2^4 - 1 = 15 - readonly byte[] Bit5 = new byte[] { 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1 }; // 2^5 - 1 = 31 - - // [Ron] treated the 'Div by 31' counter as another polynomial because of - // the way it operates. It does not have a 50% duty cycle, but instead - // has a 13:18 ratio (of course, 13+18 = 31). This could also be - // implemented by using counters. - readonly byte[] Div31 = new byte[] { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - // Rather than have a table with 511 entries, I use a random number - readonly byte[] Bit9 = new byte[511]; // 2^9 - 1 = 511 - - readonly int[] P4 = new int[2]; // Position counter for the 4-bit POLY array - readonly int[] P5 = new int[2]; // Position counter for the 5-bit POLY array - readonly int[] P9 = new int[2]; // Position counter for the 9-bit POLY array - - readonly int[] DivByNCounter = new int[2]; // Divide by n counter, one for each channel - readonly int[] DivByNMaximum = new int[2]; // Divide by n maximum, one for each channel - - readonly int _cpuClocksPerSample; - - #endregion - - #region Object State - - readonly MachineBase M; - - // The TIA Sound registers - readonly byte[] AUDC = new byte[2]; - readonly byte[] AUDF = new byte[2]; - readonly byte[] AUDV = new byte[2]; - - // The last output volume for each channel - readonly byte[] OutputVol = new byte[2]; - - // Used to determine how much sound to render - ulong LastUpdateCPUClock; - - int BufferIndex; - - #endregion - - #region Public Members - - public void Reset() - { - for (var chan = 0; chan < 2; chan++) - { - OutputVol[chan] = 0; - DivByNCounter[chan] = 0; - DivByNMaximum[chan] = 0; - AUDC[chan] = 0; - AUDF[chan] = 0; - AUDV[chan] = 0; - P4[chan] = 0; - P5[chan] = 0; - P9[chan] = 0; - } - } - - public void StartFrame() - { - LastUpdateCPUClock = M.CPU.Clock; - BufferIndex = 0; - } - - public void EndFrame() - { - RenderSamples(M.FrameBuffer.SoundBufferByteLength - BufferIndex); - } - - public void Update(ushort addr, byte data) - { - if (M.CPU.Clock > LastUpdateCPUClock) - { - var updCPUClocks = (int)(M.CPU.Clock - LastUpdateCPUClock); - var samples = updCPUClocks / _cpuClocksPerSample; - RenderSamples(samples); - LastUpdateCPUClock += (ulong)(samples * _cpuClocksPerSample); - } - - byte chan; - - switch (addr) - { - case AUDC0: - AUDC[0] = (byte)(data & 0x0f); - chan = 0; - break; - case AUDC1: - AUDC[1] = (byte)(data & 0x0f); - chan = 1; - break; - case AUDF0: - AUDF[0] = (byte)(data & 0x1f); - chan = 0; - break; - case AUDF1: - AUDF[1] = (byte)(data & 0x1f); - chan = 1; - break; - case AUDV0: - AUDV[0] = (byte)(data & 0x0f); - chan = 0; - break; - case AUDV1: - AUDV[1] = (byte)(data & 0x0f); - chan = 1; - break; - default: - return; - } - - byte new_divn_max; - - if (AUDC[chan] == SET_TO_1) - { - // indicate the clock is zero so no process will occur - new_divn_max = 0; - // and set the output to the selected volume - OutputVol[chan] = AUDV[chan]; - } - else - { - // otherwise calculate the 'divide by N' value - new_divn_max = (byte)(AUDF[chan] + 1); - // if bits D2 & D3 are set, then multiply the 'div by n' count by 3 - if ((AUDC[chan] & 0x0c) == 0x0c) - { - new_divn_max *= 3; - } - } - - // only reset those channels that have changed - if (new_divn_max != DivByNMaximum[chan]) - { - DivByNMaximum[chan] = new_divn_max; - - // if the channel is now volume only or was volume only... - if (DivByNCounter[chan] == 0 || new_divn_max == 0) - { - // reset the counter (otherwise let it complete the previous) - DivByNCounter[chan] = new_divn_max; - } - } - } - - #endregion - - #region Constructors - - private TIASound() - { - var r = new Random(); - r.NextBytes(Bit9); - for (var i = 0; i < Bit9.Length; i++) - { - Bit9[i] &= 0x01; - } - } - - public TIASound(MachineBase m, int cpuClocksPerSample) : this() - { - if (m == null) - throw new ArgumentNullException("m"); - if (cpuClocksPerSample <= 0) - throw new ArgumentException("cpuClocksPerSample must be positive."); - - M = m; - _cpuClocksPerSample = cpuClocksPerSample; - } - - #endregion - - #region Serialization Members - - public TIASound(DeserializationContext input, MachineBase m, int cpuClocksPerSample) : this(m, cpuClocksPerSample) - { - if (input == null) - throw new ArgumentNullException("input"); - - input.CheckVersion(1); - Bit9 = input.ReadExpectedBytes(511); - P4 = input.ReadIntegers(2); - P5 = input.ReadIntegers(2); - P9 = input.ReadIntegers(2); - DivByNCounter = input.ReadIntegers(2); - DivByNMaximum = input.ReadIntegers(2); - AUDC = input.ReadExpectedBytes(2); - AUDF = input.ReadExpectedBytes(2); - AUDV = input.ReadExpectedBytes(2); - OutputVol = input.ReadExpectedBytes(2); - LastUpdateCPUClock = input.ReadUInt64(); - BufferIndex = input.ReadInt32(); - } - - public void GetObjectData(SerializationContext output) - { - if (output == null) - throw new ArgumentNullException("output"); - - output.WriteVersion(1); - output.Write(Bit9); - output.Write(P4); - output.Write(P5); - output.Write(P9); - output.Write(DivByNCounter); - output.Write(DivByNMaximum); - output.Write(AUDC); - output.Write(AUDF); - output.Write(AUDV); - output.Write(OutputVol); - output.Write(LastUpdateCPUClock); - output.Write(BufferIndex); - } - - #endregion - - #region Helpers - - void RenderSamples(int count) - { - for (; BufferIndex < M.FrameBuffer.SoundBufferByteLength && count-- > 0; BufferIndex++) - { - if (DivByNCounter[0] > 1) - { - DivByNCounter[0]--; - } - else if (DivByNCounter[0] == 1) - { - DivByNCounter[0] = DivByNMaximum[0]; - ProcessChannel(0); - } - if (DivByNCounter[1] > 1) - { - DivByNCounter[1]--; - } - else if (DivByNCounter[1] == 1) - { - DivByNCounter[1] = DivByNMaximum[1]; - ProcessChannel(1); - } - - M.FrameBuffer.SoundBuffer[BufferIndex] += (byte)(OutputVol[0] + OutputVol[1]); - } - } - - void ProcessChannel(int chan) - { - // the P5 counter has multiple uses, so we inc it here - if (++P5[chan] >= 31) - { // POLY5 size: 2^5 - 1 = 31 - P5[chan] = 0; - } - - // check clock modifier for clock tick - if ((AUDC[chan] & 0x02) == 0 || - ((AUDC[chan] & 0x01) == 0 && Div31[P5[chan]] == 1) || - ((AUDC[chan] & 0x01) == 1 && Bit5[P5[chan]] == 1)) - { - if ((AUDC[chan] & 0x04) != 0) - { // pure modified clock selected - OutputVol[chan] = (OutputVol[chan] != 0) ? (byte)0 : AUDV[chan]; - } - else if ((AUDC[chan] & 0x08) != 0) - { // check for poly5/poly9 - if (AUDC[chan] == POLY9) - { // check for poly9 - if (++P9[chan] >= 511) - { // poly9 size: 2^9 - 1 = 511 - P9[chan] = 0; - } - OutputVol[chan] = (Bit9[P9[chan]] == 1) ? AUDV[chan] : (byte)0; - } - else - { // must be poly5 - OutputVol[chan] = (Bit5[P5[chan]] == 1) ? AUDV[chan] : (byte)0; - } - } - else - { // poly4 is the only remaining possibility - if (++P4[chan] >= 15) - { // POLY4 size: 2^4 - 1 = 15 - P4[chan] = 0; - } - OutputVol[chan] = (Bit4[P4[chan]] == 1) ? AUDV[chan] : (byte)0; - } - } - } - - #endregion - } -} diff --git a/EMU7800/Core/TIATables.cs b/EMU7800/Core/TIATables.cs deleted file mode 100644 index 4a38a2b482..0000000000 --- a/EMU7800/Core/TIATables.cs +++ /dev/null @@ -1,424 +0,0 @@ -/* - * TIATables.cs - * - * Mask tables for the Television Interface Adaptor class. All derived from - * Bradford Mott's Stella code. - * - * Copyright © 2003, 2004 Mike Murphy - * - */ -namespace EMU7800.Core -{ - public static class TIATables - { - public static readonly TIACxPairFlags[] CollisionMask = BuildCollisionMaskTable(); - public static readonly uint[][] PFMask = BuildPFMaskTable(); - public static readonly bool[][] BLMask = BuildBLMaskTable(); - public static readonly bool[][][] MxMask = BuildMxMaskTable(); - public static readonly byte[][][] PxMask = BuildPxMaskTable(); - public static readonly byte[] GRPReflect = BuildGRPReflectTable(); - - public static readonly int[] NTSCPalette = - { - 0x000000, 0x000000, 0x4a4a4a, 0x4a4a4a, - 0x6f6f6f, 0x6f6f6f, 0x8e8e8e, 0x8e8e8e, - 0xaaaaaa, 0xaaaaaa, 0xc0c0c0, 0xc0c0c0, - 0xd6d6d6, 0xd6d6d6, 0xececec, 0xececec, - - 0x484800, 0x484800, 0x69690f, 0x69690f, - 0x86861d, 0x86861d, 0xa2a22a, 0xa2a22a, - 0xbbbb35, 0xbbbb35, 0xd2d240, 0xd2d240, - 0xe8e84a, 0xe8e84a, 0xfcfc54, 0xfcfc54, - - 0x7c2c00, 0x7c2c00, 0x904811, 0x904811, - 0xa26221, 0xa26221, 0xb47a30, 0xb47a30, - 0xc3903d, 0xc3903d, 0xd2a44a, 0xd2a44a, - 0xdfb755, 0xdfb755, 0xecc860, 0xecc860, - - 0x901c00, 0x901c00, 0xa33915, 0xa33915, - 0xb55328, 0xb55328, 0xc66c3a, 0xc66c3a, - 0xd5824a, 0xd5824a, 0xe39759, 0xe39759, - 0xf0aa67, 0xf0aa67, 0xfcbc74, 0xfcbc74, - - 0x940000, 0x940000, 0xa71a1a, 0xa71a1a, - 0xb83232, 0xb83232, 0xc84848, 0xc84848, - 0xd65c5c, 0xd65c5c, 0xe46f6f, 0xe46f6f, - 0xf08080, 0xf08080, 0xfc9090, 0xfc9090, - - 0x840064, 0x840064, 0x97197a, 0x97197a, - 0xa8308f, 0xa8308f, 0xb846a2, 0xb846a2, - 0xc659b3, 0xc659b3, 0xd46cc3, 0xd46cc3, - 0xe07cd2, 0xe07cd2, 0xec8ce0, 0xec8ce0, - - 0x500084, 0x500084, 0x68199a, 0x68199a, - 0x7d30ad, 0x7d30ad, 0x9246c0, 0x9246c0, - 0xa459d0, 0xa459d0, 0xb56ce0, 0xb56ce0, - 0xc57cee, 0xc57cee, 0xd48cfc, 0xd48cfc, - - 0x140090, 0x140090, 0x331aa3, 0x331aa3, - 0x4e32b5, 0x4e32b5, 0x6848c6, 0x6848c6, - 0x7f5cd5, 0x7f5cd5, 0x956fe3, 0x956fe3, - 0xa980f0, 0xa980f0, 0xbc90fc, 0xbc90fc, - - 0x000094, 0x000094, 0x181aa7, 0x181aa7, - 0x2d32b8, 0x2d32b8, 0x4248c8, 0x4248c8, - 0x545cd6, 0x545cd6, 0x656fe4, 0x656fe4, - 0x7580f0, 0x7580f0, 0x8490fc, 0x8490fc, - - 0x001c88, 0x001c88, 0x183b9d, 0x183b9d, - 0x2d57b0, 0x2d57b0, 0x4272c2, 0x4272c2, - 0x548ad2, 0x548ad2, 0x65a0e1, 0x65a0e1, - 0x75b5ef, 0x75b5ef, 0x84c8fc, 0x84c8fc, - - 0x003064, 0x003064, 0x185080, 0x185080, - 0x2d6d98, 0x2d6d98, 0x4288b0, 0x4288b0, - 0x54a0c5, 0x54a0c5, 0x65b7d9, 0x65b7d9, - 0x75cceb, 0x75cceb, 0x84e0fc, 0x84e0fc, - - 0x004030, 0x004030, 0x18624e, 0x18624e, - 0x2d8169, 0x2d8169, 0x429e82, 0x429e82, - 0x54b899, 0x54b899, 0x65d1ae, 0x65d1ae, - 0x75e7c2, 0x75e7c2, 0x84fcd4, 0x84fcd4, - - 0x004400, 0x004400, 0x1a661a, 0x1a661a, - 0x328432, 0x328432, 0x48a048, 0x48a048, - 0x5cba5c, 0x5cba5c, 0x6fd26f, 0x6fd26f, - 0x80e880, 0x80e880, 0x90fc90, 0x90fc90, - - 0x143c00, 0x143c00, 0x355f18, 0x355f18, - 0x527e2d, 0x527e2d, 0x6e9c42, 0x6e9c42, - 0x87b754, 0x87b754, 0x9ed065, 0x9ed065, - 0xb4e775, 0xb4e775, 0xc8fc84, 0xc8fc84, - - 0x303800, 0x303800, 0x505916, 0x505916, - 0x6d762b, 0x6d762b, 0x88923e, 0x88923e, - 0xa0ab4f, 0xa0ab4f, 0xb7c25f, 0xb7c25f, - 0xccd86e, 0xccd86e, 0xe0ec7c, 0xe0ec7c, - - 0x482c00, 0x482c00, 0x694d14, 0x694d14, - 0x866a26, 0x866a26, 0xa28638, 0xa28638, - 0xbb9f47, 0xbb9f47, 0xd2b656, 0xd2b656, - 0xe8cc63, 0xe8cc63, 0xfce070, 0xfce070 - }; - - public static readonly int[] PALPalette = - { - 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, - 0x525252, 0x525252, 0x767676, 0x767676, - 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, - 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec, - - 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, - 0x525252, 0x525252, 0x767676, 0x767676, - 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, - 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec, - - 0x805800, 0x000000, 0x96711a, 0x2b2b2b, - 0xab8732, 0x525252, 0xbe9c48, 0x767676, - 0xcfaf5c, 0x979797, 0xdfc06f, 0xb6b6b6, - 0xeed180, 0xd2d2d2, 0xfce090, 0xececec, - - 0x445c00, 0x000000, 0x5e791a, 0x2b2b2b, - 0x769332, 0x525252, 0x8cac48, 0x767676, - 0xa0c25c, 0x979797, 0xb3d76f, 0xb6b6b6, - 0xc4ea80, 0xd2d2d2, 0xd4fc90, 0xececec, - - 0x703400, 0x000000, 0x89511a, 0x2b2b2b, - 0xa06b32, 0x525252, 0xb68448, 0x767676, - 0xc99a5c, 0x979797, 0xdcaf6f, 0xb6b6b6, - 0xecc280, 0xd2d2d2, 0xfcd490, 0xececec, - - 0x006414, 0x000000, 0x1a8035, 0x2b2b2b, - 0x329852, 0x525252, 0x48b06e, 0x767676, - 0x5cc587, 0x979797, 0x6fd99e, 0xb6b6b6, - 0x80ebb4, 0xd2d2d2, 0x90fcc8, 0xececec, - - 0x700014, 0x000000, 0x891a35, 0x2b2b2b, - 0xa03252, 0x525252, 0xb6486e, 0x767676, - 0xc95c87, 0x979797, 0xdc6f9e, 0xb6b6b6, - 0xec80b4, 0xd2d2d2, 0xfc90c8, 0xececec, - - 0x005c5c, 0x000000, 0x1a7676, 0x2b2b2b, - 0x328e8e, 0x525252, 0x48a4a4, 0x767676, - 0x5cb8b8, 0x979797, 0x6fcbcb, 0xb6b6b6, - 0x80dcdc, 0xd2d2d2, 0x90ecec, 0xececec, - - 0x70005c, 0x000000, 0x841a74, 0x2b2b2b, - 0x963289, 0x525252, 0xa8489e, 0x767676, - 0xb75cb0, 0x979797, 0xc66fc1, 0xb6b6b6, - 0xd380d1, 0xd2d2d2, 0xe090e0, 0xececec, - - 0x003c70, 0x000000, 0x195a89, 0x2b2b2b, - 0x2f75a0, 0x525252, 0x448eb6, 0x767676, - 0x57a5c9, 0x979797, 0x68badc, 0xb6b6b6, - 0x79ceec, 0xd2d2d2, 0x88e0fc, 0xececec, - - 0x580070, 0x000000, 0x6e1a89, 0x2b2b2b, - 0x8332a0, 0x525252, 0x9648b6, 0x767676, - 0xa75cc9, 0x979797, 0xb76fdc, 0xb6b6b6, - 0xc680ec, 0xd2d2d2, 0xd490fc, 0xececec, - - 0x002070, 0x000000, 0x193f89, 0x2b2b2b, - 0x2f5aa0, 0x525252, 0x4474b6, 0x767676, - 0x578bc9, 0x979797, 0x68a1dc, 0xb6b6b6, - 0x79b5ec, 0xd2d2d2, 0x88c8fc, 0xececec, - - 0x340080, 0x000000, 0x4a1a96, 0x2b2b2b, - 0x5f32ab, 0x525252, 0x7248be, 0x767676, - 0x835ccf, 0x979797, 0x936fdf, 0xb6b6b6, - 0xa280ee, 0xd2d2d2, 0xb090fc, 0xececec, - - 0x000088, 0x000000, 0x1a1a9d, 0x2b2b2b, - 0x3232b0, 0x525252, 0x4848c2, 0x767676, - 0x5c5cd2, 0x979797, 0x6f6fe1, 0xb6b6b6, - 0x8080ef, 0xd2d2d2, 0x9090fc, 0xececec, - - 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, - 0x525252, 0x525252, 0x767676, 0x767676, - 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, - 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec, - - 0x000000, 0x000000, 0x2b2b2b, 0x2b2b2b, - 0x525252, 0x525252, 0x767676, 0x767676, - 0x979797, 0x979797, 0xb6b6b6, 0xb6b6b6, - 0xd2d2d2, 0xd2d2d2, 0xececec, 0xececec - }; - - static uint[][] BuildPFMaskTable() - { - var tabl = new uint[2][]; - tabl[0] = new uint[160]; - tabl[1] = new uint[160]; - - for (var i = 0; i < 20; i++) - { - uint mask = 0; - if (i < 4) - { - mask = (uint)(1 << i); - } - else if (i < 12) - { - mask = (uint)(1 << (11 + 4 - i)); - } - else if (i < 20) - { - mask = (uint)(1 << i); - } - for (var j = 0; j < 4; j++) - { - // for non-reflected mode - tabl[0][4 * i + j] = mask; - tabl[0][80 + 4 * i + j] = mask; - - // for reflected mode - tabl[1][4 * i + j] = mask; - tabl[1][159 - 4 * i - j] = mask; - } - } - return tabl; - } - - static bool[][] BuildBLMaskTable() - { - var tabl = new bool[4][]; - for (var size = 0; size < 4; size++) - { - tabl[size] = new bool[160]; - for (var i = 0; i < 160; i++) - { - tabl[size][i] = false; - } - for (var i = 0; i < (1 << size); i++) - { - tabl[size][i] = true; - } - } - return tabl; - } - - static bool[][][] BuildMxMaskTable() - { - var tabl = new bool[4][][]; - for (var i = 0; i < 4; i++) - { - tabl[i] = new bool[8][]; - for (var j = 0; j < 8; j++) - { - tabl[i][j] = new bool[160]; - for (var k = 0; k < 160; k++) - { - tabl[i][j][k] = false; - } - } - } - - for (var size = 0; size < 4; size++) - { - for (var i = 0; i < (1 << size); i++) - { - tabl[size][0][i] = true; - - tabl[size][1][i] = true; - tabl[size][1][i + 16] = true; - - tabl[size][2][i] = true; - tabl[size][2][i + 32] = true; - - tabl[size][3][i] = true; - tabl[size][3][i + 16] = true; - tabl[size][3][i + 32] = true; - - tabl[size][4][i] = true; - tabl[size][4][i + 64] = true; - - tabl[size][5][i] = true; - - tabl[size][6][i] = true; - tabl[size][6][i + 32] = true; - tabl[size][6][i + 64] = true; - - tabl[size][7][i] = true; - } - } - return tabl; - } - - static byte[][][] BuildPxMaskTable() - { - // [suppress mode, nusiz, pixel] - // suppress=1: suppress on - // suppress=0: suppress off - var tabl = new byte[2][][]; //2 8 160 - tabl[0] = new byte[8][]; - tabl[1] = new byte[8][]; - for (var nusiz = 0; nusiz < 8; nusiz++) - { - tabl[0][nusiz] = new byte[160]; - tabl[1][nusiz] = new byte[160]; - for (var hpos = 0; hpos < 160; hpos++) - { - // nusiz: - // 0: one copy - // 1: two copies-close - // 2: two copies-med - // 3: three copies-close - // 4: two copies-wide - // 5: double size player - // 6: 3 copies medium - // 7: quad sized player - tabl[0][nusiz][hpos] = tabl[1][nusiz][hpos] = 0; - if (nusiz >= 0 && nusiz <= 4 || nusiz == 6) - { - if (hpos >= 0 && hpos < 8) - { - tabl[0][nusiz][hpos] = (byte)(1 << (7 - hpos)); - } - } - if (nusiz == 1 || nusiz == 3) - { - if (hpos >= 16 && hpos < 24) - { - tabl[0][nusiz][hpos] = (byte)(1 << (23 - hpos)); - tabl[1][nusiz][hpos] = (byte)(1 << (23 - hpos)); - } - } - if (nusiz == 2 || nusiz == 3 || nusiz == 6) - { - if (hpos >= 32 && hpos < 40) - { - tabl[0][nusiz][hpos] = (byte)(1 << (39 - hpos)); - tabl[1][nusiz][hpos] = (byte)(1 << (39 - hpos)); - } - } - if (nusiz == 4 || nusiz == 6) - { - if (hpos >= 64 && hpos < 72) - { - tabl[0][nusiz][hpos] = (byte)(1 << (71 - hpos)); - tabl[1][nusiz][hpos] = (byte)(1 << (71 - hpos)); - } - } - if (nusiz == 5) - { - if (hpos >= 0 && hpos < 16) - { - tabl[0][nusiz][hpos] = (byte)(1 << ((15 - hpos) >> 1)); - } - } - if (nusiz == 7) - { - if (hpos >= 0 && hpos < 32) - { - tabl[0][nusiz][hpos] = (byte)(1 << ((31 - hpos) >> 2)); - } - } - } - - var shift = nusiz == 5 || nusiz == 7 ? 2 : 1; - while (shift-- > 0) - { - for (var i = 159; i > 0; i--) - { - tabl[0][nusiz][i] = tabl[0][nusiz][i - 1]; - tabl[1][nusiz][i] = tabl[1][nusiz][i - 1]; - } - tabl[0][nusiz][0] = tabl[1][nusiz][0] = 0; - } - } - return tabl; - } - - static byte[] BuildGRPReflectTable() - { - var tabl = new byte[256]; - - for (var i = 0; i < 256; i++) - { - var s = (byte)i; - var r = (byte)0; - for (var j = 0; j < 8; j++) - { - r <<= 1; - r |= (byte)(s & 1); - s >>= 1; - } - tabl[i] = r; - } - return tabl; - } - - static bool tstCx(int i, TIACxFlags cxf1, TIACxFlags cxf2) - { - var f1 = (int)cxf1; - var f2 = (int)cxf2; - return ((i & f1) != 0) && ((i & f2) != 0); - } - - static TIACxPairFlags[] BuildCollisionMaskTable() - { - var tabl = new TIACxPairFlags[64]; - - for (var i = 0; i < 64; i++) - { - tabl[i] = 0; - if (tstCx(i, TIACxFlags.M0, TIACxFlags.P1)) { tabl[i] |= TIACxPairFlags.M0P1; } - if (tstCx(i, TIACxFlags.M0, TIACxFlags.P0)) { tabl[i] |= TIACxPairFlags.M0P0; } - if (tstCx(i, TIACxFlags.M1, TIACxFlags.P0)) { tabl[i] |= TIACxPairFlags.M1P0; } - if (tstCx(i, TIACxFlags.M1, TIACxFlags.P1)) { tabl[i] |= TIACxPairFlags.M1P1; } - if (tstCx(i, TIACxFlags.P0, TIACxFlags.PF)) { tabl[i] |= TIACxPairFlags.P0PF; } - if (tstCx(i, TIACxFlags.P0, TIACxFlags.BL)) { tabl[i] |= TIACxPairFlags.P0BL; } - if (tstCx(i, TIACxFlags.P1, TIACxFlags.PF)) { tabl[i] |= TIACxPairFlags.P1PF; } - if (tstCx(i, TIACxFlags.P1, TIACxFlags.BL)) { tabl[i] |= TIACxPairFlags.P1BL; } - if (tstCx(i, TIACxFlags.M0, TIACxFlags.PF)) { tabl[i] |= TIACxPairFlags.M0PF; } - if (tstCx(i, TIACxFlags.M0, TIACxFlags.BL)) { tabl[i] |= TIACxPairFlags.M0BL; } - if (tstCx(i, TIACxFlags.M1, TIACxFlags.PF)) { tabl[i] |= TIACxPairFlags.M1PF; } - if (tstCx(i, TIACxFlags.M1, TIACxFlags.BL)) { tabl[i] |= TIACxPairFlags.M1BL; } - if (tstCx(i, TIACxFlags.BL, TIACxFlags.PF)) { tabl[i] |= TIACxPairFlags.BLPF; } - if (tstCx(i, TIACxFlags.P0, TIACxFlags.P1)) { tabl[i] |= TIACxPairFlags.P0P1; } - if (tstCx(i, TIACxFlags.M0, TIACxFlags.M1)) { tabl[i] |= TIACxPairFlags.M0M1; } - } - return tabl; - } - } -} diff --git a/EMU7800/EMU7800.csproj b/EMU7800/EMU7800.csproj deleted file mode 100644 index 7c542a3a3c..0000000000 --- a/EMU7800/EMU7800.csproj +++ /dev/null @@ -1,127 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {E01193DF-F104-4B95-9D1B-FAD830F6F620} - Library - Properties - EMU7800 - EMU7800 - v4.0 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - copy /y $(TargetDir)$(TargetFileName) $(ProjectDir)..\references\$(TargetFileName) - - - - \ No newline at end of file diff --git a/EMU7800/EMU7800.sln b/EMU7800/EMU7800.sln deleted file mode 100644 index f9ab26fb2e..0000000000 --- a/EMU7800/EMU7800.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EMU7800", "EMU7800.csproj", "{E01193DF-F104-4B95-9D1B-FAD830F6F620}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E01193DF-F104-4B95-9D1B-FAD830F6F620}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E01193DF-F104-4B95-9D1B-FAD830F6F620}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E01193DF-F104-4B95-9D1B-FAD830F6F620}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E01193DF-F104-4B95-9D1B-FAD830F6F620}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/EMU7800/Properties/AssemblyInfo.cs b/EMU7800/Properties/AssemblyInfo.cs deleted file mode 100644 index 9fc9e7c874..0000000000 --- a/EMU7800/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("EMU7800")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("EMU7800")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("b1f45280-2ae9-468c-8db8-4663fe6f2300")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/EMU7800/Win/GameProgram.cs b/EMU7800/Win/GameProgram.cs deleted file mode 100644 index be65e225a0..0000000000 --- a/EMU7800/Win/GameProgram.cs +++ /dev/null @@ -1,76 +0,0 @@ -/* - * GameProgram.cs - * - * Represents attribute data associated with ROMs - * - * Copyright 2003, 2004, 2010 © Mike Murphy - * - */ - -/* - * unlike EMU7800 Core stuff, this has been hacked around a bit - */ - -using System.Text; -using EMU7800.Core; - -namespace EMU7800.Win -{ - public class GameProgram - { - public string MD5 { get; set; } - public string Title { get; set; } - public string Manufacturer { get; set; } - public string Author { get; set; } - public string Year { get; set; } - public string ModelNo { get; set; } - public string Rarity { get; set; } - public CartType CartType { get; set; } - public MachineType MachineType { get; set; } - public Controller LController { get; set; } - public Controller RController { get; set; } - public string HelpUri { get; set; } - - public string DiscoveredRomFullName { get; set; } - - public override string ToString() - { - var s = new StringBuilder("GameSettings:\n"); - s.AppendFormat(" MD5: {0}\n", MD5); - s.AppendFormat(" Title: {0}\n", Title); - s.AppendFormat(" Manufacturer: {0}\n", Manufacturer); - s.AppendFormat(" Author: {0}\n", Author); - s.AppendFormat(" Year: {0}\n", Year); - s.AppendFormat(" ModelNo: {0}\n", ModelNo); - s.AppendFormat(" Rarity: {0}\n", Rarity); - s.AppendFormat(" CartType: {0}\n", CartType); - s.AppendFormat(" MachineType: {0}\n", MachineType); - s.AppendFormat(" LController: {0}\n", LController); - s.AppendFormat(" RController: {0}\n", RController); - s.AppendFormat(" HelpUri: {0}", HelpUri); - if (DiscoveredRomFullName != null) s.AppendFormat("\n Discovered Rom Filename: {0}", DiscoveredRomFullName); - return s.ToString(); - } - - public GameProgram(string md5) - { - MD5 = md5; - } - - /// - /// not in db, so guess - /// - /// - /// - public static GameProgram GetCompleteGuess(string md5) - { - GameProgram ret = new GameProgram(md5); - ret.Title = "UNKNOWN"; - //ret.CartType = CartType.A7848; // will be guessed for us - ret.MachineType = MachineType.A7800NTSC; - ret.LController = Controller.Joystick; - ret.RController = Controller.Joystick; - return ret; - } - } -} \ No newline at end of file diff --git a/EMU7800/Win/GameProgramLibrary.cs b/EMU7800/Win/GameProgramLibrary.cs deleted file mode 100644 index b3b9ac0d1a..0000000000 --- a/EMU7800/Win/GameProgramLibrary.cs +++ /dev/null @@ -1,384 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Text; -using EMU7800.Core; - -/* - * unlike EMU7800 Core stuff, this has been hacked around significantly - */ - -namespace EMU7800.Win -{ - public class GameProgramLibrary : Dictionary - { - #region Fields - - const string - BIOS78_NTSC_MD5 = "0763f1ffb006ddbe32e52d497ee848ae", - BIOS78_NTSC_ALTERNATE_MD5 = "b32526ea179dc9ab9b2e5f8a2662b298", - BIOS78_PAL_MD5 = "397bb566584be7b9764e7a68974c4263", - HSC78_MD5 = "c8a73288ab97226c52602204ab894286"; - /* - readonly IDictionary _misc7800DiscoveredRoms = new Dictionary(); - */ - // these enums are used for matching column names in the .csv file - enum Column - { - None, - MD5, - Title, - Manufacturer, - Author, - Year, - ModelNo, - Rarity, - CartType, - MachineType, - LController, - RController, - HelpUri - }; - - //const string RomPropertiesFileName = "ROMProperties.csv"; - - static readonly Dictionary _columnPositions = new Dictionary - { - { Column.MD5, -1}, - { Column.Title, -1}, - { Column.Manufacturer, -1}, - { Column.Author, -1 }, - { Column.Year, - 1}, - { Column.ModelNo, -1}, - { Column.Rarity, -1}, - { Column.CartType, -1}, - { Column.MachineType, -1}, - { Column.LController, -1}, - { Column.RController, -1}, - { Column.HelpUri, -1}, - }; - - //readonly RomFileAccessor _romFileAccessor = new RomFileAccessor(); - readonly MD5CryptoServiceProvider _cryptoProvider = new MD5CryptoServiceProvider(); - readonly StringBuilder _sb = new StringBuilder(); - //readonly ILogger _logger; - - #endregion - - public static GameProgramLibrary EMU7800DB = null; - - #region Constructors - - private GameProgramLibrary() - { - } - - public GameProgramLibrary(TextReader r)//, ILogger logger) - { - //if (logger == null) - // throw new ArgumentNullException("logger"); - - //_logger = logger; - - //var settings = new GlobalSettings(logger); - //var fn = Path.Combine(settings.BaseDirectory, RomPropertiesFileName); - - Clear(); - //StreamReader r = null; - try - { - //r = new StreamReader(fn); - InitializeColumnPos(r.ReadLine()); - - while (true) - { - var line = r.ReadLine(); - if (line == null) - break; - var gp = CreateGameSettingsFromLine(line); - if (gp == null) - continue; - if (ContainsKey(gp.MD5)) - Console.WriteLine("7800DB: Duplicate MD5 key found: {0}", gp.MD5); else Add(gp.MD5, gp); - } - r.Close(); - } - catch (Exception ex) - { - //if (Util.IsCriticalException(ex)) - throw; - //_logger.WriteLine(ex); - } - finally - { - if (r != null) - r.Dispose(); - } - - Console.WriteLine("7800DB: {0} entries loaded.", Count); - } - - #endregion - - #region Game Program Accessors - - public GameProgram TryRecognizeRom(byte[] bytes) - { - //if (string.IsNullOrWhiteSpace(fullName)) - // throw new ArgumentException("fullName"); - - //var bytes = _romFileAccessor.GetRomBytes(fullName); - if (bytes == null) - return null; - - var md5 = ComputeMD5Digest(bytes); - if (string.IsNullOrWhiteSpace(md5)) - return null; - - var gp = GetGameProgramFromMd5(md5); - if (gp == null) - gp = GameProgram.GetCompleteGuess(md5); - //gp.DiscoveredRomFullName = fullName; - if (gp.CartType == CartType.None) - { - switch (gp.MachineType) - { - case MachineType.A2600NTSC: - case MachineType.A2600PAL: - switch (bytes.Length) - { - case 2048: gp.CartType = CartType.A2K; break; - case 4096: gp.CartType = CartType.A4K; break; - case 8192: gp.CartType = CartType.A8K; break; - case 16384: gp.CartType = CartType.A16K; break; - } - break; - case MachineType.A7800NTSC: - case MachineType.A7800PAL: - switch (bytes.Length) - { - case 8192: gp.CartType = CartType.A7808; break; - case 16384: gp.CartType = CartType.A7816; break; - case 32768: gp.CartType = CartType.A7832; break; - case 49152: gp.CartType = CartType.A7848; break; - } - break; - } - } - return gp; - /* - if (md5.Equals(HSC78_MD5, StringComparison.OrdinalIgnoreCase)) - { - if (!_misc7800DiscoveredRoms.ContainsKey(md5)) - _misc7800DiscoveredRoms.Add(md5, fullName); - _logger.WriteLine("Found 7800 Highscore Cart: {0}", fullName); - return null; - } - if (md5.Equals(BIOS78_NTSC_MD5, StringComparison.OrdinalIgnoreCase)) - { - if (!_misc7800DiscoveredRoms.ContainsKey(md5)) - _misc7800DiscoveredRoms.Add(md5, fullName); - _logger.WriteLine("Found 7800 NTSC BIOS: {0}", fullName); - return null; - } - if (md5.Equals(BIOS78_NTSC_ALTERNATE_MD5, StringComparison.OrdinalIgnoreCase)) - { - if (!_misc7800DiscoveredRoms.ContainsKey(md5)) - _misc7800DiscoveredRoms.Add(md5, fullName); - _logger.WriteLine("Found incorrect but widely used 7800 NTSC BIOS: {0}", fullName); - return null; - } - if (md5.Equals(BIOS78_PAL_MD5, StringComparison.OrdinalIgnoreCase)) - { - if (!_misc7800DiscoveredRoms.ContainsKey(md5)) - _misc7800DiscoveredRoms.Add(md5, fullName); - _logger.WriteLine("Found 7800 PAL BIOS: {0}", fullName); - return null; - } - */ - } - - /* - public GameProgram GetGameProgramFromFullName(string fullName) - { - var bytes = _romFileAccessor.GetRomBytes(fullName); - if (bytes == null) - throw new ArgumentException("File not readable: {0}", fullName); - var md5 = ComputeMD5Digest(bytes); - return !string.IsNullOrWhiteSpace(md5) ? GetGameProgramFromMd5(md5) : null; - } - */ - public GameProgram GetGameProgramFromMd5(string md5) - { - if (string.IsNullOrWhiteSpace(md5)) - throw new ArgumentNullException("md5"); - GameProgram gp; - return TryGetValue(md5, out gp) ? gp : null; - } - /* - public byte[] GetRomBytes(string fullName) - { - return _romFileAccessor.GetRomBytes(fullName); - } - - public byte[] Get78HighScoreCartBytes() - { - string fullName; - if (!_misc7800DiscoveredRoms.TryGetValue(HSC78_MD5, out fullName)) - return null; - return _romFileAccessor.GetRomBytes(fullName); - } - - public byte[] Get78BiosBytes(MachineType machineType) - { - string fullName = null; - switch (machineType) - { - case MachineType.A7800NTSC: - if (!_misc7800DiscoveredRoms.TryGetValue(BIOS78_NTSC_MD5, out fullName)) - _misc7800DiscoveredRoms.TryGetValue(BIOS78_NTSC_ALTERNATE_MD5, out fullName); - break; - case MachineType.A7800PAL: - _misc7800DiscoveredRoms.TryGetValue(BIOS78_PAL_MD5, out fullName); - break; - } - if (string.IsNullOrWhiteSpace(fullName)) - return null; - return _romFileAccessor.GetRomBytes(fullName); - }*/ - - #endregion - - #region Game Progam Related Utilities - /* - public string ComputeMD5Digest(string fullName) - { - var bytes = _romFileAccessor.GetRomBytes(fullName); - if (bytes == null) - throw new ArgumentException("File not readable: {0}", fullName); - return ComputeMD5Digest(bytes); - } - */ - #endregion - - #region Helpers - - static void InitializeColumnPos(string line) - { - var colno = 0; - var columnNames = line.Split(','); - - foreach (var columnName in columnNames) - { - var col = ToColumn(columnName); - if (col != Column.None) - _columnPositions[col] = colno; - colno++; - } - - if (_columnPositions[Column.MD5] < 0) - throw new ApplicationException("ROMProperties.csv: Required column missing: MD5"); - if (_columnPositions[Column.CartType] < 0) - throw new ApplicationException("ROMProperties.csv: Required column missing: CartType"); - if (_columnPositions[Column.MachineType] < 0) - throw new ApplicationException("ROMProperties.csv: Required column missing: MachineType"); - if (_columnPositions[Column.LController] < 0) - throw new ApplicationException("ROMProperties.csv: Required column missing: LController"); - if (_columnPositions[Column.RController] < 0) - throw new ApplicationException("ROMProperties.csv: Required column missing: RController"); - } - - static GameProgram CreateGameSettingsFromLine(string line) - { - var row = new string[13]; - var linesplit = line.Split(','); - for (var i = 0; i < row.Length && i < linesplit.Length; i++) - row[i] = linesplit[i]; - - var md5 = row[_columnPositions[Column.MD5]]; - var gp = new GameProgram(md5) - { - Title = _columnPositions[Column.Title] >= 0 ? row[_columnPositions[Column.Title]] : string.Empty, - Manufacturer = _columnPositions[Column.Manufacturer] >= 0 ? row[_columnPositions[Column.Manufacturer]] : string.Empty, - Author = _columnPositions[Column.Author] >= 0 ? row[_columnPositions[Column.Author]] : string.Empty, - Year = _columnPositions[Column.Year] >= 0 ? row[_columnPositions[Column.Year]] : string.Empty, - ModelNo = _columnPositions[Column.ModelNo] >= 0 ? row[_columnPositions[Column.ModelNo]] : string.Empty, - Rarity = _columnPositions[Column.Rarity] >= 0 ? row[_columnPositions[Column.Rarity]] : string.Empty, - CartType = ToCartType(row[_columnPositions[Column.CartType]]), - MachineType = ToMachineType(row[_columnPositions[Column.MachineType]]) - }; - - gp.LController = ToController(row[_columnPositions[Column.LController]]); - gp.RController = ToController(row[_columnPositions[Column.RController]]); - - if (gp.LController == Controller.None) - gp.LController = GetDefaultController(gp.MachineType); - if (gp.RController == Controller.None) - gp.RController = GetDefaultController(gp.MachineType); - - if (_columnPositions[Column.HelpUri] < row.Length) - { - string helpUri = row[_columnPositions[Column.HelpUri]]; - if (helpUri != null) helpUri = helpUri.Trim(); - if (helpUri != null && !helpUri.Length.Equals(0)) - gp.HelpUri = helpUri; - } - - return gp; - } - - static Controller GetDefaultController(MachineType machineType) - { - switch (machineType) - { - case MachineType.A7800NTSC: - case MachineType.A7800PAL: - return Controller.ProLineJoystick; - default: - return Controller.Joystick; - } - } - - static Column ToColumn(string columnName) - { - Column result; - return Enum.TryParse(columnName, true, out result) ? result : Column.None; - } - - static CartType ToCartType(string cartType) - { - CartType result; - return Enum.TryParse(cartType, true, out result) ? result : CartType.None; - } - - static MachineType ToMachineType(string machineType) - { - MachineType result; - return Enum.TryParse(machineType, true, out result) ? result : MachineType.None; - } - - static Controller ToController(string controller) - { - Controller result; - return Enum.TryParse(controller, true, out result) ? result : Controller.None; - } - - string ComputeMD5Digest(byte[] bytes) - { - return (bytes != null) ? StringifyMD5(_cryptoProvider.ComputeHash(bytes)) : null; - } - - string StringifyMD5(byte[] bytes) - { - if (bytes == null || bytes.Length < 16) - return string.Empty; - _sb.Length = 0; - for (var i = 0; i < 16; i++) - _sb.AppendFormat("{0:x2}", bytes[i]); - return _sb.ToString(); - } - - #endregion - } -} diff --git a/References/EMU7800.dll b/References/EMU7800.dll deleted file mode 100644 index c920cdeb79..0000000000 Binary files a/References/EMU7800.dll and /dev/null differ diff --git a/libgambatte/include/gambatte.h b/libgambatte/include/gambatte.h index 2265ffa6d9..08b3575a6a 100644 --- a/libgambatte/include/gambatte.h +++ b/libgambatte/include/gambatte.h @@ -110,6 +110,7 @@ public: void setTraceCallback(void (*callback)(void *)); void setScanlineCallback(void (*callback)(), int sl); void setRTCCallback(std::uint32_t (*callback)()); + void setLinkCallback(void (*callback)()); /** Returns true if the currently loaded ROM image is treated as having CGB support. */ bool isCgb() const; diff --git a/libgambatte/src/cinterface.cpp b/libgambatte/src/cinterface.cpp index 6549307c85..376b8c68f5 100644 --- a/libgambatte/src/cinterface.cpp +++ b/libgambatte/src/cinterface.cpp @@ -109,6 +109,11 @@ GBEXPORT void gambatte_setrtccallback(GB *g, unsigned int (*callback)()) g->setRTCCallback(callback); } +GBEXPORT void gambatte_setlinkcallback(GB *g, void (*callback)()) +{ + g->setLinkCallback(callback); +} + GBEXPORT int gambatte_iscgb(GB *g) { return g->isCgb(); diff --git a/libgambatte/src/cpu.cpp b/libgambatte/src/cpu.cpp index 3f6619eb78..88665f1989 100644 --- a/libgambatte/src/cpu.cpp +++ b/libgambatte/src/cpu.cpp @@ -298,6 +298,7 @@ void CPU::loadState(const SaveState &state) { HF2 = u8; \ ZF = CF = A + HF2; \ A = ZF & 0xFF; \ + calcHF(HF1, HF2); \ } while (0) //adc a,r (4 cycles): @@ -308,6 +309,7 @@ void CPU::loadState(const SaveState &state) { HF2 = (CF & 0x100) | (u8); \ ZF = CF = (CF >> 8 & 1) + (u8) + A; \ A = ZF & 0xFF; \ + calcHF(HF1, HF2); \ } while (0) //sub a,r (4 cycles): @@ -319,6 +321,7 @@ void CPU::loadState(const SaveState &state) { ZF = CF = A - HF2; \ A = ZF & 0xFF; \ HF2 |= 0x400; \ + calcHF(HF1, HF2); \ } while (0) //sbc a,r (4 cycles): @@ -329,6 +332,7 @@ void CPU::loadState(const SaveState &state) { HF2 = 0x400 | (CF & 0x100) | (u8); \ ZF = CF = A - ((CF >> 8) & 1) - (u8); \ A = ZF & 0xFF; \ + calcHF(HF1, HF2); \ } while (0) //and a,r (4 cycles): @@ -367,6 +371,7 @@ void CPU::loadState(const SaveState &state) { HF2 = u8; \ ZF = CF = A - HF2; \ HF2 |= 0x400; \ + calcHF(HF1, HF2); \ } while (0) //inc r (4 cycles): @@ -375,6 +380,7 @@ void CPU::loadState(const SaveState &state) { HF2 = (r) | 0x800; \ ZF = (r) + 1; \ (r) = ZF & 0xFF; \ + calcHF(HF1, HF2); \ } while (0) //dec r (4 cycles): @@ -383,6 +389,7 @@ void CPU::loadState(const SaveState &state) { HF2 = (r) | 0xC00; \ ZF = (r) - 1; \ (r) = ZF & 0xFF; \ + calcHF(HF1, HF2); \ } while (0) //16-BIT ARITHMETIC @@ -405,6 +412,7 @@ void CPU::loadState(const SaveState &state) { CF = H + (CF >> 8) + (rh); \ H = CF & 0xFF; \ cycleCounter += 4; \ + calcHF(HF1, HF2); \ } while (0) //inc rr (8 cycles): @@ -436,6 +444,7 @@ void CPU::loadState(const SaveState &state) { ZF = 1; \ cycleCounter += 4; \ (sumout) = sp_plus_n_var_sum & 0xFFFF; \ + calcHF(HF1, HF2); \ } while (0) //JUMPS: @@ -877,6 +886,7 @@ void CPU::process(const unsigned long cycles) { ZF = HF2 + 1; WRITE(addr, ZF & 0xFF); HF2 |= 0x800; + calcHF(HF1, HF2); } break; @@ -890,6 +900,7 @@ void CPU::process(const unsigned long cycles) { ZF = HF2 - 1; WRITE(addr, ZF & 0xFF); HF2 |= 0xC00; + calcHF(HF1, HF2); } break; @@ -932,6 +943,7 @@ void CPU::process(const unsigned long cycles) { CF += H; H = CF & 0xFF; cycleCounter += 4; + calcHF(HF1, HF2); break; //ldd a,(hl) (8 cycles): @@ -1428,6 +1440,7 @@ void CPU::process(const unsigned long cycles) { case 0xBF: CF = ZF = 0; HF2 = 0x400; + calcHF(HF1, HF2); \ break; //ret nz (20;8 cycles): diff --git a/libgambatte/src/cpu.h b/libgambatte/src/cpu.h index 1310257e86..2c9e4547a4 100644 --- a/libgambatte/src/cpu.h +++ b/libgambatte/src/cpu.h @@ -96,6 +96,10 @@ public: memory.setRTCCallback(callback); } + void setLinkCallback(void (*callback)()) { + memory.setLinkCallback(callback); + } + void reset_bios(int setting) { memory.bios_reset(setting); } diff --git a/libgambatte/src/gambatte.cpp b/libgambatte/src/gambatte.cpp index c3843a862c..ee064c0743 100644 --- a/libgambatte/src/gambatte.cpp +++ b/libgambatte/src/gambatte.cpp @@ -141,6 +141,10 @@ void GB::setRTCCallback(std::uint32_t (*callback)()) { p_->cpu.setRTCCallback(callback); } +void GB::setLinkCallback(void(*callback)()) { + p_->cpu.setLinkCallback(callback); +} + int GB::load(const char *romfiledata, unsigned romfilelength, const char *biosfiledata, unsigned biosfilelength, const std::uint32_t now, const unsigned flags) { //if (p_->cpu.loaded()) // p_->cpu.saveSavedata(); diff --git a/libgambatte/src/memory.cpp b/libgambatte/src/memory.cpp index 79d9820e16..548e6705d2 100644 --- a/libgambatte/src/memory.cpp +++ b/libgambatte/src/memory.cpp @@ -29,6 +29,7 @@ Memory::Memory(const Interrupter &interrupter_in) writeCallback(0), execCallback(0), cdCallback(0), + linkCallback(0), getInput(0), divLastUpdate(0), lastOamDmaUpdate(DISABLED_TIME), @@ -123,6 +124,8 @@ void Memory::updateSerial(const unsigned long cc) { if (intreq.eventTime(SERIAL) <= cc) { linkClockTrigger = true; intreq.setEventTime(DISABLED_TIME); + if (linkCallback) + linkCallback(); } } } diff --git a/libgambatte/src/memory.h b/libgambatte/src/memory.h index 78a89a0ee4..3bfe8675c0 100644 --- a/libgambatte/src/memory.h +++ b/libgambatte/src/memory.h @@ -39,6 +39,7 @@ class Memory { void (*writeCallback)(unsigned); void (*execCallback)(unsigned); CDCallback cdCallback; + void (*linkCallback)(); unsigned (*getInput)(); unsigned long divLastUpdate; @@ -275,6 +276,10 @@ public: cart.setRTCCallback(callback); } + void setLinkCallback(void (*callback)()) { + this->linkCallback = callback; + } + void setEndtime(unsigned long cc, unsigned long inc); void setSoundBuffer(uint_least32_t *const buf) { sound.setBuffer(buf); } diff --git a/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c b/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c index c9b7e8ef81..e93b90600e 100644 --- a/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c +++ b/libmupen64plus/mupen64plus-core/src/r4300/pure_interp.c @@ -60,6 +60,7 @@ static void prefetch(void); interp_PC.addr += 4; \ delay_slot=1; \ prefetch(); \ + TRACECB(); \ PC->ops(); \ update_count(); \ delay_slot=0; \ diff --git a/libmupen64plus/mupen64plus-core/src/r4300/r4300.c b/libmupen64plus/mupen64plus-core/src/r4300/r4300.c index f881ce0e0d..832829ec87 100644 --- a/libmupen64plus/mupen64plus-core/src/r4300/r4300.c +++ b/libmupen64plus/mupen64plus-core/src/r4300/r4300.c @@ -94,6 +94,7 @@ int rounding_mode = 0x33F, trunc_mode = 0xF3F, round_mode = 0x33F, PC++; \ delay_slot=1; \ UPDATE_DEBUGGER(); \ + TRACECB(); \ PC->ops(); \ update_count(); \ delay_slot=0; \ @@ -126,6 +127,7 @@ int rounding_mode = 0x33F, trunc_mode = 0xF3F, round_mode = 0x33F, PC++; \ delay_slot=1; \ UPDATE_DEBUGGER(); \ + TRACECB(); \ PC->ops(); \ update_count(); \ delay_slot=0; \ diff --git a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln index 7ef3faea38..ba5b475069 100644 --- a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln +++ b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.sln @@ -6,13 +6,19 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 + Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.ActiveCfg = Debug|Win32 - {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.Build.0 = Debug|Win32 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.ActiveCfg = Debug|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.Build.0 = Debug|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|x64.ActiveCfg = Debug|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|x64.Build.0 = Debug|x64 {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.ActiveCfg = Release|Win32 {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.Build.0 = Release|Win32 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|x64.ActiveCfg = Release|x64 + {A4D13408-A794-4199-8FC7-4A9A32505005}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj index 35d3025ae6..26e5fdb29a 100644 --- a/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj +++ b/libmupen64plus/mupen64plus-video-glide64mk2/projects/msvc10/mupen64plus-video-glide64mk2.vcxproj @@ -5,10 +5,18 @@ Debug Win32 + + Debug + x64 + Release Win32 + + Release + x64 + {A4D13408-A794-4199-8FC7-4A9A32505005} @@ -23,34 +31,64 @@ true v100 + + DynamicLibrary + false + MultiByte + true + v100 + DynamicLibrary false MultiByte v100 + + DynamicLibrary + false + MultiByte + v100 + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 $(SolutionDir)..\..\..\..\output\dll\ + $(SolutionDir)..\..\..\..\output\dll\ $(Configuration)\ + $(Configuration)\ true + true $(SolutionDir)..\..\..\..\output\dll\ + $(SolutionDir)..\..\..\..\output\dll\ $(Configuration)\ + $(Configuration)\ false + false true + true F:\Code\Third Party\boost;$(IncludePath) + F:\Code\Third Party\boost;$(IncludePath) F:\Code\Third Party\boost\stage\lib;$(LibraryPath) + F:\Code\Third Party\boost\stage\lib;$(LibraryPath) @@ -98,6 +136,50 @@ .\Debug/n64Glide.bsc + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/n64Glide.tlb + + + + + Disabled + ..\..\..\mupen64plus-win32-deps\boost-1.57.0\;..\..\..\mupen64plus-core\src\api;..\..\src\Glide64;..\..\src\Glide64\inc;..\..\src\GlideHQ;..\..\src\GlideHQ\tc-1.1+;..\..\src\Glitch64;..\..\src\Glitch64\inc;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\include;%(AdditionalIncludeDirectories) + _DEBUG;NO_ASM;_GLIBCXX_HAVE_BROKEN_VSWPRINTF;NO_FILTER_THREAD;_VARIADIC_MAX=10;_CRT_SECURE_NO_WARNINGS;__MSC__;WIN32;%(PreprocessorDefinitions) + Async + EnableFastChecks + MultiThreadedDebugDLL + .\Debug/n64Glide.pch + .\Debug/ + .\Debug/ + .\Debug/ + Level3 + true + ProgramDatabase + true + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + SDL.lib;zlib.lib;libpng16.lib;opengl32.lib;winmm.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ..\..\..\deps\libs;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\lib\x64;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\lib\x64;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\lib\x64;%(AdditionalLibraryDirectories) + false + true + $(TargetDir)$(TargetName).pdb + .\Debug/Glide64.lib + + + true + .\Debug/n64Glide.bsc + + NDEBUG;%(PreprocessorDefinitions) @@ -157,122 +239,220 @@ copy ..\..\data\* "$(OutDir)" + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/n64Glide.tlb + + + + + MaxSpeed + OnlyExplicitInline + true + Speed + false + ..\..\..\mupen64plus-win32-deps\boost-1.57.0\;..\..\..\mupen64plus-core\src\api;..\..\src\Glide64;..\..\src\Glide64\inc;..\..\src\GlideHQ;..\..\src\GlideHQ\tc-1.1+;..\..\src\Glitch64;..\..\src\Glitch64\inc;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\include;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\include;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\include;%(AdditionalIncludeDirectories) + NO_ASM;_GLIBCXX_HAVE_BROKEN_VSWPRINTF;NO_FILTER_THREAD;_VARIADIC_MAX=10;_CRT_SECURE_NO_WARNINGS;__MSC__;WIN32;__VISUALC__;%(PreprocessorDefinitions) + true + Async + MultiThreadedDLL + true + NotSet + .\Release/n64Glide.pch + .\Release/ + .\Release/ + .\Release/ + Level3 + true + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + SDL.lib;zlib.lib;libpng16.lib;opengl32.lib;winmm.lib;comctl32.lib;rpcrt4.lib;wsock32.lib;%(AdditionalDependencies) + $(OutDir)$(TargetName)$(TargetExt) + true + ..\..\..\deps\libs;..\..\..\mupen64plus-win32-deps\libpng-1.6.18\lib\x64;..\..\..\mupen64plus-win32-deps\zlib-1.2.8\lib\x64;..\..\..\mupen64plus-win32-deps\SDL-1.2.15\lib\x64;%(AdditionalLibraryDirectories) + $(TargetDir)$(TargetName).pdb + + + Windows + true + /pdbaltpath:%_PDB% %(AdditionalOptions) + + + true + .\Release/n64Glide.bsc + + + true + + + Copying shared data and libraries to build directory... + copy ..\..\data\* "$(OutDir)" + + false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false false + false .\Release/%(Filename)1.obj + .\Release/%(Filename)1.obj $(IntDir)%(Filename)1.xdc + $(IntDir)%(Filename)1.xdc false + false false + false diff --git a/output/dll/libdarm.dll b/output/dll/libdarm.dll new file mode 100644 index 0000000000..6a16a2bc5f Binary files /dev/null and b/output/dll/libdarm.dll differ diff --git a/output/dll/libgambatte.dll b/output/dll/libgambatte.dll index 369d16266d..4bf168c395 100644 Binary files a/output/dll/libgambatte.dll and b/output/dll/libgambatte.dll differ diff --git a/output/dll/mupen64plus-video-glide64mk2.dll b/output/dll/mupen64plus-video-glide64mk2.dll index da44f01514..36989cb4d3 100644 Binary files a/output/dll/mupen64plus-video-glide64mk2.dll and b/output/dll/mupen64plus-video-glide64mk2.dll differ diff --git a/output/dll/mupen64plus.dll b/output/dll/mupen64plus.dll index d4f49ceb97..a7c7facbda 100644 Binary files a/output/dll/mupen64plus.dll and b/output/dll/mupen64plus.dll differ diff --git a/output/dll/octoshock.dll b/output/dll/octoshock.dll index 292d2536eb..3e80c9454e 100644 Binary files a/output/dll/octoshock.dll and b/output/dll/octoshock.dll differ diff --git a/output/dll/sameboy.wbx.gz b/output/dll/sameboy.wbx.gz index 10f48206a4..9233cc62d7 100644 Binary files a/output/dll/sameboy.wbx.gz and b/output/dll/sameboy.wbx.gz differ diff --git a/output/dll/ss.wbx.gz b/output/dll/ss.wbx.gz index 6b6cf90539..a298b11861 100644 Binary files a/output/dll/ss.wbx.gz and b/output/dll/ss.wbx.gz differ diff --git a/psx/octoshock/psx/input/memcard.cpp b/psx/octoshock/psx/input/memcard.cpp index 814e68d117..b98fa9de58 100644 --- a/psx/octoshock/psx/input/memcard.cpp +++ b/psx/octoshock/psx/input/memcard.cpp @@ -193,7 +193,9 @@ void InputDevice_Memcard::SyncState(bool isReader, EW::NewState *ns) //HOWEVER - we clear the dirty flag. that way, a user wont accidentally `clobber` his savestates when loading a state. //instead, the state will only be dirtied when the game actually modifies the contents NSS(card_data); - dirty_count = 0; + + if(isReader) + dirty_count = 0; } // //int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name) diff --git a/waterbox/emulibc/waterboxcore.h b/waterbox/emulibc/waterboxcore.h index 8ac891d120..4dc8741469 100644 --- a/waterbox/emulibc/waterboxcore.h +++ b/waterbox/emulibc/waterboxcore.h @@ -21,7 +21,7 @@ typedef struct void* Data; const char* Name; int64_t Size; - int32_t Flags; + int64_t Flags; } MemoryArea; #define MEMORYAREA_FLAGS_WRITABLE 1 diff --git a/waterbox/sameboy/bizhawk.cpp b/waterbox/sameboy/bizhawk.cpp index 28c6cda11e..94ba62a39f 100644 --- a/waterbox/sameboy/bizhawk.cpp +++ b/waterbox/sameboy/bizhawk.cpp @@ -64,6 +64,24 @@ static void InputCallback(GB_gameboy_t *gb) FrontendInputCallback(); } +typedef void (*FrontendPrinterCallback_t)(uint32_t *image, + uint8_t height, + uint8_t top_margin, + uint8_t bottom_margin, + uint8_t exposure); + +static FrontendPrinterCallback_t FrontendPrinterCallback; + +static void PrinterCallback(GB_gameboy_t *gb, + uint32_t *image, + uint8_t height, + uint8_t top_margin, + uint8_t bottom_margin, + uint8_t exposure) +{ + FrontendPrinterCallback(image, height, top_margin, bottom_margin, exposure); +} + static blip_t *leftblip; static blip_t *rightblip; const int SOUND_RATE_GB = 2097152; @@ -245,6 +263,22 @@ ECL_EXPORT bool HasSaveRam() return true; } +ECL_EXPORT void SetPrinterCallback(FrontendPrinterCallback_t callback) +{ + FrontendPrinterCallback = callback; + + if (callback) + { + GB_connect_printer(&GB, PrinterCallback); + } + else + { + GB_set_serial_transfer_start_callback(&GB, NULL); + GB_set_serial_transfer_end_callback(&GB, NULL); + GB.printer.callback = NULL; + } +} + int main() { return 0; diff --git a/waterbox/sameboy/printer.c b/waterbox/sameboy/printer.c index bc1d45ab47..e27d7d544d 100644 --- a/waterbox/sameboy/printer.c +++ b/waterbox/sameboy/printer.c @@ -1,4 +1,5 @@ #include "gb.h" +#include "../emulibc/emulibc.h" /* TODO: Emulation is VERY basic and assumes the ROM correctly uses the printer's interface. Incorrect usage is not correctly emulated, as it's not well documented, nor do I @@ -9,6 +10,9 @@ Also, field mask values are assumed. */ +// hackadoodle! we must not overflow the stack +static ECL_INVISIBLE uint32_t tmp_image[160 * 200]; + static void handle_command(GB_gameboy_t *gb) { @@ -21,7 +25,7 @@ static void handle_command(GB_gameboy_t *gb) case GB_PRINTER_START_COMMAND: if (gb->printer.command_length == 4) { gb->printer.status = 6; /* Printing */ - uint32_t image[gb->printer.image_offset]; + uint32_t *const image = tmp_image; uint8_t palette = gb->printer.command_data[2]; uint32_t colors[4] = {gb->rgb_encode_callback(gb, 0xff, 0xff, 0xff), gb->rgb_encode_callback(gb, 0xaa, 0xaa, 0xaa), diff --git a/waterbox/sameboy/sgb.c b/waterbox/sameboy/sgb.c index f4fb6af834..d08ff4ae8d 100644 --- a/waterbox/sameboy/sgb.c +++ b/waterbox/sameboy/sgb.c @@ -3,6 +3,7 @@ #include #include #include "snes_spc/spc.h" +#include "../emulibc/emulibc.h" #define utils_log printf @@ -76,13 +77,13 @@ typedef struct uint16_t tilemap[32 * 32]; // frame data - uint8_t frame[160 * 144]; // the most recent obtained full frame + uint8_t frame[160 * 144]; // the most recent obtained full frame uint32_t frozenframe[256 * 224]; // the most recent saved full frame (MASK_EN) - uint8_t attr[20 * 18]; // current attr map for the GB screen - uint8_t auxattr[45][20 * 18]; // 45 attr files + uint8_t attr[20 * 18]; // current attr map for the GB screen + uint8_t auxattr[45][20 * 18]; // 45 attr files // MASK_EN - uint8_t active_mask; // true if mask is currently being used + uint8_t active_mask; // true if mask is currently being used // audio SNES_SPC *spc; @@ -622,12 +623,15 @@ int sgb_init(const uint8_t *spc, int length) utils_log("SGB: Failed to load SPC\n"); return 0; } - + + // make a scratch buffer in a predictable (not stack) place because spc stores multiple pointers to it + // which is kind of nasty... + int16_t *sound_buffer = alloc_invisible(4096 * sizeof(int16_t)); + // the combination of the sameboy bootrom plus the built in SPC file we use means // that the SPC doesn't finish its init fast enough for donkey kong, which starts poking // data too early. it's just a combination of various HLE concerns not meshing... - int16_t sound_buffer[4096]; - spc_set_output(sgb.spc, sound_buffer, sizeof(sound_buffer) / sizeof(sound_buffer[0])); + spc_set_output(sgb.spc, sound_buffer, 4096); for (int i = 0; i < 240; i++) { spc_end_frame(sgb.spc, 35104); @@ -741,10 +745,10 @@ void sgb_set_controller_data(const uint8_t *buttons) memcpy(sgb.joypad_data, buttons, sizeof(sgb.joypad_data)); } -static void trn_sound(const uint8_t* data) +static void trn_sound(const uint8_t *data) { - const uint8_t* const dataend = data + 0x10000; - uint8_t* const dst = spc_get_ram(sgb.spc); + const uint8_t *const dataend = data + 0x10000; + uint8_t *const dst = spc_get_ram(sgb.spc); while (1) { @@ -771,7 +775,7 @@ static void trn_sound(const uint8_t* data) utils_log("TRN_SOUND dst overflow\n"); return; } - utils_log("TRN_SOUND addr %04x len %04x\n", addr, len); + utils_log("TRN_SOUND addr %04x len %04x\n", addr, len); memcpy(dst + addr, data, len); data += len; } @@ -1014,14 +1018,14 @@ void sgb_render_audio(uint64_t time, void (*callback)(int16_t l, int16_t r, uint else { utils_log("SPC: %02x %02x %02x %02x => %02x %02x %02x %02x\n", - spc_read_port(sgb.spc, 0, 0), - spc_read_port(sgb.spc, 0, 1), - spc_read_port(sgb.spc, 0, 2), - spc_read_port(sgb.spc, 0, 3), - sgb.sound_control[0], - sgb.sound_control[1], - sgb.sound_control[2], - sgb.sound_control[3]); + spc_read_port(sgb.spc, 0, 0), + spc_read_port(sgb.spc, 0, 1), + spc_read_port(sgb.spc, 0, 2), + spc_read_port(sgb.spc, 0, 3), + sgb.sound_control[0], + sgb.sound_control[1], + sgb.sound_control[2], + sgb.sound_control[3]); } for (int p = 0; p < 4; p++) { diff --git a/waterbox/ss/ss.cpp b/waterbox/ss/ss.cpp index ec0cf755ac..762dffffac 100644 --- a/waterbox/ss/ss.cpp +++ b/waterbox/ss/ss.cpp @@ -65,7 +65,7 @@ static uint8 SCU_SSH2VectorFetch(void); static void INLINE MDFN_HOT CheckEventsByMemTS(void); SH7095 CPU[2]{{"SH2-M", SS_EVENT_SH2_M_DMA, SCU_MSH2VectorFetch}, {"SH2-S", SS_EVENT_SH2_S_DMA, SCU_SSH2VectorFetch}}; -static uint16* BIOSROM; +static uint16 *BIOSROM; static uint16 WorkRAML[1024 * 1024 / sizeof(uint16)]; static uint16 WorkRAMH[1024 * 1024 / sizeof(uint16)]; // Effectively 32-bit in reality, but 16-bit here because of CPU interpreter design(regarding fastmap). static uint8 BackupRAM[32768]; @@ -92,6 +92,9 @@ static void INLINE SH7095_BusWrite(uint32 A, T V, const bool BurstHax, int32 *SH template static T INLINE SH7095_BusRead(uint32 A, const bool BurstHax, int32 *SH2DMAHax); +static int32 ExtBusCounter[2]; +static size_t ExtBusWhich; + // SH-2 region // 0: 0x00000000-0x01FFFFFF // 1: 0x02000000-0x03FFFFFF @@ -105,6 +108,9 @@ static T INLINE SH7095_BusRead(uint32 A, const bool BurstHax, int32 *SH2DMAHax); template static INLINE void BusRW(uint32 A, T &V, const bool BurstHax, int32 *SH2DMAHax) { + if (!BurstHax && !SH2DMAHax) + ExtBusCounter[ExtBusWhich]++; + // // High work RAM // @@ -636,11 +642,18 @@ static int32 NO_INLINE MDFN_HOT RunLoop(EmulateSpecStruct *espec) { do { + ExtBusCounter[0] = ExtBusCounter[1] = 0; + ExtBusWhich = 0; + if (DebugMode) DBG_CPUHandler<0>(eff_ts); CPU[0].Step<0, DebugMode>(); + if (CPU[0].DMA_RunCond(0) || CPU[0].DMA_RunCond(1)) + CPU[0].timestamp += ExtBusCounter[0] * 16; + + ExtBusWhich = 1; while (MDFN_LIKELY(CPU[0].timestamp > CPU[1].timestamp)) { if (DebugMode) @@ -927,7 +940,7 @@ static bool MDFN_COLD InitCommon(const unsigned cart_type, const unsigned smpc_a // Call InitFastMemMap() before functions like SOUND_Init() InitFastMemMap(); - BIOSROM = (uint16*)alloc_sealed(524288); + BIOSROM = (uint16 *)alloc_sealed(524288); AddMemoryDomain("Boot Rom", BIOSROM, 524288, MEMORYAREA_FLAGS_YUGEENDIAN | MEMORYAREA_FLAGS_WORDSIZE2); SS_SetPhysMemMap(0x00000000, 0x000FFFFF, BIOSROM, 524288); SS_SetPhysMemMap(0x00200000, 0x003FFFFF, WorkRAML, sizeof(WorkRAML), true); @@ -969,7 +982,7 @@ static bool MDFN_COLD InitCommon(const unsigned cart_type, const unsigned smpc_a return false; } - FirmwareDataCallback(biospath, (uint8*)&BIOSROM[0]); + FirmwareDataCallback(biospath, (uint8 *)&BIOSROM[0]); for (unsigned i = 0; i < 262144; i++) BIOSROM[i] = MDFN_de16msb(&BIOSROM[i]); @@ -994,8 +1007,8 @@ static bool MDFN_COLD InitCommon(const unsigned cart_type, const unsigned smpc_a CorrectAspect = setting_ss_correct_aspect; ShowHOverscan = setting_ss_h_overscan; DoHBlend = setting_ss_h_blend; - LineVisFirst = sls; - LineVisLast = sle; + LineVisFirst = sls; + LineVisLast = sle; MDFN_printf(_("Displayed scanlines: [%u,%u]\n"), sls, sle); MDFN_printf(_("Correct Aspect Ratio: %s\n"), correct_aspect ? _("Enabled") : _("Disabled"));