mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-24 12:30:17 +00:00
Merge pull request #611 from TomHarte/68000
Adds an Initial Emulation of the 68000
This commit is contained in:
commit
9c3c2192dd
@ -62,6 +62,7 @@ class ConcreteMachine:
|
||||
set_clock_rate(2000000);
|
||||
|
||||
speaker_.set_input_rate(2000000 / SoundGenerator::clock_rate_divider);
|
||||
speaker_.set_high_frequency_cutoff(7000);
|
||||
|
||||
std::vector<std::string> rom_names = {"basic.rom", "os.rom"};
|
||||
if(target.has_adfs) {
|
||||
|
@ -150,7 +150,6 @@
|
||||
4B2A332D1DB86821002876E3 /* OricOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2A332B1DB86821002876E3 /* OricOptions.xib */; };
|
||||
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
|
||||
4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53961D117D36003C6002 /* CSMachine.mm */; };
|
||||
4B2AF8691E513FC20027EE29 /* TIATests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2AF8681E513FC20027EE29 /* TIATests.mm */; };
|
||||
4B2B3A4B1F9B8FA70062DABF /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A471F9B8FA70062DABF /* Typer.cpp */; };
|
||||
4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2B3A481F9B8FA70062DABF /* MemoryFuzzer.cpp */; };
|
||||
4B2BFC5F1D613E0200BA3AA9 /* TapePRG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFC5D1D613E0200BA3AA9 /* TapePRG.cpp */; };
|
||||
@ -198,7 +197,6 @@
|
||||
4B4B1A3D200198CA00A0F866 /* KonamiSCC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4B1A3A200198C900A0F866 /* KonamiSCC.cpp */; };
|
||||
4B4DC8211D2C2425003C5BF8 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC81F1D2C2425003C5BF8 /* Vic20.cpp */; };
|
||||
4B4DC82B1D2C27A4003C5BF8 /* SerialBus.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */; };
|
||||
4B50730A1DDFCFDF00C48FBD /* ArrayBuilderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */; };
|
||||
4B54C0BC1F8D8E790050900F /* KeyboardMachine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */; };
|
||||
4B54C0BF1F8D8F450050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0BD1F8D8F450050900F /* Keyboard.cpp */; };
|
||||
4B54C0C21F8D91CD0050900F /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B54C0C11F8D91CD0050900F /* Keyboard.cpp */; };
|
||||
@ -248,6 +246,8 @@
|
||||
4B83348A1F5DB94B0097E338 /* IRQDelegatePortHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8334891F5DB94B0097E338 /* IRQDelegatePortHandler.cpp */; };
|
||||
4B83348C1F5DB99C0097E338 /* 6522Base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B83348B1F5DB99C0097E338 /* 6522Base.cpp */; };
|
||||
4B8334951F5E25B60097E338 /* C1540.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8334941F5E25B60097E338 /* C1540.cpp */; };
|
||||
4B85322D227793CB00F26553 /* etos192uk.trace.txt.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4B85322C227793CA00F26553 /* etos192uk.trace.txt.gz */; };
|
||||
4B85322F2277ABDE00F26553 /* tos100.trace.txt.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4B85322E2277ABDD00F26553 /* tos100.trace.txt.gz */; };
|
||||
4B86E25B1F8C628F006FAA45 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B86E2591F8C628F006FAA45 /* Keyboard.cpp */; };
|
||||
4B8805F01DCFC99C003085B1 /* Acorn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */; };
|
||||
4B8805F41DCFD22A003085B1 /* Commodore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B8805F21DCFD22A003085B1 /* Commodore.cpp */; };
|
||||
@ -308,6 +308,9 @@
|
||||
4B98A1CE1FFADEC500ADF63B /* MSX ROMs in Resources */ = {isa = PBXBuildFile; fileRef = 4B98A1CD1FFADEC400ADF63B /* MSX ROMs */; };
|
||||
4B9BE400203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */; };
|
||||
4B9BE401203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */; };
|
||||
4B9F11C92272375400701480 /* qltrace.txt.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4B9F11C82272375400701480 /* qltrace.txt.gz */; };
|
||||
4B9F11CA2272433900701480 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; };
|
||||
4B9F11CC22729B3600701480 /* OPCLOGR2.BIN in Resources */ = {isa = PBXBuildFile; fileRef = 4B9F11CB22729B3500701480 /* OPCLOGR2.BIN */; };
|
||||
4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */; };
|
||||
4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */; };
|
||||
4BA91E1D216D85BA00F79557 /* MasterSystemVDPTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */; };
|
||||
@ -618,6 +621,7 @@
|
||||
4BCF1FA41DADC3DD0039D2E7 /* Oric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCF1FA21DADC3DD0039D2E7 /* Oric.cpp */; };
|
||||
4BD191F42191180E0042E144 /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD191F22191180E0042E144 /* ScanTarget.cpp */; };
|
||||
4BD191F52191180E0042E144 /* ScanTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD191F22191180E0042E144 /* ScanTarget.cpp */; };
|
||||
4BD388882239E198002D14B5 /* 68000Tests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BD388872239E198002D14B5 /* 68000Tests.mm */; };
|
||||
4BD3A30B1EE755C800B5B501 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD3A3091EE755C800B5B501 /* Video.cpp */; };
|
||||
4BD424DF2193B5340097291A /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD424DD2193B5340097291A /* TextureTarget.cpp */; };
|
||||
4BD424E02193B5340097291A /* TextureTarget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BD424DD2193B5340097291A /* TextureTarget.cpp */; };
|
||||
@ -638,6 +642,7 @@
|
||||
4BDB61EB2032806E0048AF91 /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A539A1D117D36003C6002 /* CSAtari2600.mm */; };
|
||||
4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE21F1DA19D7C0090D3CE /* Atari2600OptionsPanel.swift */; };
|
||||
4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDDBA981EF3451200347E61 /* Z80MachineCycleTests.swift */; };
|
||||
4BE76CF922641ED400ACD6FA /* QLTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BE76CF822641ED300ACD6FA /* QLTests.mm */; };
|
||||
4BE7C9181E3D397100A5496D /* TIA.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BE7C9161E3D397100A5496D /* TIA.cpp */; };
|
||||
4BE9A6B11EDE293000CBCB47 /* zexdoc.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BE9A6B01EDE293000CBCB47 /* zexdoc.com */; };
|
||||
4BEA525E1DF33323007E74F2 /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BEA525D1DF33323007E74F2 /* Tape.cpp */; };
|
||||
@ -661,6 +666,9 @@
|
||||
4BFDD78C1F7F2DB4008579B9 /* ImplicitSectors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */; };
|
||||
4BFE7B871FC39BF100160B38 /* StandardOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */; };
|
||||
4BFE7B881FC39D8900160B38 /* StandardOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */; };
|
||||
4BFF1D3922337B0300838EA1 /* 68000Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFF1D3822337B0300838EA1 /* 68000Storage.cpp */; };
|
||||
4BFF1D3A22337B0300838EA1 /* 68000Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFF1D3822337B0300838EA1 /* 68000Storage.cpp */; };
|
||||
4BFF1D3D2235C3C100838EA1 /* EmuTOSTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -869,7 +877,6 @@
|
||||
4B4DC8271D2C2470003C5BF8 /* C1540.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = C1540.hpp; sourceTree = "<group>"; };
|
||||
4B4DC8291D2C27A4003C5BF8 /* SerialBus.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SerialBus.cpp; sourceTree = "<group>"; };
|
||||
4B4DC82A1D2C27A4003C5BF8 /* SerialBus.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SerialBus.hpp; sourceTree = "<group>"; };
|
||||
4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ArrayBuilderTests.mm; sourceTree = "<group>"; };
|
||||
4B51F70920A521D700AFA2C1 /* Source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Source.hpp; sourceTree = "<group>"; };
|
||||
4B51F70A20A521D700AFA2C1 /* Observer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Observer.hpp; sourceTree = "<group>"; };
|
||||
4B54C0BB1F8D8E790050900F /* KeyboardMachine.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardMachine.cpp; sourceTree = "<group>"; };
|
||||
@ -958,6 +965,9 @@
|
||||
4B83348E1F5DBA6E0097E338 /* 6522Storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = 6522Storage.hpp; path = Implementation/6522Storage.hpp; sourceTree = "<group>"; };
|
||||
4B8334911F5E24FF0097E338 /* C1540Base.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = C1540Base.hpp; path = Implementation/C1540Base.hpp; sourceTree = "<group>"; };
|
||||
4B8334941F5E25B60097E338 /* C1540.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = C1540.cpp; path = Implementation/C1540.cpp; sourceTree = "<group>"; };
|
||||
4B85322922778E4200F26553 /* Comparative68000.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Comparative68000.hpp; sourceTree = "<group>"; };
|
||||
4B85322C227793CA00F26553 /* etos192uk.trace.txt.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = etos192uk.trace.txt.gz; sourceTree = "<group>"; };
|
||||
4B85322E2277ABDD00F26553 /* tos100.trace.txt.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = tos100.trace.txt.gz; sourceTree = "<group>"; };
|
||||
4B86E2591F8C628F006FAA45 /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = "<group>"; };
|
||||
4B86E25A1F8C628F006FAA45 /* Keyboard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = "<group>"; };
|
||||
4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = "<group>"; };
|
||||
@ -1035,6 +1045,8 @@
|
||||
4B98A1CD1FFADEC400ADF63B /* MSX ROMs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "MSX ROMs"; sourceTree = "<group>"; };
|
||||
4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiSpeaker.cpp; sourceTree = "<group>"; };
|
||||
4B9BE3FF203A0C0600FFAE60 /* MultiSpeaker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiSpeaker.hpp; sourceTree = "<group>"; };
|
||||
4B9F11C82272375400701480 /* qltrace.txt.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = qltrace.txt.gz; sourceTree = "<group>"; };
|
||||
4B9F11CB22729B3500701480 /* OPCLOGR2.BIN */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = OPCLOGR2.BIN; path = "68000 Coverage/OPCLOGR2.BIN"; sourceTree = "<group>"; };
|
||||
4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZX8081.cpp; path = Data/ZX8081.cpp; sourceTree = "<group>"; };
|
||||
4BA0F68D1EEA0E8400E9489E /* ZX8081.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZX8081.hpp; path = Data/ZX8081.hpp; sourceTree = "<group>"; };
|
||||
4BA141C12073100800A31EC9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
|
||||
@ -1375,6 +1387,7 @@
|
||||
4BD191F22191180E0042E144 /* ScanTarget.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ScanTarget.cpp; sourceTree = "<group>"; };
|
||||
4BD191F32191180E0042E144 /* ScanTarget.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ScanTarget.hpp; sourceTree = "<group>"; };
|
||||
4BD388411FE34E010042B588 /* 9918Base.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 9918Base.hpp; path = 9918/Implementation/9918Base.hpp; sourceTree = "<group>"; };
|
||||
4BD388872239E198002D14B5 /* 68000Tests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000Tests.mm; sourceTree = "<group>"; };
|
||||
4BD3A3091EE755C800B5B501 /* Video.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Video.cpp; path = ZX8081/Video.cpp; sourceTree = "<group>"; };
|
||||
4BD3A30A1EE755C800B5B501 /* Video.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Video.hpp; path = ZX8081/Video.hpp; sourceTree = "<group>"; };
|
||||
4BD424DD2193B5340097291A /* TextureTarget.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextureTarget.cpp; sourceTree = "<group>"; };
|
||||
@ -1404,6 +1417,7 @@
|
||||
4BE3231520532AA7006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
|
||||
4BE3231620532BED006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
|
||||
4BE3231720532CC0006EF799 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = "<group>"; };
|
||||
4BE76CF822641ED300ACD6FA /* QLTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = QLTests.mm; sourceTree = "<group>"; };
|
||||
4BE7C9161E3D397100A5496D /* TIA.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TIA.cpp; sourceTree = "<group>"; };
|
||||
4BE7C9171E3D397100A5496D /* TIA.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TIA.hpp; sourceTree = "<group>"; };
|
||||
4BE845201F2FF7F100A5EA22 /* CRTC6845.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRTC6845.hpp; path = 6845/CRTC6845.hpp; sourceTree = "<group>"; };
|
||||
@ -1459,6 +1473,11 @@
|
||||
4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImplicitSectors.cpp; sourceTree = "<group>"; };
|
||||
4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StandardOptions.cpp; sourceTree = "<group>"; };
|
||||
4BFE7B861FC39BF100160B38 /* StandardOptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StandardOptions.hpp; sourceTree = "<group>"; };
|
||||
4BFF1D342233778C00838EA1 /* 68000.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 68000.hpp; sourceTree = "<group>"; };
|
||||
4BFF1D37223379D500838EA1 /* 68000Storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 68000Storage.hpp; sourceTree = "<group>"; };
|
||||
4BFF1D3822337B0300838EA1 /* 68000Storage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = 68000Storage.cpp; sourceTree = "<group>"; };
|
||||
4BFF1D3B2235714900838EA1 /* 68000Implementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = 68000Implementation.hpp; sourceTree = "<group>"; };
|
||||
4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = EmuTOSTests.mm; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -1486,6 +1505,7 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4B9F11CA2272433900701480 /* libz.tbd in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1551,13 +1571,16 @@
|
||||
4B1414631B588A1100E04248 /* Test Binaries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B85322B227793CA00F26553 /* TOS Startup */,
|
||||
4B9252CD1E74D28200B76AF1 /* Atari ROMs */,
|
||||
4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */,
|
||||
4B98A1CD1FFADEC400ADF63B /* MSX ROMs */,
|
||||
4B018B88211930DE002A3937 /* 65C02_extended_opcodes_test.bin */,
|
||||
4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */,
|
||||
4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */,
|
||||
4B9F11CB22729B3500701480 /* OPCLOGR2.BIN */,
|
||||
4BBF49B41ED2881600AB3669 /* FUSE */,
|
||||
4B9F11C72272375400701480 /* QL Startup */,
|
||||
4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */,
|
||||
4BE9A6B21EDE294200CBCB47 /* Zexall */,
|
||||
);
|
||||
@ -2238,6 +2261,15 @@
|
||||
name = Implementation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B85322B227793CA00F26553 /* TOS Startup */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B85322E2277ABDD00F26553 /* tos100.trace.txt.gz */,
|
||||
4B85322C227793CA00F26553 /* etos192uk.trace.txt.gz */,
|
||||
);
|
||||
path = "TOS Startup";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B86E2581F8C628F006FAA45 /* Inputs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2435,6 +2467,14 @@
|
||||
path = Implementation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4B9F11C72272375400701480 /* QL Startup */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B9F11C82272375400701480 /* qltrace.txt.gz */,
|
||||
);
|
||||
path = "QL Startup";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BAB62AA1D3272D200DF5BA0 /* Disk */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2817,13 +2857,16 @@
|
||||
4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */,
|
||||
4B85322922778E4200F26553 /* Comparative68000.hpp */,
|
||||
4BD388872239E198002D14B5 /* 68000Tests.mm */,
|
||||
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
|
||||
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
|
||||
4BFF1D3C2235C3C100838EA1 /* EmuTOSTests.mm */,
|
||||
4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */,
|
||||
4B98A0601FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm */,
|
||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
|
||||
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
|
||||
4BE76CF822641ED300ACD6FA /* QLTests.mm */,
|
||||
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
|
||||
4B1D08051E0F7A1100763741 /* TimeTests.mm */,
|
||||
4BB73EB81B587A5100552FC2 /* Info.plist */,
|
||||
@ -2886,11 +2929,12 @@
|
||||
4BB73EDD1B587CA500552FC2 /* Processors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B1414561B58879D00E04248 /* 6502 */,
|
||||
4B77069E1EC9045B0053B588 /* Z80 */,
|
||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
|
||||
4BFCA1211ECBDCAF00AC40C1 /* AllRAMProcessor.cpp */,
|
||||
4BFCA1221ECBDCAF00AC40C1 /* AllRAMProcessor.hpp */,
|
||||
4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */,
|
||||
4B1414561B58879D00E04248 /* 6502 */,
|
||||
4BFF1D332233778C00838EA1 /* 68000 */,
|
||||
4B77069E1EC9045B0053B588 /* Z80 */,
|
||||
);
|
||||
name = Processors;
|
||||
path = ../../Processors;
|
||||
@ -3196,6 +3240,25 @@
|
||||
path = Utility;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BFF1D332233778C00838EA1 /* 68000 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BFF1D342233778C00838EA1 /* 68000.hpp */,
|
||||
4BFF1D36223379D500838EA1 /* Implementation */,
|
||||
);
|
||||
path = 68000;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4BFF1D36223379D500838EA1 /* Implementation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4BFF1D37223379D500838EA1 /* 68000Storage.hpp */,
|
||||
4BFF1D3822337B0300838EA1 /* 68000Storage.cpp */,
|
||||
4BFF1D3B2235714900838EA1 /* 68000Implementation.hpp */,
|
||||
);
|
||||
path = Implementation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -3285,7 +3348,7 @@
|
||||
};
|
||||
4BB73E9D1B587A5100552FC2 = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
SystemCapabilities = {
|
||||
com.apple.Sandbox = {
|
||||
enabled = 1;
|
||||
@ -3294,12 +3357,12 @@
|
||||
};
|
||||
4BB73EB11B587A5100552FC2 = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
TestTargetID = 4BB73E9D1B587A5100552FC2;
|
||||
};
|
||||
4BB73EBC1B587A5100552FC2 = {
|
||||
CreatedOnToolsVersion = 7.0;
|
||||
LastSwiftMigration = 0900;
|
||||
LastSwiftMigration = 1020;
|
||||
TestTargetID = 4BB73E9D1B587A5100552FC2;
|
||||
};
|
||||
};
|
||||
@ -3408,6 +3471,7 @@
|
||||
4BB298FB1B587D8400A49093 /* ancb in Resources */,
|
||||
4BB299431B587D8400A49093 /* dcma in Resources */,
|
||||
4BB298FD1B587D8400A49093 /* andax in Resources */,
|
||||
4B85322D227793CB00F26553 /* etos192uk.trace.txt.gz in Resources */,
|
||||
4BB299401B587D8400A49093 /* cpya in Resources */,
|
||||
4BB299BE1B587D8400A49093 /* rraix in Resources */,
|
||||
4BB299E41B587D8400A49093 /* tayn in Resources */,
|
||||
@ -3484,6 +3548,7 @@
|
||||
4BB2997D1B587D8400A49093 /* ldxay in Resources */,
|
||||
4BB299D71B587D8400A49093 /* staax in Resources */,
|
||||
4B98A1CE1FFADEC500ADF63B /* MSX ROMs in Resources */,
|
||||
4B9F11CC22729B3600701480 /* OPCLOGR2.BIN in Resources */,
|
||||
4BB2990C1B587D8400A49093 /* asoax in Resources */,
|
||||
4BB299191B587D8400A49093 /* bita in Resources */,
|
||||
4BB2992A1B587D8400A49093 /* cia2ta in Resources */,
|
||||
@ -3501,6 +3566,7 @@
|
||||
4BB299C41B587D8400A49093 /* sbca in Resources */,
|
||||
4BB298F41B587D8400A49093 /* adcay in Resources */,
|
||||
4B44EBF51DC987AF00A7820C /* AllSuiteA.bin in Resources */,
|
||||
4B85322F2277ABDE00F26553 /* tos100.trace.txt.gz in Resources */,
|
||||
4BB299C61B587D8400A49093 /* sbcay in Resources */,
|
||||
4BB299601B587D8400A49093 /* insa in Resources */,
|
||||
4BB299951B587D8400A49093 /* mmufetch in Resources */,
|
||||
@ -3602,6 +3668,7 @@
|
||||
4BB299A41B587D8400A49093 /* oraz in Resources */,
|
||||
4BB299611B587D8400A49093 /* insax in Resources */,
|
||||
4BB299351B587D8400A49093 /* cmpix in Resources */,
|
||||
4B9F11C92272375400701480 /* qltrace.txt.gz in Resources */,
|
||||
4BB299041B587D8400A49093 /* aneb in Resources */,
|
||||
4BB299BB1B587D8400A49093 /* rraa in Resources */,
|
||||
4BB299091B587D8400A49093 /* aslz in Resources */,
|
||||
@ -3687,6 +3754,7 @@
|
||||
4B05401F219D1618001BF69C /* ScanTarget.cpp in Sources */,
|
||||
4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */,
|
||||
4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */,
|
||||
4BFF1D3A22337B0300838EA1 /* 68000Storage.cpp in Sources */,
|
||||
4B055AC71FAE9AEE0060FFFF /* TIA.cpp in Sources */,
|
||||
4B055AD21FAE9B0B0060FFFF /* Keyboard.cpp in Sources */,
|
||||
4B89451B201967B4007DE474 /* ConfidenceSummary.cpp in Sources */,
|
||||
@ -3967,6 +4035,7 @@
|
||||
4B8334821F5D9FF70097E338 /* PartialMachineCycle.cpp in Sources */,
|
||||
4BD424E72193B5830097291A /* Rectangle.cpp in Sources */,
|
||||
4B1B88C0202E3DB200B67DFF /* MultiConfigurable.cpp in Sources */,
|
||||
4BFF1D3922337B0300838EA1 /* 68000Storage.cpp in Sources */,
|
||||
4B54C0BC1F8D8E790050900F /* KeyboardMachine.cpp in Sources */,
|
||||
4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */,
|
||||
4B894534201967B4007DE474 /* AddressMapper.cpp in Sources */,
|
||||
@ -3979,6 +4048,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
4BFF1D3D2235C3C100838EA1 /* EmuTOSTests.mm in Sources */,
|
||||
4B1E85811D176468001EF87D /* 6532Tests.swift in Sources */,
|
||||
4BDDBA991EF3451200347E61 /* Z80MachineCycleTests.swift in Sources */,
|
||||
4B98A05F1FFAD62400ADF63B /* CSROMFetcher.mm in Sources */,
|
||||
@ -3989,18 +4059,18 @@
|
||||
4B7BC7F51F58F27800D1B1B4 /* 6502AllRAM.cpp in Sources */,
|
||||
4B08A2751EE35D56008B7065 /* Z80InterruptTests.swift in Sources */,
|
||||
4BFCA1241ECBDCB400AC40C1 /* AllRAMProcessor.cpp in Sources */,
|
||||
4B50730A1DDFCFDF00C48FBD /* ArrayBuilderTests.mm in Sources */,
|
||||
4BBF49AF1ED2880200AB3669 /* FUSETests.swift in Sources */,
|
||||
4B2AF8691E513FC20027EE29 /* TIATests.mm in Sources */,
|
||||
4B3BA0CE1D318B44005DD7A7 /* C1540Bridge.mm in Sources */,
|
||||
4B3BA0D11D318B44005DD7A7 /* TestMachine6502.mm in Sources */,
|
||||
4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */,
|
||||
4BB73EB71B587A5100552FC2 /* AllSuiteATests.swift in Sources */,
|
||||
4B01A6881F22F0DB001FD6E3 /* Z80MemptrTests.swift in Sources */,
|
||||
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */,
|
||||
4BD388882239E198002D14B5 /* 68000Tests.mm in Sources */,
|
||||
4BA91E1D216D85BA00F79557 /* MasterSystemVDPTests.mm in Sources */,
|
||||
4B98A0611FFADCDE00ADF63B /* MSXStaticAnalyserTests.mm in Sources */,
|
||||
4BEF6AAC1D35D1C400E73575 /* DPLLTests.swift in Sources */,
|
||||
4BE76CF922641ED400ACD6FA /* QLTests.mm in Sources */,
|
||||
4B3BA0CF1D318B44005DD7A7 /* MOS6522Bridge.mm in Sources */,
|
||||
4BC751B21D157E61006C31D9 /* 6522Tests.swift in Sources */,
|
||||
4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */,
|
||||
@ -4313,8 +4383,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -4355,8 +4424,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-Signal";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock Signal/ClockSignal-Bridging-Header.h";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -4372,8 +4440,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
|
||||
};
|
||||
name = Debug;
|
||||
@ -4389,8 +4456,7 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalTests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Clock SignalTests/Bridges/Clock SignalTests-Bridging-Header.h";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Clock Signal.app/Contents/MacOS/Clock Signal";
|
||||
};
|
||||
name = Release;
|
||||
@ -4403,8 +4469,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = "Clock Signal";
|
||||
USES_XCTRUNNER = YES;
|
||||
};
|
||||
@ -4418,8 +4483,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "TH.Clock-SignalUITests";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
|
||||
SWIFT_VERSION = 4.0;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_TARGET_NAME = "Clock Signal";
|
||||
USES_XCTRUNNER = YES;
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
disableMainThreadChecker = "YES"
|
||||
codeCoverageEnabled = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
|
@ -49,7 +49,7 @@ class MachineDocument:
|
||||
fileprivate var bestEffortUpdater: CSBestEffortUpdater?
|
||||
|
||||
override var windowNibName: NSNib.Name? {
|
||||
return NSNib.Name(rawValue: "MachineDocument")
|
||||
return "MachineDocument"
|
||||
}
|
||||
|
||||
override func windowControllerDidLoadNib(_ aController: NSWindowController) {
|
||||
@ -64,7 +64,7 @@ class MachineDocument:
|
||||
func windowDidUpdate(_ notification: Notification) {
|
||||
if self.shouldShowNewMachinePanel {
|
||||
self.shouldShowNewMachinePanel = false
|
||||
Bundle.main.loadNibNamed(NSNib.Name(rawValue: "MachinePicker"), owner: self, topLevelObjects: nil)
|
||||
Bundle.main.loadNibNamed("MachinePicker", owner: self, topLevelObjects: nil)
|
||||
self.machinePicker?.establishStoredOptions()
|
||||
self.windowControllers[0].window?.beginSheet(self.machinePickerPanel!, completionHandler: nil)
|
||||
}
|
||||
@ -80,7 +80,7 @@ class MachineDocument:
|
||||
|
||||
// attach an options panel if one is available
|
||||
if let optionsPanelNibName = self.optionsPanelNibName {
|
||||
Bundle.main.loadNibNamed(NSNib.Name(rawValue: optionsPanelNibName), owner: self, topLevelObjects: nil)
|
||||
Bundle.main.loadNibNamed(optionsPanelNibName, owner: self, topLevelObjects: nil)
|
||||
self.optionsPanel.machine = machine
|
||||
self.optionsPanel?.establishStoredOptions()
|
||||
showOptions(self)
|
||||
@ -372,7 +372,7 @@ class MachineDocument:
|
||||
func setupActivityDisplay() {
|
||||
var leds = machine.leds
|
||||
if leds.count > 0 {
|
||||
Bundle.main.loadNibNamed(NSNib.Name(rawValue: "Activity"), owner: self, topLevelObjects: nil)
|
||||
Bundle.main.loadNibNamed("Activity", owner: self, topLevelObjects: nil)
|
||||
showActivity(nil)
|
||||
|
||||
// Inspect the activity panel for indicators.
|
||||
|
BIN
OSBindings/Mac/Clock SignalTests/68000 Coverage/OPCLOGR2.BIN
Executable file
BIN
OSBindings/Mac/Clock SignalTests/68000 Coverage/OPCLOGR2.BIN
Executable file
Binary file not shown.
@ -0,0 +1,5 @@
|
||||
This file provides a record of which opcodes are valid and which are invalid on a
|
||||
real 68000. It was generated by AtariZoll and made available via
|
||||
http://www.atari-forum.com/viewtopic.php?f=68&t=26820 .
|
||||
|
||||
No licence was specified.
|
518
OSBindings/Mac/Clock SignalTests/68000Tests.mm
Normal file
518
OSBindings/Mac/Clock SignalTests/68000Tests.mm
Normal file
@ -0,0 +1,518 @@
|
||||
//
|
||||
// 68000Tests.m
|
||||
// Clock SignalTests
|
||||
//
|
||||
// Created by Thomas Harte on 13/03/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "68000.hpp"
|
||||
|
||||
/*!
|
||||
Provides a 68000 with 64kb of RAM in its low address space;
|
||||
/RESET will put the supervisor stack pointer at 0xFFFF and
|
||||
begin execution at 0x0400.
|
||||
*/
|
||||
class RAM68000: public CPU::MC68000::BusHandler {
|
||||
public:
|
||||
RAM68000() : m68000_(*this) {
|
||||
ram_.resize(256*1024);
|
||||
|
||||
// Setup the /RESET vector.
|
||||
ram_[0] = 0;
|
||||
ram_[1] = 0xffff;
|
||||
ram_[2] = 0;
|
||||
ram_[3] = 0x1000;
|
||||
}
|
||||
|
||||
void set_program(const std::vector<uint16_t> &program) {
|
||||
memcpy(&ram_[0x1000 >> 1], program.data(), program.size() * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void will_perform(uint32_t address, uint16_t opcode) {
|
||||
--instructions_remaining_;
|
||||
}
|
||||
|
||||
void run_for_instructions(int count) {
|
||||
instructions_remaining_ = count;
|
||||
while(instructions_remaining_) {
|
||||
run_for(HalfCycles(2));
|
||||
}
|
||||
}
|
||||
|
||||
void run_for(HalfCycles cycles) {
|
||||
m68000_.run_for(cycles);
|
||||
}
|
||||
|
||||
uint16_t *ram_at(uint32_t address) {
|
||||
return &ram_[address >> 1];
|
||||
}
|
||||
|
||||
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
|
||||
const uint32_t word_address = cycle.word_address();
|
||||
|
||||
using Microcycle = CPU::MC68000::Microcycle;
|
||||
if(cycle.data_select_active()) {
|
||||
if(cycle.operation & Microcycle::InterruptAcknowledge) {
|
||||
cycle.value->halves.low = 10;
|
||||
} else {
|
||||
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
||||
default: break;
|
||||
|
||||
case Microcycle::SelectWord | Microcycle::Read:
|
||||
cycle.value->full = ram_[word_address];
|
||||
printf("r %04x from %08x \n", cycle.value->full, *cycle.address);
|
||||
break;
|
||||
case Microcycle::SelectByte | Microcycle::Read:
|
||||
cycle.value->halves.low = ram_[word_address] >> cycle.byte_shift();
|
||||
break;
|
||||
case Microcycle::SelectWord:
|
||||
printf("w %08x of %04x\n", *cycle.address, cycle.value->full);
|
||||
ram_[word_address] = cycle.value->full;
|
||||
break;
|
||||
case Microcycle::SelectByte:
|
||||
ram_[word_address] = (cycle.value->full & cycle.byte_mask()) | (ram_[word_address] & (0xffff ^ cycle.byte_mask()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
CPU::MC68000::Processor<RAM68000, true>::State get_processor_state() {
|
||||
return m68000_.get_state();
|
||||
}
|
||||
|
||||
void set_processor_state(const CPU::MC68000::Processor<RAM68000, true>::State &state) {
|
||||
m68000_.set_state(state);
|
||||
}
|
||||
|
||||
CPU::MC68000::Processor<RAM68000, true, true> &processor() {
|
||||
return m68000_;
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::MC68000::Processor<RAM68000, true, true> m68000_;
|
||||
std::vector<uint16_t> ram_;
|
||||
int instructions_remaining_;
|
||||
};
|
||||
|
||||
class CPU::MC68000::ProcessorStorageTests {
|
||||
public:
|
||||
ProcessorStorageTests(const CPU::MC68000::ProcessorStorage &storage, const char *coverage_file_name) {
|
||||
false_valids_ = [NSMutableSet set];
|
||||
false_invalids_ = [NSMutableSet set];
|
||||
|
||||
FILE *source = fopen(coverage_file_name, "rb");
|
||||
|
||||
// The file format here is [2 bytes opcode][2 ASCII characters:VA for valid, IN for invalid]...
|
||||
// The file terminates with four additional bytes that begin with two zero bytes.
|
||||
//
|
||||
// The version of the file I grabbed seems to cover all opcodes, making their enumeration
|
||||
// arguably redundant; the code below nevertheless uses the codes from the file.
|
||||
//
|
||||
// Similarly, I'm testing for exactly the strings VA or IN to ensure no further
|
||||
// types creep into any updated version of the table that I then deal with incorrectly.
|
||||
uint16_t last_observed = 0;
|
||||
while(true) {
|
||||
// Fetch opcode number.
|
||||
uint16_t next_opcode = fgetc(source) << 8;
|
||||
next_opcode |= fgetc(source);
|
||||
if(next_opcode < last_observed) break;
|
||||
last_observed = next_opcode;
|
||||
|
||||
// Determine whether it's meant to be valid.
|
||||
char type[3];
|
||||
type[0] = fgetc(source);
|
||||
type[1] = fgetc(source);
|
||||
type[2] = '\0';
|
||||
|
||||
// TEMPORARY: factor out A- and F-line exceptions.
|
||||
if((next_opcode&0xf000) == 0xa000) continue;
|
||||
if((next_opcode&0xf000) == 0xf000) continue;
|
||||
|
||||
if(!strcmp(type, "VA")) {
|
||||
// Test for validity.
|
||||
if(!storage.instructions[next_opcode].micro_operations) {
|
||||
[false_invalids_ addObject:@(next_opcode)];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!strcmp(type, "IN")) {
|
||||
// Test for invalidity.
|
||||
if(storage.instructions[next_opcode].micro_operations) {
|
||||
[false_valids_ addObject:@(next_opcode)];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
fclose(source);
|
||||
}
|
||||
|
||||
NSSet<NSNumber *> *false_valids() const {
|
||||
return false_valids_;
|
||||
}
|
||||
|
||||
NSSet<NSNumber *> *false_invalids() const {
|
||||
return false_invalids_;
|
||||
}
|
||||
|
||||
private:
|
||||
NSMutableSet<NSNumber *> *false_invalids_;
|
||||
NSMutableSet<NSNumber *> *false_valids_;
|
||||
};
|
||||
|
||||
@interface NSSet (CSHexDump)
|
||||
|
||||
- (NSString *)hexDump;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSSet (CSHexDump)
|
||||
|
||||
- (NSString *)hexDump {
|
||||
NSMutableArray<NSString *> *components = [NSMutableArray array];
|
||||
|
||||
for(NSNumber *number in [[self allObjects] sortedArrayUsingSelector:@selector(compare:)]) {
|
||||
[components addObject:[NSString stringWithFormat:@"%04x", number.intValue]];
|
||||
}
|
||||
|
||||
return [components componentsJoinedByString:@" "];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface M68000Tests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation M68000Tests {
|
||||
std::unique_ptr<RAM68000> _machine;
|
||||
}
|
||||
|
||||
- (void)setUp {
|
||||
_machine.reset(new RAM68000());
|
||||
}
|
||||
|
||||
- (void)tearDown {
|
||||
_machine.reset();
|
||||
}
|
||||
|
||||
- (void)testABCD {
|
||||
for(int d = 0; d < 100; ++d) {
|
||||
_machine.reset(new RAM68000());
|
||||
_machine->set_program({
|
||||
0xc100 // ABCD D0, D0
|
||||
});
|
||||
|
||||
auto state = _machine->get_processor_state();
|
||||
const uint8_t bcd_d = ((d / 10) * 16) + (d % 10);
|
||||
state.data[0] = bcd_d;
|
||||
_machine->set_processor_state(state);
|
||||
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
state = _machine->get_processor_state();
|
||||
const uint8_t double_d = (d * 2) % 100;
|
||||
const uint8_t bcd_double_d = ((double_d / 10) * 16) + (double_d % 10);
|
||||
XCTAssert(state.data[0] == bcd_double_d, "%02x + %02x = %02x; should equal %02x", bcd_d, bcd_d, state.data[0], bcd_double_d);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testDivideByZero {
|
||||
_machine->set_program({
|
||||
0x7000, // MOVE #0, D0; location 0x400
|
||||
0x3200, // MOVE D0, D1; location 0x402
|
||||
|
||||
0x82C0, // DIVU; location 0x404
|
||||
|
||||
/* Next instruction would be at 0x406 */
|
||||
});
|
||||
|
||||
auto state = _machine->get_processor_state();
|
||||
state.supervisor_stack_pointer = 0x1000;
|
||||
_machine->set_processor_state(state);
|
||||
|
||||
_machine->run_for_instructions(4);
|
||||
state = _machine->get_processor_state();
|
||||
|
||||
XCTAssert(state.supervisor_stack_pointer == 0x1000 - 6, @"Exception information should have been pushed to stack.");
|
||||
|
||||
const uint16_t *stack_top = _machine->ram_at(state.supervisor_stack_pointer);
|
||||
XCTAssert(stack_top[1] == 0x0000 && stack_top[2] == 0x1006, @"Return address should point to instruction after DIVU.");
|
||||
}
|
||||
|
||||
- (void)testMOVE {
|
||||
_machine->set_program({
|
||||
0x303c, 0xfb2e, // MOVE #fb2e, D0
|
||||
0x3200, // MOVE D0, D1
|
||||
|
||||
0x3040, // MOVEA D0, A0
|
||||
0x3278, 0x1000, // MOVEA.w (0x1000), A1
|
||||
|
||||
0x387c, 0x1000, // MOVE #$1000, A4
|
||||
0x2414, // MOVE.l (A4), D2
|
||||
});
|
||||
|
||||
// run_for_instructions technically runs up to the next instruction
|
||||
// fetch; therefore run for '1' to get past the implied RESET.
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
// Perform MOVE #fb2e, D0
|
||||
_machine->run_for_instructions(1);
|
||||
auto state = _machine->get_processor_state();
|
||||
XCTAssert(state.data[0] == 0xfb2e);
|
||||
|
||||
// Perform MOVE D0, D1
|
||||
_machine->run_for_instructions(1);
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.data[1] == 0xfb2e);
|
||||
|
||||
// Perform MOVEA D0, A0
|
||||
_machine->run_for_instructions(1);
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.address[0] == 0xfffffb2e, "A0 was %08x instead of 0xfffffb2e", state.address[0]);
|
||||
|
||||
// Perform MOVEA.w (0x1000), A1
|
||||
_machine->run_for_instructions(1);
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.address[1] == 0x0000303c, "A1 was %08x instead of 0x0000303c", state.address[1]);
|
||||
|
||||
// Perform MOVE #$400, A4; MOVE.l (A4), D2
|
||||
_machine->run_for_instructions(2);
|
||||
state = _machine->get_processor_state();
|
||||
XCTAssert(state.address[4] == 0x1000, "A4 was %08x instead of 0x00001000", state.address[4]);
|
||||
XCTAssert(state.data[2] == 0x303cfb2e, "D2 was %08x instead of 0x303cfb2e", state.data[2]);
|
||||
}
|
||||
|
||||
- (void)testVectoredInterrupt {
|
||||
_machine->set_program({
|
||||
0x46fc, 0x2000, // MOVE.w #$2000, SR
|
||||
0x4e71, // NOP
|
||||
0x4e71, // NOP
|
||||
0x4e71, // NOP
|
||||
0x4e71, // NOP
|
||||
0x4e71, // NOP
|
||||
});
|
||||
|
||||
// Set the vector that will be supplied back to the start of the
|
||||
// program; this will ensure no further exceptions following
|
||||
// the interrupt.
|
||||
const auto vector = _machine->ram_at(40);
|
||||
vector[0] = 0x0000;
|
||||
vector[1] = 0x1004;
|
||||
|
||||
_machine->run_for_instructions(3);
|
||||
_machine->processor().set_interrupt_level(1);
|
||||
_machine->run_for_instructions(1);
|
||||
|
||||
const auto state = _machine->processor().get_state();
|
||||
XCTAssert(state.program_counter == 0x1008); // i.e. the interrupt happened, the instruction performed was the one at 1004, and therefore
|
||||
// by the wonders of prefetch the program counter is now at 1008.
|
||||
}
|
||||
|
||||
- (void)testOpcodeCoverage {
|
||||
// Perform an audit of implemented instructions.
|
||||
CPU::MC68000::ProcessorStorageTests storage_tests(
|
||||
_machine->processor(),
|
||||
[[NSBundle bundleForClass:[self class]] pathForResource:@"OPCLOGR2" ofType:@"BIN"].UTF8String
|
||||
);
|
||||
|
||||
// This is a list of instructions nominated as valid with OPCLOGR2.BIN but with no obvious decoding —
|
||||
// the disassemblers I tried couldn't figure them out, and I didn't spot them anywhere in the PRM.
|
||||
NSSet<NSNumber *> *const undecodables = [NSSet setWithArray:@[
|
||||
// These look like malformed MOVEs.
|
||||
@(0x2e7d), @(0x2e7e), @(0x2e7f), @(0x2efd), @(0x2efe), @(0x2eff), @(0x2f7d), @(0x2f7e),
|
||||
@(0x2f7f), @(0x2fc0), @(0x2fc1), @(0x2fc2), @(0x2fc3), @(0x2fc4), @(0x2fc5), @(0x2fc6),
|
||||
@(0x2fc7), @(0x2fc8), @(0x2fc9), @(0x2fca), @(0x2fcb), @(0x2fcc), @(0x2fcd), @(0x2fce),
|
||||
@(0x2fcf), @(0x2fd0), @(0x2fd1), @(0x2fd2), @(0x2fd3), @(0x2fd4), @(0x2fd5), @(0x2fd6),
|
||||
@(0x2fd7), @(0x2fd8), @(0x2fd9), @(0x2fda), @(0x2fdb), @(0x2fdc), @(0x2fdd), @(0x2fde),
|
||||
@(0x2fdf), @(0x2fe0), @(0x2fe1), @(0x2fe2), @(0x2fe3), @(0x2fe4), @(0x2fe5), @(0x2fe6),
|
||||
@(0x2fe7), @(0x2fe8), @(0x2fe9), @(0x2fea), @(0x2feb), @(0x2fec), @(0x2fed), @(0x2fee),
|
||||
@(0x2fef), @(0x2ff0), @(0x2ff1), @(0x2ff2), @(0x2ff3), @(0x2ff4), @(0x2ff5), @(0x2ff6),
|
||||
@(0x2ff7), @(0x2ff8), @(0x2ff9), @(0x2ffa), @(0x2ffb), @(0x2ffc), @(0x2ffd), @(0x2ffe),
|
||||
@(0x2fff),
|
||||
|
||||
@(0x3e7d), @(0x3e7e), @(0x3e7f), @(0x3efd), @(0x3efe), @(0x3eff), @(0x3f7d), @(0x3f7e),
|
||||
@(0x3f7f), @(0x3fc0), @(0x3fc1), @(0x3fc2), @(0x3fc3), @(0x3fc4), @(0x3fc5), @(0x3fc6),
|
||||
@(0x3fc7), @(0x3fc8), @(0x3fc9), @(0x3fca), @(0x3fcb), @(0x3fcc), @(0x3fcd), @(0x3fce),
|
||||
@(0x3fcf), @(0x3fd0), @(0x3fd1), @(0x3fd2), @(0x3fd3), @(0x3fd4), @(0x3fd5), @(0x3fd6),
|
||||
@(0x3fd7), @(0x3fd8), @(0x3fd9), @(0x3fda), @(0x3fdb), @(0x3fdc), @(0x3fdd), @(0x3fde),
|
||||
@(0x3fdf), @(0x3fe0), @(0x3fe1), @(0x3fe2), @(0x3fe3), @(0x3fe4), @(0x3fe5), @(0x3fe6),
|
||||
@(0x3fe7), @(0x3fe8), @(0x3fe9), @(0x3fea), @(0x3feb), @(0x3fec), @(0x3fed), @(0x3fee),
|
||||
@(0x3fef), @(0x3ff0), @(0x3ff1), @(0x3ff2), @(0x3ff3), @(0x3ff4), @(0x3ff5), @(0x3ff6),
|
||||
@(0x3ff7), @(0x3ff8), @(0x3ff9), @(0x3ffa), @(0x3ffb), @(0x3ffc), @(0x3ffd), @(0x3ffe),
|
||||
@(0x3fff),
|
||||
|
||||
@(0x46c8), @(0x46c9), @(0x46ca), @(0x46cb), @(0x46cc), @(0x46cd), @(0x46ce), @(0x46cf),
|
||||
@(0x46fd), @(0x46fe), @(0x46ff), @(0x47c0), @(0x47c1), @(0x47c2), @(0x47c3), @(0x47c4),
|
||||
@(0x47c5), @(0x47c6), @(0x47c7), @(0x47c8), @(0x47c9), @(0x47ca), @(0x47cb), @(0x47cc),
|
||||
@(0x47cd), @(0x47ce), @(0x47cf), @(0x47d8), @(0x47d9), @(0x47da), @(0x47db), @(0x47dc),
|
||||
@(0x47dd), @(0x47de), @(0x47df), @(0x47e0), @(0x47e1), @(0x47e2), @(0x47e3), @(0x47e4),
|
||||
@(0x47e5), @(0x47e6), @(0x47e7), @(0x47fc), @(0x47fd), @(0x47fe), @(0x47ff), @(0x4e80),
|
||||
@(0x4e81), @(0x4e82), @(0x4e83), @(0x4e84), @(0x4e85), @(0x4e86), @(0x4e87), @(0x4e88),
|
||||
@(0x4e89), @(0x4e8a), @(0x4e8b), @(0x4e8c), @(0x4e8d), @(0x4e8e), @(0x4e8f), @(0x4e98),
|
||||
@(0x4e99), @(0x4e9a), @(0x4e9b), @(0x4e9c), @(0x4e9d), @(0x4e9e), @(0x4e9f), @(0x4ea0),
|
||||
@(0x4ea1), @(0x4ea2), @(0x4ea3), @(0x4ea4), @(0x4ea5), @(0x4ea6), @(0x4ea7), @(0x4ebc),
|
||||
@(0x4ebd), @(0x4ebe), @(0x4ebf), @(0x4ec0), @(0x4ec1), @(0x4ec2), @(0x4ec3), @(0x4ec4),
|
||||
@(0x4ec5), @(0x4ec6), @(0x4ec7), @(0x4ec8), @(0x4ec9), @(0x4eca), @(0x4ecb), @(0x4ecc),
|
||||
@(0x4ecd), @(0x4ece), @(0x4ecf), @(0x4ed8), @(0x4ed9), @(0x4eda), @(0x4edb), @(0x4edc),
|
||||
@(0x4edd), @(0x4ede), @(0x4edf), @(0x4ee0), @(0x4ee1), @(0x4ee2), @(0x4ee3), @(0x4ee4),
|
||||
@(0x4ee5), @(0x4ee6), @(0x4ee7), @(0x4efc), @(0x4efd), @(0x4efe), @(0x4eff), @(0x4f88),
|
||||
@(0x4f89), @(0x4f8a), @(0x4f8b), @(0x4f8c), @(0x4f8d), @(0x4f8e), @(0x4f8f), @(0x4fbd),
|
||||
@(0x4fbe), @(0x4fbf), @(0x4fc0), @(0x4fc1), @(0x4fc2), @(0x4fc3), @(0x4fc4), @(0x4fc5),
|
||||
@(0x4fc6), @(0x4fc7), @(0x4fc8), @(0x4fc9), @(0x4fca), @(0x4fcb), @(0x4fcc), @(0x4fcd),
|
||||
@(0x4fce), @(0x4fcf), @(0x4fd8), @(0x4fd9), @(0x4fda), @(0x4fdb), @(0x4fdc), @(0x4fdd),
|
||||
@(0x4fde), @(0x4fdf), @(0x4fe0), @(0x4fe1), @(0x4fe2), @(0x4fe3), @(0x4fe4), @(0x4fe5),
|
||||
@(0x4fe6), @(0x4fe7), @(0x4ffc), @(0x4ffd), @(0x4ffe), @(0x4fff),
|
||||
|
||||
@(0x50fa), @(0x50fb), @(0x50fc), @(0x50fd), @(0x50fe), @(0x50ff), @(0x51fa), @(0x51fb),
|
||||
@(0x51fc), @(0x51fd), @(0x51fe), @(0x51ff), @(0x52fa), @(0x52fb), @(0x52fc), @(0x52fd),
|
||||
@(0x52fe), @(0x52ff), @(0x53fa), @(0x53fb), @(0x53fc), @(0x53fd), @(0x53fe), @(0x53ff),
|
||||
@(0x54fa), @(0x54fb), @(0x54fc), @(0x54fd), @(0x54fe), @(0x54ff), @(0x55fa), @(0x55fb),
|
||||
@(0x55fc), @(0x55fd), @(0x55fe), @(0x55ff), @(0x56fa), @(0x56fb), @(0x56fc), @(0x56fd),
|
||||
@(0x56fe), @(0x56ff), @(0x57fa), @(0x57fb), @(0x57fc), @(0x57fd), @(0x57fe), @(0x57ff),
|
||||
@(0x58fa), @(0x58fb), @(0x58fc), @(0x58fd), @(0x58fe), @(0x58ff), @(0x59fa), @(0x59fb),
|
||||
@(0x59fc), @(0x59fd), @(0x59fe), @(0x59ff), @(0x5afa), @(0x5afb), @(0x5afc), @(0x5afd),
|
||||
@(0x5afe), @(0x5aff), @(0x5bfa), @(0x5bfb), @(0x5bfc), @(0x5bfd), @(0x5bfe), @(0x5bff),
|
||||
@(0x5cfa), @(0x5cfb), @(0x5cfc), @(0x5cfd), @(0x5cfe), @(0x5cff), @(0x5dfa), @(0x5dfb),
|
||||
@(0x5dfc), @(0x5dfd), @(0x5dfe), @(0x5dff), @(0x5eba), @(0x5ebb), @(0x5ebc), @(0x5ebd),
|
||||
@(0x5ebe), @(0x5ebf), @(0x5efa), @(0x5efb), @(0x5efc), @(0x5efd), @(0x5efe), @(0x5eff),
|
||||
@(0x5fba), @(0x5fbb), @(0x5fbc), @(0x5fbd), @(0x5fbe), @(0x5fbf), @(0x5ffa), @(0x5ffb),
|
||||
@(0x5ffc), @(0x5ffd), @(0x5ffe), @(0x5fff),
|
||||
|
||||
// These are almost MOVEQs if only bit 8 weren't set.
|
||||
@(0x71c8), @(0x71c9), @(0x71ca), @(0x71cb), @(0x71cc), @(0x71cd), @(0x71ce), @(0x71cf),
|
||||
@(0x71d8), @(0x71d9), @(0x71da), @(0x71db), @(0x71dc), @(0x71dd), @(0x71de), @(0x71df),
|
||||
@(0x71e8), @(0x71e9), @(0x71ea), @(0x71eb), @(0x71ec), @(0x71ed), @(0x71ee), @(0x71ef),
|
||||
@(0x71f8), @(0x71f9), @(0x71fa), @(0x71fb), @(0x71fc), @(0x71fd), @(0x71fe), @(0x71ff),
|
||||
@(0x73c8), @(0x73c9), @(0x73ca), @(0x73cb), @(0x73cc), @(0x73cd), @(0x73ce), @(0x73cf),
|
||||
@(0x73d8), @(0x73d9), @(0x73da), @(0x73db), @(0x73dc), @(0x73dd), @(0x73de), @(0x73df),
|
||||
@(0x73e8), @(0x73e9), @(0x73ea), @(0x73eb), @(0x73ec), @(0x73ed), @(0x73ee), @(0x73ef),
|
||||
@(0x73f8), @(0x73f9), @(0x73fa), @(0x73fb), @(0x73fc), @(0x73fd), @(0x73fe), @(0x73ff),
|
||||
@(0x75c8), @(0x75c9), @(0x75ca), @(0x75cb), @(0x75cc), @(0x75cd), @(0x75ce), @(0x75cf),
|
||||
@(0x75d8), @(0x75d9), @(0x75da), @(0x75db), @(0x75dc), @(0x75dd), @(0x75de), @(0x75df),
|
||||
@(0x75e8), @(0x75e9), @(0x75ea), @(0x75eb), @(0x75ec), @(0x75ed), @(0x75ee), @(0x75ef),
|
||||
@(0x75f8), @(0x75f9), @(0x75fa), @(0x75fb), @(0x75fc), @(0x75fd), @(0x75fe), @(0x75ff),
|
||||
@(0x77c0), @(0x77c1), @(0x77c2), @(0x77c3), @(0x77c4), @(0x77c5), @(0x77c6), @(0x77c7),
|
||||
@(0x77c8), @(0x77c9), @(0x77ca), @(0x77cb), @(0x77cc), @(0x77cd), @(0x77ce), @(0x77cf),
|
||||
@(0x77d0), @(0x77d1), @(0x77d2), @(0x77d3), @(0x77d4), @(0x77d5), @(0x77d6), @(0x77d7),
|
||||
@(0x77d8), @(0x77d9), @(0x77da), @(0x77db), @(0x77dc), @(0x77dd), @(0x77de), @(0x77df),
|
||||
@(0x77e0), @(0x77e1), @(0x77e2), @(0x77e3), @(0x77e4), @(0x77e5), @(0x77e6), @(0x77e7),
|
||||
@(0x77e8), @(0x77e9), @(0x77ea), @(0x77eb), @(0x77ec), @(0x77ed), @(0x77ee), @(0x77ef),
|
||||
@(0x77f0), @(0x77f1), @(0x77f2), @(0x77f3), @(0x77f4), @(0x77f5), @(0x77f6), @(0x77f7),
|
||||
@(0x77f8), @(0x77f9), @(0x77fa), @(0x77fb), @(0x77fc), @(0x77fd), @(0x77fe), @(0x77ff),
|
||||
@(0x79c8), @(0x79c9), @(0x79ca), @(0x79cb), @(0x79cc), @(0x79cd), @(0x79ce), @(0x79cf),
|
||||
@(0x79d8), @(0x79d9), @(0x79da), @(0x79db), @(0x79dc), @(0x79dd), @(0x79de), @(0x79df),
|
||||
@(0x79e8), @(0x79e9), @(0x79ea), @(0x79eb), @(0x79ec), @(0x79ed), @(0x79ee), @(0x79ef),
|
||||
@(0x79f8), @(0x79f9), @(0x79fa), @(0x79fb), @(0x79fc), @(0x79fd), @(0x79fe), @(0x79ff),
|
||||
@(0x7bc8), @(0x7bc9), @(0x7bca), @(0x7bcb), @(0x7bcc), @(0x7bcd), @(0x7bce), @(0x7bcf),
|
||||
@(0x7bd8), @(0x7bd9), @(0x7bda), @(0x7bdb), @(0x7bdc), @(0x7bdd), @(0x7bde), @(0x7bdf),
|
||||
@(0x7be8), @(0x7be9), @(0x7bea), @(0x7beb), @(0x7bec), @(0x7bed), @(0x7bee), @(0x7bef),
|
||||
@(0x7bf8), @(0x7bf9), @(0x7bfa), @(0x7bfb), @(0x7bfc), @(0x7bfd), @(0x7bfe), @(0x7bff),
|
||||
@(0x7dc8), @(0x7dc9), @(0x7dca), @(0x7dcb), @(0x7dcc), @(0x7dcd), @(0x7dce), @(0x7dcf),
|
||||
@(0x7dd8), @(0x7dd9), @(0x7dda), @(0x7ddb), @(0x7ddc), @(0x7ddd), @(0x7dde), @(0x7ddf),
|
||||
@(0x7de8), @(0x7de9), @(0x7dea), @(0x7deb), @(0x7dec), @(0x7ded), @(0x7dee), @(0x7def),
|
||||
@(0x7df8), @(0x7df9), @(0x7dfa), @(0x7dfb), @(0x7dfc), @(0x7dfd), @(0x7dfe), @(0x7dff),
|
||||
@(0x7f40), @(0x7f41), @(0x7f42), @(0x7f43), @(0x7f44), @(0x7f45), @(0x7f46), @(0x7f47),
|
||||
@(0x7f48), @(0x7f49), @(0x7f4a), @(0x7f4b), @(0x7f4c), @(0x7f4d), @(0x7f4e), @(0x7f4f),
|
||||
@(0x7f50), @(0x7f51), @(0x7f52), @(0x7f53), @(0x7f54), @(0x7f55), @(0x7f56), @(0x7f57),
|
||||
@(0x7f58), @(0x7f59), @(0x7f5a), @(0x7f5b), @(0x7f5c), @(0x7f5d), @(0x7f5e), @(0x7f5f),
|
||||
@(0x7f60), @(0x7f61), @(0x7f62), @(0x7f63), @(0x7f64), @(0x7f65), @(0x7f66), @(0x7f67),
|
||||
@(0x7f68), @(0x7f69), @(0x7f6a), @(0x7f6b), @(0x7f6c), @(0x7f6d), @(0x7f6e), @(0x7f6f),
|
||||
@(0x7f70), @(0x7f71), @(0x7f72), @(0x7f73), @(0x7f74), @(0x7f75), @(0x7f76), @(0x7f77),
|
||||
@(0x7f78), @(0x7f79), @(0x7f7a), @(0x7f7b), @(0x7f7c), @(0x7f7d), @(0x7f7e), @(0x7f7f),
|
||||
@(0x7f80), @(0x7f81), @(0x7f82), @(0x7f83), @(0x7f84), @(0x7f85), @(0x7f86), @(0x7f87),
|
||||
@(0x7f88), @(0x7f89), @(0x7f8a), @(0x7f8b), @(0x7f8c), @(0x7f8d), @(0x7f8e), @(0x7f8f),
|
||||
@(0x7f90), @(0x7f91), @(0x7f92), @(0x7f93), @(0x7f94), @(0x7f95), @(0x7f96), @(0x7f97),
|
||||
@(0x7f98), @(0x7f99), @(0x7f9a), @(0x7f9b), @(0x7f9c), @(0x7f9d), @(0x7f9e), @(0x7f9f),
|
||||
@(0x7fa0), @(0x7fa1), @(0x7fa2), @(0x7fa3), @(0x7fa4), @(0x7fa5), @(0x7fa6), @(0x7fa7),
|
||||
@(0x7fa8), @(0x7fa9), @(0x7faa), @(0x7fab), @(0x7fac), @(0x7fad), @(0x7fae), @(0x7faf),
|
||||
@(0x7fb0), @(0x7fb1), @(0x7fb2), @(0x7fb3), @(0x7fb4), @(0x7fb5), @(0x7fb6), @(0x7fb7),
|
||||
@(0x7fb8), @(0x7fb9), @(0x7fba), @(0x7fbb), @(0x7fbc), @(0x7fbd), @(0x7fbe), @(0x7fbf),
|
||||
@(0x7fc0), @(0x7fc1), @(0x7fc2), @(0x7fc3), @(0x7fc4), @(0x7fc5), @(0x7fc6), @(0x7fc7),
|
||||
@(0x7fc8), @(0x7fc9), @(0x7fca), @(0x7fcb), @(0x7fcc), @(0x7fcd), @(0x7fce), @(0x7fcf),
|
||||
@(0x7fd0), @(0x7fd1), @(0x7fd2), @(0x7fd3), @(0x7fd4), @(0x7fd5), @(0x7fd6), @(0x7fd7),
|
||||
@(0x7fd8), @(0x7fd9), @(0x7fda), @(0x7fdb), @(0x7fdc), @(0x7fdd), @(0x7fde), @(0x7fdf),
|
||||
@(0x7fe0), @(0x7fe1), @(0x7fe2), @(0x7fe3), @(0x7fe4), @(0x7fe5), @(0x7fe6), @(0x7fe7),
|
||||
@(0x7fe8), @(0x7fe9), @(0x7fea), @(0x7feb), @(0x7fec), @(0x7fed), @(0x7fee), @(0x7fef),
|
||||
@(0x7ff0), @(0x7ff1), @(0x7ff2), @(0x7ff3), @(0x7ff4), @(0x7ff5), @(0x7ff6), @(0x7ff7),
|
||||
@(0x7ff8), @(0x7ff9), @(0x7ffa), @(0x7ffb), @(0x7ffc), @(0x7ffd), @(0x7ffe), @(0x7fff),
|
||||
|
||||
@(0xbe7d), @(0xbe7e), @(0xbe7f), @(0xbefd), @(0xbefe), @(0xbeff), @(0xbf7a), @(0xbf7b),
|
||||
@(0xbf7c), @(0xbf7d), @(0xbf7e), @(0xbf7f), @(0xbffd), @(0xbffe), @(0xbfff),
|
||||
|
||||
//
|
||||
@(0xc6c8), @(0xc6c9), @(0xc6ca), @(0xc6cb), @(0xc6cc), @(0xc6cd), @(0xc6ce), @(0xc6cf),
|
||||
@(0xc6fd), @(0xc6fe), @(0xc6ff), @(0xc7c8), @(0xc7c9), @(0xc7ca), @(0xc7cb), @(0xc7cc),
|
||||
@(0xc7cd), @(0xc7ce), @(0xc7cf), @(0xc7fd), @(0xc7fe), @(0xc7ff), @(0xce88), @(0xce89),
|
||||
@(0xce8a), @(0xce8b), @(0xce8c), @(0xce8d), @(0xce8e), @(0xce8f), @(0xcebd), @(0xcebe),
|
||||
@(0xcebf), @(0xcec8), @(0xcec9), @(0xceca), @(0xcecb), @(0xcecc), @(0xcecd), @(0xcece),
|
||||
@(0xcecf), @(0xcefd), @(0xcefe), @(0xceff), @(0xcf80), @(0xcf81), @(0xcf82), @(0xcf83),
|
||||
@(0xcf84), @(0xcf85), @(0xcf86), @(0xcf87), @(0xcfba), @(0xcfbb), @(0xcfbc), @(0xcfbd),
|
||||
@(0xcfbe), @(0xcfbf), @(0xcfc8), @(0xcfc9), @(0xcfca), @(0xcfcb), @(0xcfcc), @(0xcfcd),
|
||||
@(0xcfce), @(0xcfcf), @(0xcffd), @(0xcffe), @(0xcfff),
|
||||
|
||||
// These are from the Bcc/BRA/BSR page.
|
||||
@(0xd0fd), @(0xd0fe), @(0xd0ff), @(0xd1fd), @(0xd1fe), @(0xd1ff), @(0xd2fd), @(0xd2fe),
|
||||
@(0xd2ff), @(0xd3fd), @(0xd3fe), @(0xd3ff), @(0xd4fd), @(0xd4fe), @(0xd4ff), @(0xd5fd),
|
||||
@(0xd5fe), @(0xd5ff), @(0xd6fd), @(0xd6fe), @(0xd6ff), @(0xd7fd), @(0xd7fe), @(0xd7ff),
|
||||
@(0xd8fd), @(0xd8fe), @(0xd8ff), @(0xd9fd), @(0xd9fe), @(0xd9ff), @(0xdafd), @(0xdafe),
|
||||
@(0xdaff), @(0xdbfd), @(0xdbfe), @(0xdbff), @(0xdcfd), @(0xdcfe), @(0xdcff), @(0xddfd),
|
||||
@(0xddfe), @(0xddff), @(0xdebd), @(0xdebe), @(0xdebf), @(0xdefd), @(0xdefe), @(0xdeff),
|
||||
@(0xdfba), @(0xdfbb), @(0xdfbc), @(0xdfbd), @(0xdfbe), @(0xdfbf), @(0xdffd), @(0xdffe),
|
||||
@(0xdfff),
|
||||
|
||||
// The E line is for shifts and rolls; none of the those listed below appear to nominate valid
|
||||
// addressing modes.
|
||||
@(0xe6c0), @(0xe6c1), @(0xe6c2), @(0xe6c3), @(0xe6c4), @(0xe6c5), @(0xe6c6), @(0xe6c7),
|
||||
@(0xe6c8), @(0xe6c9), @(0xe6ca), @(0xe6cb), @(0xe6cc), @(0xe6cd), @(0xe6ce), @(0xe6cf),
|
||||
@(0xe6fa), @(0xe6fb), @(0xe6fc), @(0xe6fd), @(0xe6fe), @(0xe6ff), @(0xe7c0), @(0xe7c1),
|
||||
@(0xe7c2), @(0xe7c3), @(0xe7c4), @(0xe7c5), @(0xe7c6), @(0xe7c7), @(0xe7c8), @(0xe7c9),
|
||||
@(0xe7ca), @(0xe7cb), @(0xe7cc), @(0xe7cd), @(0xe7ce), @(0xe7cf), @(0xe7fa), @(0xe7fb),
|
||||
@(0xe7fc), @(0xe7fd), @(0xe7fe), @(0xe7ff), @(0xeec0), @(0xeec1), @(0xeec2), @(0xeec3),
|
||||
@(0xeec4), @(0xeec5), @(0xeec6), @(0xeec7), @(0xeec8), @(0xeec9), @(0xeeca), @(0xeecb),
|
||||
@(0xeecc), @(0xeecd), @(0xeece), @(0xeecf), @(0xeed0), @(0xeed1), @(0xeed2), @(0xeed3),
|
||||
@(0xeed4), @(0xeed5), @(0xeed6), @(0xeed7), @(0xeed8), @(0xeed9), @(0xeeda), @(0xeedb),
|
||||
@(0xeedc), @(0xeedd), @(0xeede), @(0xeedf), @(0xeee0), @(0xeee1), @(0xeee2), @(0xeee3),
|
||||
@(0xeee4), @(0xeee5), @(0xeee6), @(0xeee7), @(0xeee8), @(0xeee9), @(0xeeea), @(0xeeeb),
|
||||
@(0xeeec), @(0xeeed), @(0xeeee), @(0xeeef), @(0xeef0), @(0xeef1), @(0xeef2), @(0xeef3),
|
||||
@(0xeef4), @(0xeef5), @(0xeef6), @(0xeef7), @(0xeef8), @(0xeef9), @(0xeefa), @(0xeefb),
|
||||
@(0xeefc), @(0xeefd), @(0xeefe), @(0xeeff), @(0xefc0), @(0xefc1), @(0xefc2), @(0xefc3),
|
||||
@(0xefc4), @(0xefc5), @(0xefc6), @(0xefc7), @(0xefc8), @(0xefc9), @(0xefca), @(0xefcb),
|
||||
@(0xefcc), @(0xefcd), @(0xefce), @(0xefcf), @(0xefd0), @(0xefd1), @(0xefd2), @(0xefd3),
|
||||
@(0xefd4), @(0xefd5), @(0xefd6), @(0xefd7), @(0xefd8), @(0xefd9), @(0xefda), @(0xefdb),
|
||||
@(0xefdc), @(0xefdd), @(0xefde), @(0xefdf), @(0xefe0), @(0xefe1), @(0xefe2), @(0xefe3),
|
||||
@(0xefe4), @(0xefe5), @(0xefe6), @(0xefe7), @(0xefe8), @(0xefe9), @(0xefea), @(0xefeb),
|
||||
@(0xefec), @(0xefed), @(0xefee), @(0xefef), @(0xeff0), @(0xeff1), @(0xeff2), @(0xeff3),
|
||||
@(0xeff4), @(0xeff5), @(0xeff6), @(0xeff7), @(0xeff8), @(0xeff9), @(0xeffa), @(0xeffb),
|
||||
@(0xeffc), @(0xeffd), @(0xeffe), @(0xefff)
|
||||
]];
|
||||
|
||||
NSSet<NSNumber *> *const falseValids = storage_tests.false_valids();
|
||||
NSSet<NSNumber *> *const falseInvalids = storage_tests.false_invalids();
|
||||
|
||||
XCTAssert(!falseValids.count, "%@ opcodes should be invalid but aren't: %@", @(falseValids.count), falseValids.hexDump);
|
||||
|
||||
NSMutableSet<NSNumber *> *const decodedUndecodables = [undecodables mutableCopy];
|
||||
[decodedUndecodables minusSet:falseInvalids];
|
||||
XCTAssert(!decodedUndecodables.count, "This test considers these undecodable but they were decoded: %@", decodedUndecodables.hexDump);
|
||||
|
||||
NSMutableSet<NSNumber *> *const trimmedInvalids = [falseInvalids mutableCopy];
|
||||
[trimmedInvalids minusSet:undecodables];
|
||||
XCTAssert(!trimmedInvalids.count, "%@ opcodes should be valid but aren't: %@", @(trimmedInvalids.count), trimmedInvalids.hexDump);
|
||||
|
||||
// XCTAssert(!falseInvalids.count, "%@ opcodes should be valid but aren't: %@", @(falseInvalids.count), falseInvalids.hexDump);
|
||||
}
|
||||
|
||||
@end
|
@ -1,140 +0,0 @@
|
||||
//
|
||||
// ArrayBuilderTests.m
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 19/11/2016.
|
||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "ArrayBuilder.hpp"
|
||||
|
||||
static NSData *inputData, *outputData;
|
||||
|
||||
static void setData(bool is_input, uint8_t *data, size_t size)
|
||||
{
|
||||
NSData *dataObject = [NSData dataWithBytes:data length:size];
|
||||
if(is_input) inputData = dataObject; else outputData = dataObject;
|
||||
}
|
||||
|
||||
@interface ArrayBuilderTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation ArrayBuilderTests
|
||||
|
||||
+ (void)setUp
|
||||
{
|
||||
inputData = nil;
|
||||
outputData = nil;
|
||||
}
|
||||
|
||||
- (void)assertMonotonicForInputSize:(size_t)inputSize outputSize:(size_t)outputSize
|
||||
{
|
||||
XCTAssert(inputData != nil, @"Should have received some input data");
|
||||
XCTAssert(outputData != nil, @"Should have received some output data");
|
||||
|
||||
XCTAssert(inputData.length == inputSize, @"Input data should be %lu bytes long, was %lu", inputSize, (unsigned long)inputData.length);
|
||||
XCTAssert(outputData.length == outputSize, @"Output data should be %lu bytes long, was %lu", outputSize, (unsigned long)outputData.length);
|
||||
|
||||
if(inputData.length == inputSize && outputData.length == outputSize)
|
||||
{
|
||||
uint8_t *input = (uint8_t *)inputData.bytes;
|
||||
uint8_t *output = (uint8_t *)outputData.bytes;
|
||||
|
||||
for(int c = 0; c < inputSize; c++) XCTAssert(input[c] == c, @"Input item %d should be %d, was %d", c, c, input[c]);
|
||||
for(int c = 0; c < outputSize; c++) XCTAssert(output[c] == c + 0x80, @"Output item %d should be %d, was %d", c, c+0x80, output[c]);
|
||||
}
|
||||
}
|
||||
|
||||
- (std::function<void(uint8_t *input, size_t input_size, uint8_t *output, size_t output_size)>)emptyFlushFunction
|
||||
{
|
||||
return [=] (uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) {};
|
||||
}
|
||||
|
||||
- (void)testSingleWriteSingleFlush
|
||||
{
|
||||
Outputs::CRT::ArrayBuilder arrayBuilder(200, 100, setData);
|
||||
|
||||
uint8_t *input = arrayBuilder.get_input_storage(5);
|
||||
uint8_t *output = arrayBuilder.get_output_storage(3);
|
||||
|
||||
for(int c = 0; c < 5; c++) input[c] = c;
|
||||
for(int c = 0; c < 3; c++) output[c] = c + 0x80;
|
||||
|
||||
arrayBuilder.flush(self.emptyFlushFunction);
|
||||
arrayBuilder.submit();
|
||||
|
||||
[self assertMonotonicForInputSize:5 outputSize:3];
|
||||
}
|
||||
|
||||
- (void)testDoubleWriteSingleFlush
|
||||
{
|
||||
Outputs::CRT::ArrayBuilder arrayBuilder(200, 100, setData);
|
||||
uint8_t *input;
|
||||
uint8_t *output;
|
||||
|
||||
input = arrayBuilder.get_input_storage(2);
|
||||
output = arrayBuilder.get_output_storage(2);
|
||||
|
||||
for(int c = 0; c < 2; c++) input[c] = c;
|
||||
for(int c = 0; c < 2; c++) output[c] = c + 0x80;
|
||||
|
||||
input = arrayBuilder.get_input_storage(2);
|
||||
output = arrayBuilder.get_output_storage(2);
|
||||
|
||||
for(int c = 0; c < 2; c++) input[c] = c+2;
|
||||
for(int c = 0; c < 2; c++) output[c] = c+2 + 0x80;
|
||||
|
||||
arrayBuilder.flush(self.emptyFlushFunction);
|
||||
arrayBuilder.submit();
|
||||
|
||||
[self assertMonotonicForInputSize:4 outputSize:4];
|
||||
}
|
||||
|
||||
- (void)testSubmitWithoutFlush
|
||||
{
|
||||
Outputs::CRT::ArrayBuilder arrayBuilder(200, 100, setData);
|
||||
|
||||
arrayBuilder.get_input_storage(5);
|
||||
arrayBuilder.get_input_storage(8);
|
||||
arrayBuilder.get_output_storage(6);
|
||||
arrayBuilder.get_input_storage(12);
|
||||
arrayBuilder.get_output_storage(3);
|
||||
|
||||
arrayBuilder.submit();
|
||||
|
||||
XCTAssert(inputData.length == 0, @"No input data should have been received; %lu bytes were received", (unsigned long)inputData.length);
|
||||
XCTAssert(outputData.length == 0, @"No output data should have been received; %lu bytes were received", (unsigned long)outputData.length);
|
||||
|
||||
arrayBuilder.flush(self.emptyFlushFunction);
|
||||
arrayBuilder.submit();
|
||||
|
||||
XCTAssert(inputData.length == 25, @"All input data should have been received; %lu bytes were received", (unsigned long)inputData.length);
|
||||
XCTAssert(outputData.length == 9, @"All output data should have been received; %lu bytes were received", (unsigned long)outputData.length);
|
||||
}
|
||||
|
||||
- (void)testSubmitContinuity
|
||||
{
|
||||
Outputs::CRT::ArrayBuilder arrayBuilder(200, 100, setData);
|
||||
|
||||
arrayBuilder.get_input_storage(5);
|
||||
arrayBuilder.get_output_storage(5);
|
||||
|
||||
arrayBuilder.flush(self.emptyFlushFunction);
|
||||
|
||||
uint8_t *input = arrayBuilder.get_input_storage(5);
|
||||
uint8_t *output = arrayBuilder.get_output_storage(5);
|
||||
|
||||
arrayBuilder.submit();
|
||||
|
||||
for(int c = 0; c < 5; c++) input[c] = c;
|
||||
for(int c = 0; c < 5; c++) output[c] = c + 0x80;
|
||||
|
||||
arrayBuilder.flush(self.emptyFlushFunction);
|
||||
arrayBuilder.submit();
|
||||
|
||||
[self assertMonotonicForInputSize:5 outputSize:5];
|
||||
}
|
||||
|
||||
@end
|
59
OSBindings/Mac/Clock SignalTests/Comparative68000.hpp
Normal file
59
OSBindings/Mac/Clock SignalTests/Comparative68000.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// Comparative68000.hpp
|
||||
// Clock SignalTests
|
||||
//
|
||||
// Created by Thomas Harte on 29/04/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef Comparative68000_hpp
|
||||
#define Comparative68000_hpp
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "68000.hpp"
|
||||
|
||||
class ComparativeBusHandler: public CPU::MC68000::BusHandler {
|
||||
public:
|
||||
ComparativeBusHandler(const char *trace_name) {
|
||||
trace = gzopen(trace_name, "rt");
|
||||
}
|
||||
|
||||
~ComparativeBusHandler() {
|
||||
gzclose(trace);
|
||||
}
|
||||
|
||||
void will_perform(uint32_t address, uint16_t opcode) {
|
||||
// Obtain the next line from the trace file.
|
||||
char correct_state[300] = "\n";
|
||||
gzgets(trace, correct_state, sizeof(correct_state));
|
||||
++line_count;
|
||||
|
||||
// Generate state locally.
|
||||
const auto state = get_state();
|
||||
char local_state[300];
|
||||
sprintf(local_state, "%04x: %02x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
|
||||
address,
|
||||
state.status,
|
||||
state.data[0], state.data[1], state.data[2], state.data[3], state.data[4], state.data[5], state.data[6], state.data[7],
|
||||
state.address[0], state.address[1], state.address[2], state.address[3], state.address[4], state.address[5], state.address[6],
|
||||
(state.status & 0x2000) ? state.supervisor_stack_pointer : state.user_stack_pointer
|
||||
);
|
||||
|
||||
// Check that the two coincide.
|
||||
if(strcmp(correct_state, local_state)) {
|
||||
fprintf(stderr, "Diverges at line %d\n", line_count);
|
||||
fprintf(stderr, "Good: %s", correct_state);
|
||||
fprintf(stderr, "Bad: %s", local_state);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
virtual CPU::MC68000::ProcessorState get_state() = 0;
|
||||
|
||||
private:
|
||||
int line_count = 0;
|
||||
gzFile trace;
|
||||
};
|
||||
|
||||
#endif /* Comparative68000_hpp */
|
120
OSBindings/Mac/Clock SignalTests/EmuTOSTests.mm
Normal file
120
OSBindings/Mac/Clock SignalTests/EmuTOSTests.mm
Normal file
@ -0,0 +1,120 @@
|
||||
//
|
||||
// EmuTOSTests.m
|
||||
// Clock SignalTests
|
||||
//
|
||||
// Created by Thomas Harte on 10/03/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "68000.hpp"
|
||||
#include "Comparative68000.hpp"
|
||||
#include "CSROMFetcher.hpp"
|
||||
|
||||
class EmuTOS: public ComparativeBusHandler {
|
||||
public:
|
||||
EmuTOS(const std::vector<uint8_t> &emuTOS, const char *trace_name) : ComparativeBusHandler(trace_name), m68000_(*this) {
|
||||
assert(!(emuTOS.size() & 1));
|
||||
emuTOS_.resize(emuTOS.size() / 2);
|
||||
|
||||
for(size_t c = 0; c < emuTOS_.size(); ++c) {
|
||||
emuTOS_[c] = (emuTOS[c << 1] << 8) | emuTOS[(c << 1) + 1];
|
||||
}
|
||||
}
|
||||
|
||||
void run_for(HalfCycles cycles) {
|
||||
m68000_.run_for(cycles);
|
||||
}
|
||||
|
||||
CPU::MC68000::ProcessorState get_state() override {
|
||||
return m68000_.get_state();
|
||||
}
|
||||
|
||||
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
|
||||
const uint32_t address = cycle.word_address();
|
||||
uint32_t word_address = address;
|
||||
|
||||
// As much about the Atari ST's memory map as is relevant here: the ROM begins
|
||||
// at 0xfc0000, and the first eight bytes are mirrored to the first four memory
|
||||
// addresses in order for /RESET to work properly. RAM otherwise fills the first
|
||||
// 512kb of the address space. Trying to write to ROM raises a bus error.
|
||||
|
||||
const bool is_rom = (word_address >= (0xfc0000 >> 1) && word_address < (0xff0000 >> 1)) || word_address < 4;
|
||||
const bool is_ram = word_address < ram_.size();
|
||||
const bool is_peripheral = !is_rom && !is_ram;
|
||||
|
||||
uint16_t *const base = is_rom ? emuTOS_.data() : ram_.data();
|
||||
if(is_rom) {
|
||||
word_address %= emuTOS_.size();
|
||||
} else {
|
||||
word_address %= ram_.size();
|
||||
}
|
||||
|
||||
using Microcycle = CPU::MC68000::Microcycle;
|
||||
if(cycle.data_select_active()) {
|
||||
uint16_t peripheral_result = 0xffff;
|
||||
if(is_peripheral) {
|
||||
switch(address & 0x7ff) {
|
||||
// A hard-coded value for TIMER B.
|
||||
case (0xa21 >> 1):
|
||||
peripheral_result = 0x00000001;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
||||
default: break;
|
||||
|
||||
case Microcycle::SelectWord | Microcycle::Read:
|
||||
cycle.value->full = is_peripheral ? peripheral_result : base[word_address];
|
||||
break;
|
||||
case Microcycle::SelectByte | Microcycle::Read:
|
||||
cycle.value->halves.low = (is_peripheral ? peripheral_result : base[word_address]) >> cycle.byte_shift();
|
||||
break;
|
||||
case Microcycle::SelectWord:
|
||||
base[word_address] = cycle.value->full;
|
||||
break;
|
||||
case Microcycle::SelectByte:
|
||||
base[word_address] = (cycle.value->halves.low << cycle.byte_shift()) | (base[word_address] & (0xffff ^ cycle.byte_mask()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::MC68000::Processor<EmuTOS, true, true> m68000_;
|
||||
|
||||
std::vector<uint16_t> emuTOS_;
|
||||
std::array<uint16_t, 256*1024> ram_;
|
||||
};
|
||||
|
||||
@interface EmuTOSTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation EmuTOSTests {
|
||||
std::unique_ptr<EmuTOS> _machine;
|
||||
}
|
||||
|
||||
- (void)testImage:(NSString *)image trace:(NSString *)trace length:(int)length {
|
||||
const auto roms = CSROMFetcher()("AtariST", { image.UTF8String });
|
||||
NSString *const traceLocation = [[NSBundle bundleForClass:[self class]] pathForResource:trace ofType:@"trace.txt.gz"];
|
||||
_machine.reset(new EmuTOS(*roms[0], traceLocation.UTF8String));
|
||||
_machine->run_for(HalfCycles(length));
|
||||
}
|
||||
|
||||
- (void)testEmuTOSStartup {
|
||||
[self testImage:@"etos192uk.img" trace:@"etos192uk" length:313490];
|
||||
// TODO: assert that machine is now STOPped.
|
||||
}
|
||||
|
||||
- (void)testTOSStartup {
|
||||
[self testImage:@"tos100.img" trace:@"tos100" length:54011091];
|
||||
}
|
||||
|
||||
@end
|
BIN
OSBindings/Mac/Clock SignalTests/QL Startup/qltrace.txt.gz
Normal file
BIN
OSBindings/Mac/Clock SignalTests/QL Startup/qltrace.txt.gz
Normal file
Binary file not shown.
112
OSBindings/Mac/Clock SignalTests/QLTests.mm
Normal file
112
OSBindings/Mac/Clock SignalTests/QLTests.mm
Normal file
@ -0,0 +1,112 @@
|
||||
//
|
||||
// EmuTOSTests.m
|
||||
// Clock SignalTests
|
||||
//
|
||||
// Created by Thomas Harte on 10/03/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include "68000.hpp"
|
||||
#include "Comparative68000.hpp"
|
||||
#include "CSROMFetcher.hpp"
|
||||
|
||||
class QL: public ComparativeBusHandler {
|
||||
public:
|
||||
QL(const std::vector<uint8_t> &rom, const char *trace_name) : ComparativeBusHandler(trace_name), m68000_(*this) {
|
||||
assert(!(rom.size() & 1));
|
||||
rom_.resize(rom.size() / 2);
|
||||
|
||||
for(size_t c = 0; c < rom_.size(); ++c) {
|
||||
rom_[c] = (rom[c << 1] << 8) | rom[(c << 1) + 1];
|
||||
}
|
||||
}
|
||||
|
||||
void run_for(HalfCycles cycles) {
|
||||
m68000_.run_for(cycles);
|
||||
}
|
||||
|
||||
CPU::MC68000::ProcessorState get_state() override {
|
||||
return m68000_.get_state();
|
||||
}
|
||||
|
||||
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
|
||||
const uint32_t address = cycle.word_address();
|
||||
uint32_t word_address = address;
|
||||
|
||||
// QL memory map: ROM is in the lowest area; RAM is from 0x20000.
|
||||
const bool is_rom = word_address < rom_.size();
|
||||
const bool is_ram = word_address >= 0x10000 && word_address < 0x10000+ram_.size();
|
||||
const bool is_peripheral = !is_ram && !is_rom;
|
||||
|
||||
uint16_t *const base = is_rom ? rom_.data() : ram_.data();
|
||||
if(is_rom) {
|
||||
word_address %= rom_.size();
|
||||
}
|
||||
if(is_ram) {
|
||||
word_address %= ram_.size();
|
||||
}
|
||||
|
||||
using Microcycle = CPU::MC68000::Microcycle;
|
||||
if(cycle.data_select_active()) {
|
||||
uint16_t peripheral_result = 0xffff;
|
||||
|
||||
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
||||
default: break;
|
||||
|
||||
case Microcycle::SelectWord | Microcycle::Read:
|
||||
cycle.value->full = is_peripheral ? peripheral_result : base[word_address];
|
||||
break;
|
||||
case Microcycle::SelectByte | Microcycle::Read:
|
||||
cycle.value->halves.low = (is_peripheral ? peripheral_result : base[word_address]) >> cycle.byte_shift();
|
||||
break;
|
||||
case Microcycle::SelectWord:
|
||||
assert(!(is_rom && !is_peripheral));
|
||||
if(!is_peripheral) base[word_address] = cycle.value->full;
|
||||
break;
|
||||
case Microcycle::SelectByte:
|
||||
assert(!(is_rom && !is_peripheral));
|
||||
if(!is_peripheral) base[word_address] = (cycle.value->halves.low << cycle.byte_shift()) | (base[word_address] & (0xffff ^ cycle.byte_mask()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
private:
|
||||
CPU::MC68000::Processor<QL, true, true> m68000_;
|
||||
|
||||
std::vector<uint16_t> rom_;
|
||||
std::array<uint16_t, 64*1024> ram_;
|
||||
};
|
||||
|
||||
@interface QLTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation QLTests {
|
||||
std::unique_ptr<QL> _machine;
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests the progression of Clock Signal's 68000 through the Sinclair QL's ROM against a known-good trace.
|
||||
*/
|
||||
- (void)testStartup {
|
||||
const auto roms = CSROMFetcher()("SinclairQL", {"js.rom"});
|
||||
NSString *const traceLocation = [[NSBundle bundleForClass:[self class]] pathForResource:@"qltrace" ofType:@".txt.gz"];
|
||||
_machine.reset(new QL(*roms[0], traceLocation.UTF8String));
|
||||
|
||||
// This is how many cycles it takes to exhaust the supplied trace file.
|
||||
_machine->run_for(HalfCycles(23923180));
|
||||
}
|
||||
|
||||
@end
|
Binary file not shown.
BIN
OSBindings/Mac/Clock SignalTests/TOS Startup/tos100.trace.txt.gz
Normal file
BIN
OSBindings/Mac/Clock SignalTests/TOS Startup/tos100.trace.txt.gz
Normal file
Binary file not shown.
@ -24,6 +24,7 @@ class Z80MachineCycleTests: XCTestCase {
|
||||
case .portRead: opName = "i"
|
||||
case .portWrite: opName = "o"
|
||||
case .internalOperation: opName = "iop"
|
||||
default: opName = "?"
|
||||
}
|
||||
return "\(opName) \(length)"
|
||||
}
|
||||
@ -35,7 +36,7 @@ class Z80MachineCycleTests: XCTestCase {
|
||||
// Create a machine and install the supplied program at address 0, setting the PC to run from there
|
||||
let machine = CSTestMachineZ80()
|
||||
machine.setValue(0x0000, for: .programCounter)
|
||||
machine.setData(Data(bytes: program), atAddress: 0x0000)
|
||||
machine.setData(Data(_: program), atAddress: 0x0000)
|
||||
|
||||
// Figure out the total number of cycles implied by the bus cycles
|
||||
var totalCycles: Int32 = 0
|
||||
|
@ -14,7 +14,7 @@ class Z80MemptrTests: XCTestCase {
|
||||
private func test(program : [UInt8], length : Int32, initialValue : UInt16) -> UInt16 {
|
||||
// Create a machine and install the supplied program at address 0, setting the PC to run from there
|
||||
machine.setValue(0x0000, for: .programCounter)
|
||||
machine.setData(Data(bytes: program), atAddress: 0x0000)
|
||||
machine.setData(Data(_: program), atAddress: 0x0000)
|
||||
|
||||
// Set the initial value of memptr, run for the requested number of cycles,
|
||||
// return the new value
|
||||
@ -316,7 +316,7 @@ class Z80MemptrTests: XCTestCase {
|
||||
let program: [UInt8] = [
|
||||
0xed, 0xa1
|
||||
]
|
||||
machine.setData(Data(bytes: program), atAddress: 0x0000)
|
||||
machine.setData(Data(_: program), atAddress: 0x0000)
|
||||
machine.setValue(0, for: .memPtr)
|
||||
|
||||
for c in 1 ..< 65536 {
|
||||
@ -332,7 +332,7 @@ class Z80MemptrTests: XCTestCase {
|
||||
let program: [UInt8] = [
|
||||
0xed, 0xa9
|
||||
]
|
||||
machine.setData(Data(bytes: program), atAddress: 0x0000)
|
||||
machine.setData(Data(_: program), atAddress: 0x0000)
|
||||
machine.setValue(0, for: .memPtr)
|
||||
|
||||
for c in 1 ..< 65536 {
|
||||
|
@ -67,6 +67,7 @@ SOURCES += glob.glob('../../Outputs/OpenGL/*.cpp')
|
||||
SOURCES += glob.glob('../../Outputs/OpenGL/Primitives/*.cpp')
|
||||
|
||||
SOURCES += glob.glob('../../Processors/6502/Implementation/*.cpp')
|
||||
SOURCES += glob.glob('../../Processors/68000/Implementation/*.cpp')
|
||||
SOURCES += glob.glob('../../Processors/Z80/Implementation/*.cpp')
|
||||
|
||||
SOURCES += glob.glob('../../SignalProcessing/*.cpp')
|
||||
|
@ -23,8 +23,8 @@
|
||||
#include <ios>
|
||||
#include <iomanip>
|
||||
|
||||
#define PADHEX(n) std::hex << std::setw(n) << std::right << std::setfill('0')
|
||||
#define PADDEC(n) std::dec << std::setw(n) << std::right << std::setfill('0')
|
||||
#define PADHEX(n) std::hex << std::setfill('0') << std::setw(n)
|
||||
#define PADDEC(n) std::dec << std::setfill('0') << std::setw(n)
|
||||
|
||||
#define LOG(x) std::cout << x << std::endl
|
||||
#define LOGNBR(x) std::cout << x
|
||||
|
@ -28,7 +28,7 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
// These plus program below act to give the compiler permission to update these values
|
||||
// without touching the class storage (i.e. it explicitly says they need be completely up
|
||||
// to date in this stack frame only); which saves some complicated addressing
|
||||
RegisterPair nextAddress = next_address_;
|
||||
RegisterPair16 nextAddress = next_address_;
|
||||
BusOperation nextBusOperation = next_bus_operation_;
|
||||
uint16_t busAddress = bus_address_;
|
||||
uint8_t *busValue = bus_value_;
|
||||
@ -147,8 +147,8 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
}
|
||||
|
||||
case CycleIncPCPushPCH: pc_.full++; // deliberate fallthrough
|
||||
case CyclePushPCH: push(pc_.bytes.high); break;
|
||||
case CyclePushPCL: push(pc_.bytes.low); break;
|
||||
case CyclePushPCH: push(pc_.halves.high); break;
|
||||
case CyclePushPCL: push(pc_.halves.low); break;
|
||||
case CyclePushOperand: push(operand_); break;
|
||||
case CyclePushA: push(a_); break;
|
||||
case CyclePushX: push(x_); break;
|
||||
@ -175,8 +175,8 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
continue;
|
||||
case OperationNMIPickVector: nextAddress.full = 0xfffa; continue;
|
||||
case OperationRSTPickVector: nextAddress.full = 0xfffc; continue;
|
||||
case CycleReadVectorLow: read_mem(pc_.bytes.low, nextAddress.full); break;
|
||||
case CycleReadVectorHigh: read_mem(pc_.bytes.high, nextAddress.full+1); break;
|
||||
case CycleReadVectorLow: read_mem(pc_.halves.low, nextAddress.full); break;
|
||||
case CycleReadVectorHigh: read_mem(pc_.halves.high, nextAddress.full+1); break;
|
||||
case OperationSetIRQFlags:
|
||||
inverse_interrupt_flag_ = 0;
|
||||
if(is_65c02(personality)) decimal_flag_ = false;
|
||||
@ -185,8 +185,8 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
if(is_65c02(personality)) decimal_flag_ = false;
|
||||
continue;
|
||||
|
||||
case CyclePullPCL: s_++; read_mem(pc_.bytes.low, s_ | 0x100); break;
|
||||
case CyclePullPCH: s_++; read_mem(pc_.bytes.high, s_ | 0x100); break;
|
||||
case CyclePullPCL: s_++; read_mem(pc_.halves.low, s_ | 0x100); break;
|
||||
case CyclePullPCH: s_++; read_mem(pc_.halves.high, s_ | 0x100); break;
|
||||
case CyclePullA: s_++; read_mem(a_, s_ | 0x100); break;
|
||||
case CyclePullX: s_++; read_mem(x_, s_ | 0x100); break;
|
||||
case CyclePullY: s_++; read_mem(y_, s_ | 0x100); break;
|
||||
@ -198,11 +198,11 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
case OperationSetFlagsFromX: zero_result_ = negative_result_ = x_; continue;
|
||||
case OperationSetFlagsFromY: zero_result_ = negative_result_ = y_; continue;
|
||||
|
||||
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
|
||||
case CycleReadPCLFromAddress: read_mem(pc_.bytes.low, address_.full); break;
|
||||
case CycleReadPCHFromAddressLowInc: address_.bytes.low++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressFixed: if(!address_.bytes.low) address_.bytes.high++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressInc: address_.full++; read_mem(pc_.bytes.high, address_.full); break;
|
||||
case CycleIncrementPCAndReadStack: pc_.full++; throwaway_read(s_ | 0x100); break;
|
||||
case CycleReadPCLFromAddress: read_mem(pc_.halves.low, address_.full); break;
|
||||
case CycleReadPCHFromAddressLowInc: address_.halves.low++; read_mem(pc_.halves.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressFixed: if(!address_.halves.low) address_.halves.high++; read_mem(pc_.halves.high, address_.full); break;
|
||||
case CycleReadPCHFromAddressInc: address_.full++; read_mem(pc_.halves.high, address_.full); break;
|
||||
|
||||
case CycleReadAndIncrementPC: {
|
||||
uint16_t oldPC = pc_.full;
|
||||
@ -244,10 +244,10 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
case OperationSTY: operand_ = y_; continue;
|
||||
case OperationSTZ: operand_ = 0; continue;
|
||||
case OperationSAX: operand_ = a_ & x_; continue;
|
||||
case OperationSHA: operand_ = a_ & x_ & (address_.bytes.high+1); continue;
|
||||
case OperationSHX: operand_ = x_ & (address_.bytes.high+1); continue;
|
||||
case OperationSHY: operand_ = y_ & (address_.bytes.high+1); continue;
|
||||
case OperationSHS: s_ = a_ & x_; operand_ = s_ & (address_.bytes.high+1); continue;
|
||||
case OperationSHA: operand_ = a_ & x_ & (address_.halves.high+1); continue;
|
||||
case OperationSHX: operand_ = x_ & (address_.halves.high+1); continue;
|
||||
case OperationSHY: operand_ = y_ & (address_.halves.high+1); continue;
|
||||
case OperationSHS: s_ = a_ & x_; operand_ = s_ & (address_.halves.high+1); continue;
|
||||
|
||||
case OperationLXA:
|
||||
a_ = x_ = (a_ | 0xee) & operand_;
|
||||
@ -475,28 +475,28 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
|
||||
case CycleAddXToAddressLow:
|
||||
nextAddress.full = address_.full + x_;
|
||||
address_.bytes.low = nextAddress.bytes.low;
|
||||
if(address_.bytes.high != nextAddress.bytes.high) {
|
||||
address_.halves.low = nextAddress.halves.low;
|
||||
if(address_.halves.high != nextAddress.halves.high) {
|
||||
page_crossing_stall_read();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case CycleAddXToAddressLowRead:
|
||||
nextAddress.full = address_.full + x_;
|
||||
address_.bytes.low = nextAddress.bytes.low;
|
||||
address_.halves.low = nextAddress.halves.low;
|
||||
page_crossing_stall_read();
|
||||
break;
|
||||
case CycleAddYToAddressLow:
|
||||
nextAddress.full = address_.full + y_;
|
||||
address_.bytes.low = nextAddress.bytes.low;
|
||||
if(address_.bytes.high != nextAddress.bytes.high) {
|
||||
address_.halves.low = nextAddress.halves.low;
|
||||
if(address_.halves.high != nextAddress.halves.high) {
|
||||
page_crossing_stall_read();
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case CycleAddYToAddressLowRead:
|
||||
nextAddress.full = address_.full + y_;
|
||||
address_.bytes.low = nextAddress.bytes.low;
|
||||
address_.halves.low = nextAddress.halves.low;
|
||||
page_crossing_stall_read();
|
||||
break;
|
||||
|
||||
@ -507,37 +507,37 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
continue;
|
||||
case CycleIncrementPCFetchAddressLowFromOperand:
|
||||
pc_.full++;
|
||||
read_mem(address_.bytes.low, operand_);
|
||||
read_mem(address_.halves.low, operand_);
|
||||
break;
|
||||
case CycleAddXToOperandFetchAddressLow:
|
||||
operand_ += x_;
|
||||
read_mem(address_.bytes.low, operand_);
|
||||
read_mem(address_.halves.low, operand_);
|
||||
break;
|
||||
case CycleFetchAddressLowFromOperand:
|
||||
read_mem(address_.bytes.low, operand_);
|
||||
read_mem(address_.halves.low, operand_);
|
||||
break;
|
||||
case CycleIncrementOperandFetchAddressHigh:
|
||||
operand_++;
|
||||
read_mem(address_.bytes.high, operand_);
|
||||
read_mem(address_.halves.high, operand_);
|
||||
break;
|
||||
case CycleIncrementPCReadPCHLoadPCL: // deliberate fallthrough
|
||||
pc_.full++;
|
||||
case CycleReadPCHLoadPCL: {
|
||||
uint16_t oldPC = pc_.full;
|
||||
pc_.bytes.low = operand_;
|
||||
read_mem(pc_.bytes.high, oldPC);
|
||||
pc_.halves.low = operand_;
|
||||
read_mem(pc_.halves.high, oldPC);
|
||||
} break;
|
||||
|
||||
case CycleReadAddressHLoadAddressL:
|
||||
address_.bytes.low = operand_; pc_.full++;
|
||||
read_mem(address_.bytes.high, pc_.full);
|
||||
address_.halves.low = operand_; pc_.full++;
|
||||
read_mem(address_.halves.high, pc_.full);
|
||||
break;
|
||||
|
||||
case CycleLoadAddressAbsolute: {
|
||||
uint16_t nextPC = pc_.full+1;
|
||||
pc_.full += 2;
|
||||
address_.bytes.low = operand_;
|
||||
read_mem(address_.bytes.high, nextPC);
|
||||
address_.halves.low = operand_;
|
||||
read_mem(address_.halves.high, nextPC);
|
||||
} break;
|
||||
|
||||
case OperationLoadAddressZeroPage:
|
||||
@ -583,8 +583,8 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
|
||||
case CycleAddSignedOperandToPC:
|
||||
nextAddress.full = static_cast<uint16_t>(pc_.full + (int8_t)operand_);
|
||||
pc_.bytes.low = nextAddress.bytes.low;
|
||||
if(nextAddress.bytes.high != pc_.bytes.high) {
|
||||
pc_.halves.low = nextAddress.halves.low;
|
||||
if(nextAddress.halves.high != pc_.halves.high) {
|
||||
uint16_t halfUpdatedPc = pc_.full;
|
||||
pc_.full = nextAddress.full;
|
||||
throwaway_read(halfUpdatedPc);
|
||||
@ -598,7 +598,7 @@ template <Personality personality, typename T, bool uses_ready_line> void Proces
|
||||
continue;
|
||||
|
||||
case CycleFetchFromHalfUpdatedPC: {
|
||||
uint16_t halfUpdatedPc = static_cast<uint16_t>(((pc_.bytes.low + (int8_t)operand_) & 0xff) | (pc_.bytes.high << 8));
|
||||
uint16_t halfUpdatedPc = static_cast<uint16_t>(((pc_.halves.low + (int8_t)operand_) & 0xff) | (pc_.halves.high << 8));
|
||||
throwaway_read(halfUpdatedPc);
|
||||
} break;
|
||||
|
||||
|
@ -205,7 +205,7 @@ class ProcessorStorage {
|
||||
/*
|
||||
Storage for the 6502 registers; F is stored as individual flags.
|
||||
*/
|
||||
RegisterPair pc_, last_operation_pc_;
|
||||
RegisterPair16 pc_, last_operation_pc_;
|
||||
uint8_t a_, x_, y_, s_ = 0;
|
||||
uint8_t carry_flag_, negative_result_, zero_result_, decimal_flag_, overflow_flag_, inverse_interrupt_flag_ = 0;
|
||||
|
||||
@ -213,7 +213,7 @@ class ProcessorStorage {
|
||||
Temporary state for the micro programs.
|
||||
*/
|
||||
uint8_t operation_, operand_;
|
||||
RegisterPair address_, next_address_;
|
||||
RegisterPair16 address_, next_address_;
|
||||
|
||||
/*
|
||||
Temporary storage allowing a common dispatch point for calling perform_bus_operation;
|
||||
|
294
Processors/68000/68000.hpp
Normal file
294
Processors/68000/68000.hpp
Normal file
@ -0,0 +1,294 @@
|
||||
//
|
||||
// 68000.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 08/03/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MC68000_h
|
||||
#define MC68000_h
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
#include "../RegisterSizes.hpp"
|
||||
|
||||
namespace CPU {
|
||||
namespace MC68000 {
|
||||
|
||||
/*!
|
||||
A microcycle is an atomic unit of 68000 bus activity — it is a single item large enough
|
||||
fully to specify a sequence of bus events that occur without any possible interruption.
|
||||
|
||||
Concretely, a standard read cycle breaks down into at least two microcycles:
|
||||
|
||||
1) a 4 half-cycle length microcycle in which the address strobe is signalled; and
|
||||
2) a 4 half-cycle length microcycle in which at least one of the data strobes is
|
||||
signalled, and the data bus is sampled.
|
||||
|
||||
That is, assuming DTack were signalled when microcycle (1) ended. If not then additional
|
||||
wait state microcycles would fall between those two parts.
|
||||
|
||||
The 68000 data sheet defines when the address becomes valid during microcycle (1), and
|
||||
when the address strobe is actually asserted. But those timings are fixed. So simply
|
||||
telling you that this was a microcycle during which the address trobe was signalled is
|
||||
sufficient fully to describe the bus activity.
|
||||
|
||||
(Aside: see the 68000 template's definition for options re: implicit DTack; if your
|
||||
68000 owner can always predict exactly how long it will hold DTack following observation
|
||||
of an address-strobing microcycle, it can just supply those periods for accounting and
|
||||
avoid the runtime cost of actual DTack emulation. But such as the bus allows.)
|
||||
*/
|
||||
struct Microcycle {
|
||||
/// A NewAddress cycle is one in which the address strobe is initially low but becomes high;
|
||||
/// this correlates to states 0 to 5 of a standard read/write cycle.
|
||||
static const int NewAddress = 1 << 0;
|
||||
|
||||
/// A SameAddress cycle is one in which the address strobe is continuously asserted, but neither
|
||||
/// of the data strobes are.
|
||||
static const int SameAddress = 1 << 1;
|
||||
|
||||
/// A Reset cycle is one in which the RESET output is asserted.
|
||||
static const int Reset = 1 << 2;
|
||||
|
||||
/// Indicates that the address and both data select strobes are active.
|
||||
static const int SelectWord = 1 << 3;
|
||||
|
||||
/// Indicates that the address strobe and exactly one of the data strobes are active; you can determine
|
||||
/// which by inspecting the low bit of the provided address. The RW line indicates a read.
|
||||
static const int SelectByte = 1 << 4;
|
||||
|
||||
/// If set, indicates a read. Otherwise, a write.
|
||||
static const int Read = 1 << 5;
|
||||
|
||||
/// Contains the value of line FC0 if it is not implicit via InterruptAcknowledge.
|
||||
static const int IsData = 1 << 6;
|
||||
|
||||
/// Contains the value of line FC1 if it is not implicit via InterruptAcknowledge.
|
||||
static const int IsProgram = 1 << 7;
|
||||
|
||||
/// The interrupt acknowledge cycle is that during which the 68000 seeks to obtain the vector for
|
||||
/// an interrupt it plans to observe. Noted on a real 68000 by all FCs being set to 1.
|
||||
static const int InterruptAcknowledge = 1 << 8;
|
||||
|
||||
/// Represents the state of the 68000's valid memory address line — indicating whether this microcycle
|
||||
/// is synchronised with the E clock to satisfy a valid peripheral address request.
|
||||
static const int IsPeripheral = 1 << 9;
|
||||
|
||||
/// Contains a valid combination of the various static const int flags, describing the operation
|
||||
/// performed by this Microcycle.
|
||||
int operation = 0;
|
||||
|
||||
/// Describes the duration of this Microcycle.
|
||||
HalfCycles length = HalfCycles(4);
|
||||
|
||||
/*!
|
||||
For expediency, this provides a full 32-bit byte-resolution address — e.g.
|
||||
if reading indirectly via an address register, this will indicate the full
|
||||
value of the address register.
|
||||
|
||||
The receiver should ignore bits 0 and 24+. Use word_address() automatically
|
||||
to obtain the only the 68000's real address lines, giving a 23-bit address
|
||||
at word resolution.
|
||||
*/
|
||||
const uint32_t *address = nullptr;
|
||||
|
||||
/*!
|
||||
If this is a write cycle, dereference value to get the value loaded onto
|
||||
the data bus.
|
||||
|
||||
If this is a read cycle, write the value on the data bus to it.
|
||||
|
||||
Otherwise, this value is undefined.
|
||||
|
||||
Byte values are provided via @c value.halves.low. @c value.halves.high is undefined.
|
||||
This is true regardless of whether the upper or lower byte of a word is being
|
||||
accessed.
|
||||
|
||||
Word values occupy the entirety of @c value.full.
|
||||
*/
|
||||
RegisterPair16 *value = nullptr;
|
||||
|
||||
/// @returns @c true if two Microcycles are equal; @c false otherwise.
|
||||
bool operator ==(const Microcycle &rhs) const {
|
||||
if(value != rhs.value) return false;
|
||||
if(address != rhs.address) return false;
|
||||
if(length != rhs.length) return false;
|
||||
if(operation != rhs.operation) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Various inspectors.
|
||||
|
||||
/*! @returns true if any data select line is active; @c false otherwise. */
|
||||
inline bool data_select_active() const {
|
||||
return bool(operation & (SelectWord | SelectByte | InterruptAcknowledge));
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns 0 if this byte access wants the low part of a 16-bit word; 8 if it wants the high part.
|
||||
*/
|
||||
inline unsigned int byte_shift() const {
|
||||
return (((*address) & 1) << 3) ^ 8;
|
||||
}
|
||||
|
||||
/*!
|
||||
Obtains the mask to apply to a word that will leave only the byte this microcycle is selecting.
|
||||
|
||||
@returns 0x00ff if this byte access wants the low part of a 16-bit word; 0xff00 if it wants the high part.
|
||||
*/
|
||||
inline uint16_t byte_mask() const {
|
||||
return uint16_t(0xff00) >> (((*address) & 1) << 3);
|
||||
}
|
||||
|
||||
/*!
|
||||
Obtains the mask to apply to a word that will leave only the byte this microcycle **isn't** selecting.
|
||||
i.e. this is the part of a word that should be untouched by this microcycle.
|
||||
|
||||
@returns 0xff00 if this byte access wants the low part of a 16-bit word; 0x00ff if it wants the high part.
|
||||
*/
|
||||
inline uint16_t untouched_byte_mask() const {
|
||||
return uint16_t(uint16_t(0xff) << (((*address) & 1) << 3));
|
||||
}
|
||||
|
||||
/*!
|
||||
Assuming this cycle is a byte write, mutates @c destination by writing the byte to the proper upper or
|
||||
lower part, retaining the other half.
|
||||
*/
|
||||
uint16_t write_byte(uint16_t destination) const {
|
||||
return uint16_t((destination & untouched_byte_mask()) | (value->halves.low << byte_shift()));
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns non-zero if this is a byte read and 68000 LDS is asserted.
|
||||
*/
|
||||
inline int lower_data_select() const {
|
||||
return (operation & SelectByte) & ((*address & 1) << 3);
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns non-zero if this is a byte read and 68000 UDS is asserted.
|
||||
*/
|
||||
inline int upper_data_select() const {
|
||||
return (operation & SelectByte) & ~((*address & 1) << 3);
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns the address being accessed at the precision a 68000 supplies it —
|
||||
only 24 address bit precision, with the low bit shifted out. So it's the
|
||||
68000 address at word precision: address 0 is the first word in the address
|
||||
space, address 1 is the second word (i.e. the third and fourth bytes) in
|
||||
the address space, etc.
|
||||
*/
|
||||
uint32_t word_address() const {
|
||||
return (address ? (*address) & 0x00fffffe : 0) >> 1;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
This is the prototype for a 68000 bus handler; real bus handlers can descend from this
|
||||
in order to get default implementations of any changes that may occur in the expected interface.
|
||||
*/
|
||||
class BusHandler {
|
||||
public:
|
||||
/*!
|
||||
Provides the bus handler with a single Microcycle to 'perform'.
|
||||
|
||||
FC0 and FC1 are provided inside the microcycle as the IsData and IsProgram
|
||||
flags; FC2 is provided here as is_supervisor — it'll be either 0 or 1.
|
||||
*/
|
||||
HalfCycles perform_bus_operation(const Microcycle &cycle, int is_supervisor) {
|
||||
return HalfCycles(0);
|
||||
}
|
||||
|
||||
void flush() {}
|
||||
|
||||
/*!
|
||||
Provides information about the path of execution if enabled via the template.
|
||||
*/
|
||||
void will_perform(uint32_t address, uint16_t opcode) {}
|
||||
};
|
||||
|
||||
#include "Implementation/68000Storage.hpp"
|
||||
|
||||
class ProcessorBase: public ProcessorStorage {
|
||||
};
|
||||
|
||||
struct ProcessorState {
|
||||
uint32_t data[8];
|
||||
uint32_t address[7];
|
||||
uint32_t user_stack_pointer, supervisor_stack_pointer;
|
||||
uint32_t program_counter;
|
||||
uint16_t status;
|
||||
|
||||
// TODO: More state needed to indicate current instruction, the processor's
|
||||
// progress through it, and anything it has fetched so far.
|
||||
// uint16_t current_instruction;
|
||||
};
|
||||
|
||||
template <class T, bool dtack_is_implicit, bool signal_will_perform = false> class Processor: public ProcessorBase {
|
||||
public:
|
||||
Processor(T &bus_handler) : ProcessorBase(), bus_handler_(bus_handler) {}
|
||||
|
||||
void run_for(HalfCycles duration);
|
||||
|
||||
using State = ProcessorState;
|
||||
/// @returns The current processor state.
|
||||
State get_state();
|
||||
|
||||
/// Sets the processor to the supplied state.
|
||||
void set_state(const State &);
|
||||
|
||||
/// Sets the DTack line — @c true for active, @c false for inactive.
|
||||
inline void set_dtack(bool dtack) {
|
||||
dtack_ = dtack;
|
||||
}
|
||||
|
||||
/// Sets the VPA (valid peripheral address) line — @c true for active, @c false for inactive.
|
||||
inline void set_is_peripheral_address(bool is_peripheral_address) {
|
||||
is_peripheral_address_ = is_peripheral_address;
|
||||
}
|
||||
|
||||
/// Sets the bus error line — @c true for active, @c false for inactive.
|
||||
void set_bus_error(bool bus_error) {
|
||||
bus_error_ = bus_error;
|
||||
}
|
||||
|
||||
/// Sets the interrupt lines, IPL0, IPL1 and IPL2.
|
||||
void set_interrupt_level(int interrupt_level) {
|
||||
bus_interrupt_level_ = interrupt_level;
|
||||
}
|
||||
|
||||
/// Sets the bus request line.
|
||||
/// This are of functionality is TODO.
|
||||
void set_bus_request(bool bus_request) {
|
||||
bus_request_ = bus_request;
|
||||
}
|
||||
|
||||
/// Sets the bus acknowledge line.
|
||||
/// This are of functionality is TODO.
|
||||
void set_bus_acknowledge(bool bus_acknowledge) {
|
||||
bus_acknowledge_ = bus_acknowledge;
|
||||
}
|
||||
|
||||
/// Sets the halt line.
|
||||
void set_halt(bool halt) {
|
||||
halt_ = halt;
|
||||
}
|
||||
|
||||
private:
|
||||
T &bus_handler_;
|
||||
};
|
||||
|
||||
#include "Implementation/68000Implementation.hpp"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* MC68000_h */
|
2064
Processors/68000/Implementation/68000Implementation.hpp
Normal file
2064
Processors/68000/Implementation/68000Implementation.hpp
Normal file
File diff suppressed because it is too large
Load Diff
3584
Processors/68000/Implementation/68000Storage.cpp
Normal file
3584
Processors/68000/Implementation/68000Storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
498
Processors/68000/Implementation/68000Storage.hpp
Normal file
498
Processors/68000/Implementation/68000Storage.hpp
Normal file
@ -0,0 +1,498 @@
|
||||
//
|
||||
// 68000Storage.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 08/03/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef MC68000Storage_h
|
||||
#define MC68000Storage_h
|
||||
|
||||
class ProcessorStorage {
|
||||
public:
|
||||
ProcessorStorage();
|
||||
|
||||
protected:
|
||||
RegisterPair32 data_[8];
|
||||
RegisterPair32 address_[8];
|
||||
RegisterPair32 program_counter_;
|
||||
|
||||
RegisterPair32 stack_pointers_[2]; // [0] = user stack pointer; [1] = supervisor; the values from here
|
||||
// are copied into/out of address_[7] upon mode switches.
|
||||
|
||||
RegisterPair32 prefetch_queue_; // Each word will go into the low part of the word, then proceed upward.
|
||||
|
||||
enum class ExecutionState {
|
||||
/// The normal mode, this means the 68000 is expending processing effort.
|
||||
Executing,
|
||||
|
||||
/// The 68000 is in a holding loop, waiting for either DTack or to be notified of a bus error.
|
||||
WaitingForDTack,
|
||||
|
||||
/// Occurs after executing a STOP instruction; the processor will idle waiting for an interrupt or reset.
|
||||
Stopped,
|
||||
|
||||
/// Occurs at the end of the current bus cycle after detection of the HALT input, continuing until
|
||||
/// HALT is no longer signalled.
|
||||
Halted,
|
||||
|
||||
/// Signals a transition from some other straight directly to cueing up an interrupt.
|
||||
BeginInterrupt,
|
||||
} execution_state_ = ExecutionState::Executing;
|
||||
Microcycle dtack_cycle_;
|
||||
Microcycle stop_cycle_;
|
||||
|
||||
// Various status bits.
|
||||
int is_supervisor_;
|
||||
int interrupt_level_;
|
||||
uint_fast32_t zero_result_; // The zero flag is set if this value is zero.
|
||||
uint_fast32_t carry_flag_; // The carry flag is set if this value is non-zero.
|
||||
uint_fast32_t extend_flag_; // The extend flag is set if this value is non-zero.
|
||||
uint_fast32_t overflow_flag_; // The overflow flag is set if this value is non-zero.
|
||||
uint_fast32_t negative_flag_; // The negative flag is set if this value is non-zero.
|
||||
uint_fast32_t trace_flag_; // The trace flag is set if this value is non-zero.
|
||||
|
||||
// Bus inputs.
|
||||
int bus_interrupt_level_ = 0;
|
||||
bool dtack_ = false;
|
||||
bool is_peripheral_address_ = false;
|
||||
bool bus_error_ = false;
|
||||
bool bus_request_ = false;
|
||||
bool bus_acknowledge_ = false;
|
||||
bool halt_ = false;
|
||||
|
||||
int accepted_interrupt_level_ = 0;
|
||||
bool is_starting_interrupt_ = false;
|
||||
|
||||
// Generic sources and targets for memory operations;
|
||||
// by convention: [0] = source, [1] = destination.
|
||||
RegisterPair32 effective_address_[2];
|
||||
RegisterPair32 source_bus_data_[1];
|
||||
RegisterPair32 destination_bus_data_[1];
|
||||
|
||||
HalfCycles half_cycles_left_to_run_;
|
||||
HalfCycles e_clock_phase_;
|
||||
|
||||
enum class Operation {
|
||||
None,
|
||||
ABCD, SBCD, NBCD,
|
||||
|
||||
ADDb, ADDw, ADDl,
|
||||
ADDQb, ADDQw, ADDQl,
|
||||
ADDAw, ADDAl,
|
||||
ADDQAw, ADDQAl,
|
||||
ADDXb, ADDXw, ADDXl,
|
||||
|
||||
SUBb, SUBw, SUBl,
|
||||
SUBQb, SUBQw, SUBQl,
|
||||
SUBAw, SUBAl,
|
||||
SUBQAw, SUBQAl,
|
||||
SUBXb, SUBXw, SUBXl,
|
||||
|
||||
MOVEb, MOVEw, MOVEl, MOVEq,
|
||||
MOVEAw, MOVEAl,
|
||||
|
||||
MOVEtoSR, MOVEfromSR,
|
||||
MOVEtoCCR,
|
||||
|
||||
ORItoSR, ORItoCCR,
|
||||
ANDItoSR, ANDItoCCR,
|
||||
EORItoSR, EORItoCCR,
|
||||
|
||||
BTSTb, BTSTl,
|
||||
BCLRl, BCLRb,
|
||||
CMPb, CMPw, CMPl,
|
||||
TSTb, TSTw, TSTl,
|
||||
|
||||
JMP,
|
||||
BRA, Bcc,
|
||||
DBcc,
|
||||
Scc,
|
||||
|
||||
CLRb, CLRw, CLRl,
|
||||
NEGXb, NEGXw, NEGXl,
|
||||
NEGb, NEGw, NEGl,
|
||||
|
||||
ASLb, ASLw, ASLl, ASLm,
|
||||
ASRb, ASRw, ASRl, ASRm,
|
||||
LSLb, LSLw, LSLl, LSLm,
|
||||
LSRb, LSRw, LSRl, LSRm,
|
||||
ROLb, ROLw, ROLl, ROLm,
|
||||
RORb, RORw, RORl, RORm,
|
||||
ROXLb, ROXLw, ROXLl, ROXLm,
|
||||
ROXRb, ROXRw, ROXRl, ROXRm,
|
||||
|
||||
MOVEMtoRl, MOVEMtoRw,
|
||||
MOVEMtoMl, MOVEMtoMw,
|
||||
|
||||
MOVEPtoRl, MOVEPtoRw,
|
||||
MOVEPtoMl, MOVEPtoMw,
|
||||
|
||||
ANDb, ANDw, ANDl,
|
||||
EORb, EORw, EORl,
|
||||
NOTb, NOTw, NOTl,
|
||||
ORb, ORw, ORl,
|
||||
|
||||
MULU, MULS,
|
||||
DIVU, DIVS,
|
||||
|
||||
RTE_RTR,
|
||||
|
||||
TRAP, TRAPV,
|
||||
CHK,
|
||||
|
||||
EXG, SWAP,
|
||||
|
||||
BCHGl, BCHGb,
|
||||
BSETl, BSETb,
|
||||
|
||||
TAS,
|
||||
|
||||
EXTbtow, EXTwtol,
|
||||
|
||||
LINK, UNLINK,
|
||||
|
||||
STOP,
|
||||
};
|
||||
|
||||
/*!
|
||||
Bus steps are sequences of things to communicate to the bus.
|
||||
Standard behaviour is: (i) perform microcycle; (ii) perform action.
|
||||
*/
|
||||
struct BusStep {
|
||||
Microcycle microcycle;
|
||||
enum class Action {
|
||||
None,
|
||||
|
||||
/// Performs effective_address_[0] += 2.
|
||||
IncrementEffectiveAddress0,
|
||||
|
||||
/// Performs effective_address_[1] += 2.
|
||||
IncrementEffectiveAddress1,
|
||||
|
||||
/// Performs effective_address_[0] -= 2.
|
||||
DecrementEffectiveAddress0,
|
||||
|
||||
/// Performs effective_address_[1] -= 2.
|
||||
DecrementEffectiveAddress1,
|
||||
|
||||
/// Performs program_counter_ += 2.
|
||||
IncrementProgramCounter,
|
||||
|
||||
/// Copies prefetch_queue_[1] to prefetch_queue_[0].
|
||||
AdvancePrefetch,
|
||||
|
||||
/*!
|
||||
Terminates an atomic program; if nothing else is pending, schedules the next instruction.
|
||||
This action is special in that it usurps any included microcycle. So any Step with this
|
||||
as its action acts as an end-of-list sentinel.
|
||||
*/
|
||||
ScheduleNextProgram
|
||||
|
||||
} action = Action::None;
|
||||
|
||||
inline bool operator ==(const BusStep &rhs) const {
|
||||
if(action != rhs.action) return false;
|
||||
return microcycle == rhs.microcycle;
|
||||
}
|
||||
|
||||
inline bool is_terminal() const {
|
||||
return action == Action::ScheduleNextProgram;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
A micro-op is: (i) an action to take; and (ii) a sequence of bus operations
|
||||
to perform after taking the action.
|
||||
|
||||
NOTE: this therefore has the opposite order of behaviour compared to a BusStep,
|
||||
the action occurs BEFORE the bus operations, not after.
|
||||
|
||||
A nullptr bus_program terminates a sequence of micro operations; the is_terminal
|
||||
test should be used to query for that. The action on the final operation will
|
||||
be performed.
|
||||
*/
|
||||
struct MicroOp {
|
||||
enum class Action: int {
|
||||
None,
|
||||
|
||||
/// Does whatever this instruction says is the main operation.
|
||||
PerformOperation,
|
||||
|
||||
/*
|
||||
All of the below will honour the source and destination masks
|
||||
in deciding where to apply their actions.
|
||||
*/
|
||||
|
||||
/// Subtracts 1 from the [source/destination]_address.
|
||||
Decrement1,
|
||||
/// Subtracts 2 from the [source/destination]_address.
|
||||
Decrement2,
|
||||
/// Subtracts 4 from the [source/destination]_address.
|
||||
Decrement4,
|
||||
|
||||
/// Adds 1 from the [source/destination]_address.
|
||||
Increment1,
|
||||
/// Adds 2 from the [source/destination]_address.
|
||||
Increment2,
|
||||
/// Adds 4 from the [source/destination]_address.
|
||||
Increment4,
|
||||
|
||||
/// Copies the source and/or destination to effective_address_.
|
||||
CopyToEffectiveAddress,
|
||||
|
||||
/// Peeking into the end of the prefetch queue, calculates the proper target of (d16,An) addressing.
|
||||
CalcD16An,
|
||||
|
||||
/// Peeking into the end of the prefetch queue, calculates the proper target of (d8,An,Xn) addressing.
|
||||
CalcD8AnXn,
|
||||
|
||||
/// Peeking into the prefetch queue, calculates the proper target of (d16,PC) addressing,
|
||||
/// adjusting as though it had been performed after the proper PC fetches. The source
|
||||
/// and destination mask flags affect only the destination of the result.
|
||||
CalcD16PC,
|
||||
|
||||
/// Peeking into the prefetch queue, calculates the proper target of (d8,An,Xn) addressing,
|
||||
/// adjusting as though it had been performed after the proper PC fetches. The source
|
||||
/// and destination mask flags affect only the destination of the result.
|
||||
CalcD8PCXn,
|
||||
|
||||
/// Sets the high word according to the MSB of the low word.
|
||||
SignExtendWord,
|
||||
|
||||
/// Sets the high three bytes according to the MSB of the low byte.
|
||||
SignExtendByte,
|
||||
|
||||
/// From the next word in the prefetch queue assembles a sign-extended long word in either or
|
||||
/// both of effective_address_[0] and effective_address_[1].
|
||||
AssembleWordAddressFromPrefetch,
|
||||
|
||||
/// From the next word in the prefetch queue assembles a 0-padded 32-bit long word in either or
|
||||
/// both of bus_data_[0] and bus_data_[1].
|
||||
AssembleWordDataFromPrefetch,
|
||||
|
||||
/// Copies the next two prefetch words into one of the effective_address_.
|
||||
AssembleLongWordAddressFromPrefetch,
|
||||
|
||||
/// Copies the next two prefetch words into one of the bus_data_.
|
||||
AssembleLongWordDataFromPrefetch,
|
||||
|
||||
/// Copies the low part of the prefetch queue into next_word_.
|
||||
CopyNextWord,
|
||||
|
||||
/// Performs write-back of post-increment address and/or sign extensions as necessary.
|
||||
MOVEMtoRComplete,
|
||||
|
||||
/// Performs write-back of pre-decrement address.
|
||||
MOVEMtoMComplete,
|
||||
|
||||
// (i) inspects the prefetch queue to determine the length of this instruction and copies the next PC to destination_bus_data_;
|
||||
// (ii) copies the stack pointer minus 4 to effective_address_[1];
|
||||
// (iii) decrements the stack pointer by four.
|
||||
PrepareJSR,
|
||||
PrepareBSR,
|
||||
|
||||
// (i) copies the stack pointer to effective_address_[0];
|
||||
// (ii) increments the stack pointer by four.
|
||||
PrepareRTS,
|
||||
|
||||
// (i) fills in the proper stack addresses to the bus steps for this micro-op; and
|
||||
// (ii) adjusts the stack pointer appropriately.
|
||||
PrepareRTE_RTR,
|
||||
|
||||
// Performs the necessary status word substitution for the current interrupt level,
|
||||
// and does the first part of initialising the trap steps.
|
||||
PrepareINT,
|
||||
|
||||
// Observes the bus_error_, valid_peripheral_address_ and/or the value currently in
|
||||
// source_bus_data_ to determine an interrupt vector, and fills in the final trap
|
||||
// steps detail appropriately.
|
||||
PrepareINTVector,
|
||||
};
|
||||
static const int SourceMask = 1 << 30;
|
||||
static const int DestinationMask = 1 << 29;
|
||||
int action = int(Action::None);
|
||||
|
||||
BusStep *bus_program = nullptr;
|
||||
|
||||
MicroOp() {}
|
||||
MicroOp(int action) : action(action) {}
|
||||
MicroOp(int action, BusStep *bus_program) : action(action), bus_program(bus_program) {}
|
||||
|
||||
MicroOp(Action action) : MicroOp(int(action)) {}
|
||||
MicroOp(Action action, BusStep *bus_program) : MicroOp(int(action), bus_program) {}
|
||||
|
||||
inline bool is_terminal() const {
|
||||
return bus_program == nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
A program represents the implementation of a particular opcode, as a sequence
|
||||
of micro-ops and, separately, the operation to perform plus whatever other
|
||||
fields the operation requires.
|
||||
*/
|
||||
struct Program {
|
||||
MicroOp *micro_operations = nullptr;
|
||||
RegisterPair32 *source = nullptr;
|
||||
RegisterPair32 *destination = nullptr;
|
||||
RegisterPair32 *source_address = nullptr;
|
||||
RegisterPair32 *destination_address = nullptr;
|
||||
Operation operation;
|
||||
bool requires_supervisor = false;
|
||||
|
||||
void set_source(ProcessorStorage &storage, int mode, int reg) {
|
||||
source_address = &storage.address_[reg];
|
||||
switch(mode) {
|
||||
case 0: source = &storage.data_[reg]; break;
|
||||
case 1: source = &storage.address_[reg]; break;
|
||||
default: source = &storage.source_bus_data_[0]; break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_destination(ProcessorStorage &storage, int mode, int reg) {
|
||||
destination_address = &storage.address_[reg];
|
||||
switch(mode) {
|
||||
case 0: destination = &storage.data_[reg]; break;
|
||||
case 1: destination = &storage.address_[reg]; break;
|
||||
default: destination = &storage.destination_bus_data_[0]; break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Storage for all the sequences of bus steps and micro-ops used throughout
|
||||
// the 68000.
|
||||
std::vector<BusStep> all_bus_steps_;
|
||||
std::vector<MicroOp> all_micro_ops_;
|
||||
|
||||
// A lookup table from instructions to implementations.
|
||||
Program instructions[65536];
|
||||
|
||||
// Special steps and programs for exception handlers.
|
||||
BusStep *reset_bus_steps_;
|
||||
MicroOp *long_exception_micro_ops_; // i.e. those that leave 14 bytes on the stack — bus error and address error.
|
||||
MicroOp *short_exception_micro_ops_; // i.e. those that leave 6 bytes on the stack — everything else (other than interrupts).
|
||||
MicroOp *interrupt_micro_ops_;
|
||||
|
||||
// Special micro-op sequences and storage for conditionals.
|
||||
BusStep *branch_taken_bus_steps_;
|
||||
BusStep *branch_byte_not_taken_bus_steps_;
|
||||
BusStep *branch_word_not_taken_bus_steps_;
|
||||
BusStep *bsr_bus_steps_;
|
||||
|
||||
uint32_t dbcc_false_address_;
|
||||
BusStep *dbcc_condition_true_steps_;
|
||||
BusStep *dbcc_condition_false_no_branch_steps_;
|
||||
BusStep *dbcc_condition_false_branch_steps_;
|
||||
|
||||
BusStep *movem_read_steps_;
|
||||
BusStep *movem_write_steps_;
|
||||
|
||||
BusStep *trap_steps_;
|
||||
BusStep *bus_error_steps_;
|
||||
|
||||
// Current bus step pointer, and outer program pointer.
|
||||
Program *active_program_ = nullptr;
|
||||
MicroOp *active_micro_op_ = nullptr;
|
||||
BusStep *active_step_ = nullptr;
|
||||
RegisterPair16 decoded_instruction_ = 0;
|
||||
uint16_t next_word_ = 0;
|
||||
|
||||
/// Copies address_[7] to the proper stack pointer based on current mode.
|
||||
void write_back_stack_pointer();
|
||||
|
||||
/// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated.
|
||||
void set_is_supervisor(bool);
|
||||
|
||||
// Transient storage for MOVEM, TRAP and others.
|
||||
uint32_t precomputed_addresses_[65];
|
||||
RegisterPair16 throwaway_value_;
|
||||
uint32_t movem_final_address_;
|
||||
|
||||
/*!
|
||||
Evaluates the conditional described by @c code and returns @c true or @c false to
|
||||
indicate the result of that evaluation.
|
||||
*/
|
||||
inline bool evaluate_condition(uint8_t code) {
|
||||
switch(code & 0xf) {
|
||||
default:
|
||||
case 0x00: return true; // true
|
||||
case 0x01: return false; // false
|
||||
case 0x02: return zero_result_ && !carry_flag_; // high
|
||||
case 0x03: return !zero_result_ || carry_flag_; // low or same
|
||||
case 0x04: return !carry_flag_; // carry clear
|
||||
case 0x05: return carry_flag_; // carry set
|
||||
case 0x06: return zero_result_; // not equal
|
||||
case 0x07: return !zero_result_; // equal
|
||||
case 0x08: return !overflow_flag_; // overflow clear
|
||||
case 0x09: return overflow_flag_; // overflow set
|
||||
case 0x0a: return !negative_flag_; // positive
|
||||
case 0x0b: return negative_flag_; // negative
|
||||
case 0x0c: // greater than or equal
|
||||
return (negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_);
|
||||
case 0x0d: // less than
|
||||
return (negative_flag_ && !overflow_flag_) || (!negative_flag_ && overflow_flag_);
|
||||
case 0x0e: // greater than
|
||||
return zero_result_ && ((negative_flag_ && overflow_flag_) || (!negative_flag_ && !overflow_flag_));
|
||||
case 0x0f: // less than or equal
|
||||
return !zero_result_ || (negative_flag_ && !overflow_flag_) || (!negative_flag_ && overflow_flag_);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Fills in the appropriate addresses and values to complete the TRAP steps — those
|
||||
representing a short-form exception — and mutates the status register as if one
|
||||
were beginning.
|
||||
*/
|
||||
inline void populate_trap_steps(uint32_t vector, uint16_t status) {
|
||||
// Fill in the status word value.
|
||||
destination_bus_data_[0].full = status;
|
||||
|
||||
// Switch to supervisor mode, disable the trace bit.
|
||||
set_is_supervisor(true);
|
||||
trace_flag_ = 0;
|
||||
|
||||
// Pick a vector.
|
||||
effective_address_[0].full = vector << 2;
|
||||
|
||||
// Schedule the proper stack activity.
|
||||
precomputed_addresses_[0] = address_[7].full - 2; // PC.l
|
||||
precomputed_addresses_[1] = address_[7].full - 6; // status word (in destination_bus_data_[0])
|
||||
precomputed_addresses_[2] = address_[7].full - 4; // PC.h
|
||||
address_[7].full -= 6;
|
||||
|
||||
// Set the default timing.
|
||||
trap_steps_->microcycle.length = HalfCycles(8);
|
||||
}
|
||||
|
||||
inline void populate_bus_error_steps(uint32_t vector, uint16_t status, uint16_t bus_status, RegisterPair32 faulting_address) {
|
||||
// Fill in the status word value.
|
||||
destination_bus_data_[0].halves.low.full = status;
|
||||
destination_bus_data_[0].halves.high.full = bus_status;
|
||||
effective_address_[1] = faulting_address;
|
||||
|
||||
// Switch to supervisor mode, disable the trace bit.
|
||||
set_is_supervisor(true);
|
||||
trace_flag_ = 0;
|
||||
|
||||
// Pick a vector.
|
||||
effective_address_[0].full = vector << 2;
|
||||
|
||||
// Schedule the proper stack activity.
|
||||
precomputed_addresses_[0] = address_[7].full - 2; // PC.l
|
||||
precomputed_addresses_[1] = address_[7].full - 6; // status word
|
||||
precomputed_addresses_[2] = address_[7].full - 4; // PC.h
|
||||
precomputed_addresses_[3] = address_[7].full - 8; // current instruction
|
||||
precomputed_addresses_[4] = address_[7].full - 10; // fault address.l
|
||||
precomputed_addresses_[5] = address_[7].full - 14; // bus cycle status word
|
||||
precomputed_addresses_[6] = address_[7].full - 12; // fault address.h
|
||||
address_[7].full -= 14;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ProcessorStorageConstructor;
|
||||
friend class ProcessorStorageTests;
|
||||
};
|
||||
|
||||
#endif /* MC68000Storage_h */
|
@ -13,16 +13,27 @@
|
||||
|
||||
namespace CPU {
|
||||
|
||||
union RegisterPair {
|
||||
RegisterPair(uint16_t v) : full(v) {}
|
||||
template <typename Full, typename Half> union RegisterPair {
|
||||
RegisterPair(Full v) : full(v) {}
|
||||
RegisterPair() {}
|
||||
|
||||
uint16_t full;
|
||||
Full full;
|
||||
#pragma pack(push, 1)
|
||||
#if TARGET_RT_BIG_ENDIAN
|
||||
struct {
|
||||
uint8_t low, high;
|
||||
} bytes;
|
||||
Half high, low;
|
||||
} halves;
|
||||
#else
|
||||
struct {
|
||||
Half low, high;
|
||||
} halves;
|
||||
#endif
|
||||
#pragma pack(pop)
|
||||
};
|
||||
|
||||
typedef RegisterPair<uint16_t, uint8_t> RegisterPair16;
|
||||
typedef RegisterPair<uint32_t, RegisterPair16> RegisterPair32;
|
||||
|
||||
}
|
||||
|
||||
#endif /* RegisterSizes_hpp */
|
||||
|
@ -23,38 +23,38 @@ uint16_t ProcessorBase::get_value_of_register(Register r) {
|
||||
case Register::A: return a_;
|
||||
case Register::Flags: return get_flags();
|
||||
case Register::AF: return static_cast<uint16_t>((a_ << 8) | get_flags());
|
||||
case Register::B: return bc_.bytes.high;
|
||||
case Register::C: return bc_.bytes.low;
|
||||
case Register::B: return bc_.halves.high;
|
||||
case Register::C: return bc_.halves.low;
|
||||
case Register::BC: return bc_.full;
|
||||
case Register::D: return de_.bytes.high;
|
||||
case Register::E: return de_.bytes.low;
|
||||
case Register::D: return de_.halves.high;
|
||||
case Register::E: return de_.halves.low;
|
||||
case Register::DE: return de_.full;
|
||||
case Register::H: return hl_.bytes.high;
|
||||
case Register::L: return hl_.bytes.low;
|
||||
case Register::H: return hl_.halves.high;
|
||||
case Register::L: return hl_.halves.low;
|
||||
case Register::HL: return hl_.full;
|
||||
|
||||
case Register::ADash: return afDash_.bytes.high;
|
||||
case Register::FlagsDash: return afDash_.bytes.low;
|
||||
case Register::ADash: return afDash_.halves.high;
|
||||
case Register::FlagsDash: return afDash_.halves.low;
|
||||
case Register::AFDash: return afDash_.full;
|
||||
case Register::BDash: return bcDash_.bytes.high;
|
||||
case Register::CDash: return bcDash_.bytes.low;
|
||||
case Register::BDash: return bcDash_.halves.high;
|
||||
case Register::CDash: return bcDash_.halves.low;
|
||||
case Register::BCDash: return bcDash_.full;
|
||||
case Register::DDash: return deDash_.bytes.high;
|
||||
case Register::EDash: return deDash_.bytes.low;
|
||||
case Register::DDash: return deDash_.halves.high;
|
||||
case Register::EDash: return deDash_.halves.low;
|
||||
case Register::DEDash: return deDash_.full;
|
||||
case Register::HDash: return hlDash_.bytes.high;
|
||||
case Register::LDash: return hlDash_.bytes.low;
|
||||
case Register::HDash: return hlDash_.halves.high;
|
||||
case Register::LDash: return hlDash_.halves.low;
|
||||
case Register::HLDash: return hlDash_.full;
|
||||
|
||||
case Register::IXh: return ix_.bytes.high;
|
||||
case Register::IXl: return ix_.bytes.low;
|
||||
case Register::IXh: return ix_.halves.high;
|
||||
case Register::IXl: return ix_.halves.low;
|
||||
case Register::IX: return ix_.full;
|
||||
case Register::IYh: return iy_.bytes.high;
|
||||
case Register::IYl: return iy_.bytes.low;
|
||||
case Register::IYh: return iy_.halves.high;
|
||||
case Register::IYl: return iy_.halves.low;
|
||||
case Register::IY: return iy_.full;
|
||||
|
||||
case Register::R: return ir_.bytes.low;
|
||||
case Register::I: return ir_.bytes.high;
|
||||
case Register::R: return ir_.halves.low;
|
||||
case Register::I: return ir_.halves.high;
|
||||
case Register::Refresh: return ir_.full;
|
||||
|
||||
case Register::IFF1: return iff1_ ? 1 : 0;
|
||||
@ -76,38 +76,38 @@ void ProcessorBase::set_value_of_register(Register r, uint16_t value) {
|
||||
case Register::AF: a_ = static_cast<uint8_t>(value >> 8); // deliberate fallthrough...
|
||||
case Register::Flags: set_flags(static_cast<uint8_t>(value)); break;
|
||||
|
||||
case Register::B: bc_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::C: bc_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::B: bc_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::C: bc_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::BC: bc_.full = value; break;
|
||||
case Register::D: de_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::E: de_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::D: de_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::E: de_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::DE: de_.full = value; break;
|
||||
case Register::H: hl_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::L: hl_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::H: hl_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::L: hl_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::HL: hl_.full = value; break;
|
||||
|
||||
case Register::ADash: afDash_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::FlagsDash: afDash_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::ADash: afDash_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::FlagsDash: afDash_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::AFDash: afDash_.full = value; break;
|
||||
case Register::BDash: bcDash_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::CDash: bcDash_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::BDash: bcDash_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::CDash: bcDash_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::BCDash: bcDash_.full = value; break;
|
||||
case Register::DDash: deDash_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::EDash: deDash_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::DDash: deDash_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::EDash: deDash_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::DEDash: deDash_.full = value; break;
|
||||
case Register::HDash: hlDash_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::LDash: hlDash_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::HDash: hlDash_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::LDash: hlDash_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::HLDash: hlDash_.full = value; break;
|
||||
|
||||
case Register::IXh: ix_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::IXl: ix_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::IXh: ix_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::IXl: ix_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::IX: ix_.full = value; break;
|
||||
case Register::IYh: iy_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::IYl: iy_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::IYh: iy_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::IYl: iy_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::IY: iy_.full = value; break;
|
||||
|
||||
case Register::R: ir_.bytes.low = static_cast<uint8_t>(value); break;
|
||||
case Register::I: ir_.bytes.high = static_cast<uint8_t>(value); break;
|
||||
case Register::R: ir_.halves.low = static_cast<uint8_t>(value); break;
|
||||
case Register::I: ir_.halves.high = static_cast<uint8_t>(value); break;
|
||||
case Register::Refresh: ir_.full = value; break;
|
||||
|
||||
case Register::IFF1: iff1_ = !!value; break;
|
||||
|
@ -90,7 +90,7 @@ template < class T,
|
||||
break;
|
||||
case MicroOp::DecodeOperation:
|
||||
refresh_addr_ = ir_;
|
||||
ir_.bytes.low = (ir_.bytes.low & 0x80) | ((ir_.bytes.low + current_instruction_page_->r_step) & 0x7f);
|
||||
ir_.halves.low = (ir_.halves.low & 0x80) | ((ir_.halves.low + current_instruction_page_->r_step) & 0x7f);
|
||||
pc_.full += pc_increment_ & static_cast<uint16_t>(halt_mask_);
|
||||
scheduled_program_counter_ = current_instruction_page_->instructions[operation_ & halt_mask_];
|
||||
flag_adjustment_history_ <<= 1;
|
||||
@ -108,13 +108,12 @@ template < class T,
|
||||
case MicroOp::Move16: *static_cast<uint16_t *>(operation->destination) = *static_cast<uint16_t *>(operation->source); break;
|
||||
|
||||
case MicroOp::AssembleAF:
|
||||
temp16_.bytes.high = a_;
|
||||
temp16_.bytes.low = get_flags();
|
||||
temp16_.halves.high = a_;
|
||||
temp16_.halves.low = get_flags();
|
||||
break;
|
||||
case MicroOp::DisassembleAF:
|
||||
a_ = temp16_.bytes.high;
|
||||
set_flags(temp16_.bytes.low);
|
||||
//
|
||||
a_ = temp16_.halves.high;
|
||||
set_flags(temp16_.halves.low);
|
||||
break;
|
||||
|
||||
// MARK: - Logical
|
||||
@ -179,8 +178,8 @@ template < class T,
|
||||
// MARK: - Flow control
|
||||
|
||||
case MicroOp::DJNZ:
|
||||
bc_.bytes.high--;
|
||||
if(!bc_.bytes.high) {
|
||||
bc_.halves.high--;
|
||||
if(!bc_.halves.high) {
|
||||
advance_operation();
|
||||
}
|
||||
break;
|
||||
@ -460,10 +459,10 @@ template < class T,
|
||||
case MicroOp::ExAFAFDash: {
|
||||
const uint8_t a = a_;
|
||||
const uint8_t f = get_flags();
|
||||
set_flags(afDash_.bytes.low);
|
||||
a_ = afDash_.bytes.high;
|
||||
afDash_.bytes.high = a;
|
||||
afDash_.bytes.low = f;
|
||||
set_flags(afDash_.halves.low);
|
||||
a_ = afDash_.halves.high;
|
||||
afDash_.halves.high = a;
|
||||
afDash_.halves.low = f;
|
||||
} break;
|
||||
|
||||
case MicroOp::EXX: {
|
||||
@ -554,13 +553,13 @@ template < class T,
|
||||
#undef CPxR_STEP
|
||||
|
||||
#define INxR_STEP(dir) \
|
||||
bc_.bytes.high--; \
|
||||
bc_.halves.high--; \
|
||||
hl_.full += dir; \
|
||||
\
|
||||
sign_result_ = zero_result_ = bit53_result_ = bc_.bytes.high; \
|
||||
sign_result_ = zero_result_ = bit53_result_ = bc_.halves.high; \
|
||||
subtract_flag_ = (temp8_ >> 6) & Flag::Subtract; \
|
||||
\
|
||||
const int next_bc = bc_.bytes.low + dir; \
|
||||
const int next_bc = bc_.halves.low + dir; \
|
||||
int summation = temp8_ + (next_bc&0xff); \
|
||||
\
|
||||
if(summation > 0xff) { \
|
||||
@ -571,18 +570,18 @@ template < class T,
|
||||
half_carry_result_ = 0; \
|
||||
} \
|
||||
\
|
||||
summation = (summation&7) ^ bc_.bytes.high; \
|
||||
summation = (summation&7) ^ bc_.halves.high; \
|
||||
set_parity(summation); \
|
||||
set_did_compute_flags();
|
||||
|
||||
case MicroOp::INDR: {
|
||||
INxR_STEP(-1);
|
||||
REPEAT(bc_.bytes.high);
|
||||
REPEAT(bc_.halves.high);
|
||||
} break;
|
||||
|
||||
case MicroOp::INIR: {
|
||||
INxR_STEP(1);
|
||||
REPEAT(bc_.bytes.high);
|
||||
REPEAT(bc_.halves.high);
|
||||
} break;
|
||||
|
||||
case MicroOp::IND: {
|
||||
@ -598,13 +597,13 @@ template < class T,
|
||||
#undef INxR_STEP
|
||||
|
||||
#define OUTxR_STEP(dir) \
|
||||
bc_.bytes.high--; \
|
||||
bc_.halves.high--; \
|
||||
hl_.full += dir; \
|
||||
\
|
||||
sign_result_ = zero_result_ = bit53_result_ = bc_.bytes.high; \
|
||||
sign_result_ = zero_result_ = bit53_result_ = bc_.halves.high; \
|
||||
subtract_flag_ = (temp8_ >> 6) & Flag::Subtract; \
|
||||
\
|
||||
int summation = temp8_ + hl_.bytes.low; \
|
||||
int summation = temp8_ + hl_.halves.low; \
|
||||
if(summation > 0xff) { \
|
||||
carry_result_ = Flag::Carry; \
|
||||
half_carry_result_ = Flag::HalfCarry; \
|
||||
@ -612,12 +611,12 @@ template < class T,
|
||||
carry_result_ = half_carry_result_ = 0; \
|
||||
} \
|
||||
\
|
||||
summation = (summation&7) ^ bc_.bytes.high; \
|
||||
summation = (summation&7) ^ bc_.halves.high; \
|
||||
set_parity(summation); \
|
||||
set_did_compute_flags();
|
||||
|
||||
case MicroOp::OUT_R:
|
||||
REPEAT(bc_.bytes.high);
|
||||
REPEAT(bc_.halves.high);
|
||||
break;
|
||||
|
||||
case MicroOp::OUTD: {
|
||||
@ -638,7 +637,7 @@ template < class T,
|
||||
const uint8_t result = *static_cast<uint8_t *>(operation->source) & (1 << ((operation_ >> 3)&7));
|
||||
|
||||
if(current_instruction_page_->is_indexed || ((operation_&0x07) == 6)) {
|
||||
bit53_result_ = memptr_.bytes.high;
|
||||
bit53_result_ = memptr_.halves.high;
|
||||
} else {
|
||||
bit53_result_ = *static_cast<uint8_t *>(operation->source);
|
||||
}
|
||||
|
@ -86,48 +86,48 @@ ProcessorStorage::ProcessorStorage() {
|
||||
#define Read5Inc(addr, val) Read5(addr, val), Inc16(addr)
|
||||
#define WriteInc(addr, val) Write3(addr, val), {MicroOp::Increment16, &addr.full}
|
||||
|
||||
#define Read16Inc(addr, val) ReadInc(addr, val.bytes.low), ReadInc(addr, val.bytes.high)
|
||||
#define Read16(addr, val) ReadInc(addr, val.bytes.low), Read3(addr, val.bytes.high)
|
||||
#define Read16Inc(addr, val) ReadInc(addr, val.halves.low), ReadInc(addr, val.halves.high)
|
||||
#define Read16(addr, val) ReadInc(addr, val.halves.low), Read3(addr, val.halves.high)
|
||||
|
||||
#define Write16(addr, val) WriteInc(addr, val.bytes.low), Write3(addr, val.bytes.high)
|
||||
#define Write16(addr, val) WriteInc(addr, val.halves.low), Write3(addr, val.halves.high)
|
||||
|
||||
#define INDEX() {MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), InternalOperation(10), {MicroOp::CalculateIndexAddress, &index}
|
||||
#define FINDEX() {MicroOp::IndexedPlaceHolder}, ReadInc(pc_, temp8_), {MicroOp::CalculateIndexAddress, &index}
|
||||
#define INDEX_ADDR() (add_offsets ? memptr_ : index)
|
||||
|
||||
#define Push(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.low)
|
||||
#define Pop(x) Read3(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read3(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full}
|
||||
#define Push(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.halves.high), {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.halves.low)
|
||||
#define Pop(x) Read3(sp_, x.halves.low), {MicroOp::Increment16, &sp_.full}, Read3(sp_, x.halves.high), {MicroOp::Increment16, &sp_.full}
|
||||
|
||||
#define Push8(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.bytes.high), {MicroOp::Decrement16, &sp_.full}, Write5(sp_, x.bytes.low)
|
||||
#define Pop7(x) Read3(sp_, x.bytes.low), {MicroOp::Increment16, &sp_.full}, Read4(sp_, x.bytes.high), {MicroOp::Increment16, &sp_.full}
|
||||
#define Push8(x) {MicroOp::Decrement16, &sp_.full}, Write3(sp_, x.halves.high), {MicroOp::Decrement16, &sp_.full}, Write5(sp_, x.halves.low)
|
||||
#define Pop7(x) Read3(sp_, x.halves.low), {MicroOp::Increment16, &sp_.full}, Read4(sp_, x.halves.high), {MicroOp::Increment16, &sp_.full}
|
||||
|
||||
/* The following are actual instructions */
|
||||
#define NOP Sequence(BusOp(Refresh(4)))
|
||||
|
||||
#define JP(cc) StdInstr(Read16Inc(pc_, temp16_), {MicroOp::cc, nullptr}, {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define CALL(cc) StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::cc, conditional_call_untaken_program_.data()}, Read4Inc(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define CALL(cc) StdInstr(ReadInc(pc_, temp16_.halves.low), {MicroOp::cc, conditional_call_untaken_program_.data()}, Read4Inc(pc_, temp16_.halves.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full})
|
||||
#define RET(cc) Instr(6, {MicroOp::cc, nullptr}, Pop(memptr_), {MicroOp::Move16, &memptr_.full, &pc_.full})
|
||||
#define JR(cc) StdInstr(ReadInc(pc_, temp8_), {MicroOp::cc, nullptr}, InternalOperation(10), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full})
|
||||
#define RST() Instr(6, {MicroOp::CalculateRSTDestination}, Push(pc_), {MicroOp::Move16, &memptr_.full, &pc_.full})
|
||||
#define LD(a, b) StdInstr({MicroOp::Move8, &b, &a})
|
||||
|
||||
#define LD_GROUP(r, ri) \
|
||||
LD(r, bc_.bytes.high), LD(r, bc_.bytes.low), LD(r, de_.bytes.high), LD(r, de_.bytes.low), \
|
||||
LD(r, index.bytes.high), LD(r, index.bytes.low), \
|
||||
LD(r, bc_.halves.high), LD(r, bc_.halves.low), LD(r, de_.halves.high), LD(r, de_.halves.low), \
|
||||
LD(r, index.halves.high), LD(r, index.halves.low), \
|
||||
StdInstr(INDEX(), Read3(INDEX_ADDR(), temp8_), {MicroOp::Move8, &temp8_, &ri}), \
|
||||
LD(r, a_)
|
||||
|
||||
#define READ_OP_GROUP(op) \
|
||||
StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &de_.bytes.high}), StdInstr({MicroOp::op, &de_.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &index.bytes.high}), StdInstr({MicroOp::op, &index.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &bc_.halves.high}), StdInstr({MicroOp::op, &bc_.halves.low}), \
|
||||
StdInstr({MicroOp::op, &de_.halves.high}), StdInstr({MicroOp::op, &de_.halves.low}), \
|
||||
StdInstr({MicroOp::op, &index.halves.high}), StdInstr({MicroOp::op, &index.halves.low}), \
|
||||
StdInstr(INDEX(), Read3(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \
|
||||
StdInstr({MicroOp::op, &a_})
|
||||
|
||||
#define READ_OP_GROUP_D(op) \
|
||||
StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &de_.bytes.high}), StdInstr({MicroOp::op, &de_.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &index.bytes.high}), StdInstr({MicroOp::op, &index.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &bc_.halves.high}), StdInstr({MicroOp::op, &bc_.halves.low}), \
|
||||
StdInstr({MicroOp::op, &de_.halves.high}), StdInstr({MicroOp::op, &de_.halves.low}), \
|
||||
StdInstr({MicroOp::op, &index.halves.high}), StdInstr({MicroOp::op, &index.halves.low}), \
|
||||
StdInstr(INDEX(), Read4Pre(INDEX_ADDR(), temp8_), {MicroOp::op, &temp8_}), \
|
||||
StdInstr({MicroOp::op, &a_})
|
||||
|
||||
@ -135,19 +135,19 @@ ProcessorStorage::ProcessorStorage() {
|
||||
#define RMWI(x, op, ...) StdInstr(Read4(INDEX_ADDR(), x), {MicroOp::op, &x}, Write3(INDEX_ADDR(), x))
|
||||
|
||||
#define MODIFY_OP_GROUP(op) \
|
||||
StdInstr({MicroOp::op, &bc_.bytes.high}), StdInstr({MicroOp::op, &bc_.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &de_.bytes.high}), StdInstr({MicroOp::op, &de_.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &index.bytes.high}), StdInstr({MicroOp::op, &index.bytes.low}), \
|
||||
StdInstr({MicroOp::op, &bc_.halves.high}), StdInstr({MicroOp::op, &bc_.halves.low}), \
|
||||
StdInstr({MicroOp::op, &de_.halves.high}), StdInstr({MicroOp::op, &de_.halves.low}), \
|
||||
StdInstr({MicroOp::op, &index.halves.high}), StdInstr({MicroOp::op, &index.halves.low}), \
|
||||
RMW(temp8_, op), \
|
||||
StdInstr({MicroOp::op, &a_})
|
||||
|
||||
#define IX_MODIFY_OP_GROUP(op) \
|
||||
RMWI(bc_.bytes.high, op), \
|
||||
RMWI(bc_.bytes.low, op), \
|
||||
RMWI(de_.bytes.high, op), \
|
||||
RMWI(de_.bytes.low, op), \
|
||||
RMWI(hl_.bytes.high, op), \
|
||||
RMWI(hl_.bytes.low, op), \
|
||||
RMWI(bc_.halves.high, op), \
|
||||
RMWI(bc_.halves.low, op), \
|
||||
RMWI(de_.halves.high, op), \
|
||||
RMWI(de_.halves.low, op), \
|
||||
RMWI(hl_.halves.high, op), \
|
||||
RMWI(hl_.halves.low, op), \
|
||||
RMWI(temp8_, op), \
|
||||
RMWI(a_, op)
|
||||
|
||||
@ -166,7 +166,7 @@ ProcessorStorage::ProcessorStorage() {
|
||||
#define SBC16(d, s) StdInstr(InternalOperation(8), InternalOperation(6), {MicroOp::SBC16, &s.full, &d.full})
|
||||
|
||||
void ProcessorStorage::install_default_instruction_set() {
|
||||
MicroOp conditional_call_untaken_program[] = Sequence(ReadInc(pc_, temp16_.bytes.high));
|
||||
MicroOp conditional_call_untaken_program[] = Sequence(ReadInc(pc_, temp16_.halves.high));
|
||||
copy_program(conditional_call_untaken_program, conditional_call_untaken_program_);
|
||||
|
||||
assemble_base_page(base_page_, hl_, false, cb_page_);
|
||||
@ -225,12 +225,12 @@ void ProcessorStorage::install_default_instruction_set() {
|
||||
};
|
||||
MicroOp irq_mode2_program[] = {
|
||||
{ MicroOp::BeginIRQ },
|
||||
BusOp(IntAckStart(7, temp16_.bytes.low)),
|
||||
BusOp(IntWait(temp16_.bytes.low)),
|
||||
BusOp(IntAckEnd(temp16_.bytes.low)),
|
||||
BusOp(IntAckStart(7, temp16_.halves.low)),
|
||||
BusOp(IntWait(temp16_.halves.low)),
|
||||
BusOp(IntAckEnd(temp16_.halves.low)),
|
||||
BusOp(Refresh(4)),
|
||||
Push(pc_),
|
||||
{ MicroOp::Move8, &ir_.bytes.high, &temp16_.bytes.high },
|
||||
{ MicroOp::Move8, &ir_.halves.high, &temp16_.halves.high },
|
||||
Read16(temp16_, pc_),
|
||||
{ MicroOp::MoveToNextProgram }
|
||||
};
|
||||
@ -253,27 +253,27 @@ void ProcessorStorage::assemble_ed_page(InstructionPage &target) {
|
||||
NOP_ROW(), /* 0x10 */
|
||||
NOP_ROW(), /* 0x20 */
|
||||
NOP_ROW(), /* 0x30 */
|
||||
/* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(bc_.bytes.high),
|
||||
/* 0x40 IN B, (C); 0x41 OUT (C), B */ IN_OUT(bc_.halves.high),
|
||||
/* 0x42 SBC HL, BC */ SBC16(hl_, bc_), /* 0x43 LD (nn), BC */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, bc_)),
|
||||
/* 0x44 NEG */ StdInstr({MicroOp::NEG}), /* 0x45 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}),
|
||||
/* 0x46 IM 0 */ StdInstr({MicroOp::IM}), /* 0x47 LD I, A */ Instr(6, {MicroOp::Move8, &a_, &ir_.bytes.high}),
|
||||
/* 0x48 IN C, (C); 0x49 OUT (C), C */ IN_OUT(bc_.bytes.low),
|
||||
/* 0x46 IM 0 */ StdInstr({MicroOp::IM}), /* 0x47 LD I, A */ Instr(6, {MicroOp::Move8, &a_, &ir_.halves.high}),
|
||||
/* 0x48 IN C, (C); 0x49 OUT (C), C */ IN_OUT(bc_.halves.low),
|
||||
/* 0x4a ADC HL, BC */ ADC16(hl_, bc_), /* 0x4b LD BC, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, bc_)),
|
||||
/* 0x4c NEG */ StdInstr({MicroOp::NEG}), /* 0x4d RETI */ StdInstr(Pop(pc_), {MicroOp::RETN}),
|
||||
/* 0x4e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x4f LD R, A */ Instr(6, {MicroOp::Move8, &a_, &ir_.bytes.low}),
|
||||
/* 0x50 IN D, (C); 0x51 OUT (C), D */ IN_OUT(de_.bytes.high),
|
||||
/* 0x4e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x4f LD R, A */ Instr(6, {MicroOp::Move8, &a_, &ir_.halves.low}),
|
||||
/* 0x50 IN D, (C); 0x51 OUT (C), D */ IN_OUT(de_.halves.high),
|
||||
/* 0x52 SBC HL, DE */ SBC16(hl_, de_), /* 0x53 LD (nn), DE */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, de_)),
|
||||
/* 0x54 NEG */ StdInstr({MicroOp::NEG}), /* 0x55 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}),
|
||||
/* 0x56 IM 1 */ StdInstr({MicroOp::IM}), /* 0x57 LD A, I */ Instr(6, {MicroOp::Move8, &ir_.bytes.high, &a_}, {MicroOp::SetAFlags}),
|
||||
/* 0x58 IN E, (C); 0x59 OUT (C), E */ IN_OUT(de_.bytes.low),
|
||||
/* 0x56 IM 1 */ StdInstr({MicroOp::IM}), /* 0x57 LD A, I */ Instr(6, {MicroOp::Move8, &ir_.halves.high, &a_}, {MicroOp::SetAFlags}),
|
||||
/* 0x58 IN E, (C); 0x59 OUT (C), E */ IN_OUT(de_.halves.low),
|
||||
/* 0x5a ADC HL, DE */ ADC16(hl_, de_), /* 0x5b LD DE, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, de_)),
|
||||
/* 0x5c NEG */ StdInstr({MicroOp::NEG}), /* 0x5d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}),
|
||||
/* 0x5e IM 2 */ StdInstr({MicroOp::IM}), /* 0x5f LD A, R */ Instr(6, {MicroOp::Move8, &ir_.bytes.low, &a_}, {MicroOp::SetAFlags}),
|
||||
/* 0x60 IN H, (C); 0x61 OUT (C), H */ IN_OUT(hl_.bytes.high),
|
||||
/* 0x5e IM 2 */ StdInstr({MicroOp::IM}), /* 0x5f LD A, R */ Instr(6, {MicroOp::Move8, &ir_.halves.low, &a_}, {MicroOp::SetAFlags}),
|
||||
/* 0x60 IN H, (C); 0x61 OUT (C), H */ IN_OUT(hl_.halves.high),
|
||||
/* 0x62 SBC HL, HL */ SBC16(hl_, hl_), /* 0x63 LD (nn), HL */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, hl_)),
|
||||
/* 0x64 NEG */ StdInstr({MicroOp::NEG}), /* 0x65 RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}),
|
||||
/* 0x66 IM 0 */ StdInstr({MicroOp::IM}), /* 0x67 RRD */ StdInstr(Read3(hl_, temp8_), InternalOperation(8), {MicroOp::RRD}, Write3(hl_, temp8_)),
|
||||
/* 0x68 IN L, (C); 0x69 OUT (C), L */ IN_OUT(hl_.bytes.low),
|
||||
/* 0x68 IN L, (C); 0x69 OUT (C), L */ IN_OUT(hl_.halves.low),
|
||||
/* 0x6a ADC HL, HL */ ADC16(hl_, hl_), /* 0x6b LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, hl_)),
|
||||
/* 0x6c NEG */ StdInstr({MicroOp::NEG}), /* 0x6d RETN */ StdInstr(Pop(pc_), {MicroOp::RETN}),
|
||||
/* 0x6e IM 0/1 */ StdInstr({MicroOp::IM}), /* 0x6f RLD */ StdInstr(Read3(hl_, temp8_), InternalOperation(8), {MicroOp::RLD}, Write3(hl_, temp8_)),
|
||||
@ -316,7 +316,7 @@ void ProcessorStorage::assemble_ed_page(InstructionPage &target) {
|
||||
#undef NOP_ROW
|
||||
}
|
||||
|
||||
void ProcessorStorage::assemble_cb_page(InstructionPage &target, RegisterPair &index, bool add_offsets) {
|
||||
void ProcessorStorage::assemble_cb_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets) {
|
||||
#define OCTO_OP_GROUP(m, x) m(x), m(x), m(x), m(x), m(x), m(x), m(x), m(x)
|
||||
#define CB_PAGE(m, p) m(RLC), m(RRC), m(RL), m(RR), m(SLA), m(SRA), m(SLL), m(SRL), OCTO_OP_GROUP(p, BIT), OCTO_OP_GROUP(m, RES), OCTO_OP_GROUP(m, SET)
|
||||
|
||||
@ -343,7 +343,7 @@ void ProcessorStorage::assemble_cb_page(InstructionPage &target, RegisterPair &i
|
||||
#undef CB_PAGE
|
||||
}
|
||||
|
||||
void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair &index, bool add_offsets, InstructionPage &cb_page) {
|
||||
void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets, InstructionPage &cb_page) {
|
||||
#define INC_DEC_LD(r) \
|
||||
StdInstr({MicroOp::Increment8, &r}), \
|
||||
StdInstr({MicroOp::Decrement8, &r}), \
|
||||
@ -360,14 +360,14 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
|
||||
/* 0x02 LD (BC), A */ StdInstr({MicroOp::SetAddrAMemptr, &bc_.full}, Write3(bc_, a_)),
|
||||
|
||||
/* 0x03 INC BC; 0x04 INC B; 0x05 DEC B; 0x06 LD B, n */
|
||||
INC_INC_DEC_LD(bc_, bc_.bytes.high),
|
||||
INC_INC_DEC_LD(bc_, bc_.halves.high),
|
||||
|
||||
/* 0x07 RLCA */ StdInstr({MicroOp::RLCA}),
|
||||
/* 0x08 EX AF, AF' */ StdInstr({MicroOp::ExAFAFDash}), /* 0x09 ADD HL, BC */ ADD16(index, bc_),
|
||||
/* 0x0a LD A, (BC) */ StdInstr({MicroOp::Move16, &bc_.full, &memptr_.full}, Read3(memptr_, a_), Inc16(memptr_)),
|
||||
|
||||
/* 0x0b DEC BC; 0x0c INC C; 0x0d DEC C; 0x0e LD C, n */
|
||||
DEC_INC_DEC_LD(bc_, bc_.bytes.low),
|
||||
DEC_INC_DEC_LD(bc_, bc_.halves.low),
|
||||
|
||||
/* 0x0f RRCA */ StdInstr({MicroOp::RRCA}),
|
||||
/* 0x10 DJNZ */ Instr(6, ReadInc(pc_, temp8_), {MicroOp::DJNZ}, InternalOperation(10), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}),
|
||||
@ -375,7 +375,7 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
|
||||
/* 0x12 LD (DE), A */ StdInstr({MicroOp::SetAddrAMemptr, &de_.full}, Write3(de_, a_)),
|
||||
|
||||
/* 0x13 INC DE; 0x14 INC D; 0x15 DEC D; 0x16 LD D, n */
|
||||
INC_INC_DEC_LD(de_, de_.bytes.high),
|
||||
INC_INC_DEC_LD(de_, de_.halves.high),
|
||||
|
||||
/* 0x17 RLA */ StdInstr({MicroOp::RLA}),
|
||||
/* 0x18 JR */ StdInstr(ReadInc(pc_, temp8_), InternalOperation(10), {MicroOp::CalculateIndexAddress, &pc_.full}, {MicroOp::Move16, &memptr_.full, &pc_.full}),
|
||||
@ -383,21 +383,21 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
|
||||
/* 0x1a LD A, (DE) */ StdInstr({MicroOp::Move16, &de_.full, &memptr_.full}, Read3(memptr_, a_), Inc16(memptr_)),
|
||||
|
||||
/* 0x1b DEC DE; 0x1c INC E; 0x1d DEC E; 0x1e LD E, n */
|
||||
DEC_INC_DEC_LD(de_, de_.bytes.low),
|
||||
DEC_INC_DEC_LD(de_, de_.halves.low),
|
||||
|
||||
/* 0x1f RRA */ StdInstr({MicroOp::RRA}),
|
||||
/* 0x20 JR NZ */ JR(TestNZ), /* 0x21 LD HL, nn */ StdInstr(Read16Inc(pc_, index)),
|
||||
/* 0x22 LD (nn), HL */ StdInstr(Read16Inc(pc_, memptr_), Write16(memptr_, index)),
|
||||
|
||||
/* 0x23 INC HL; 0x24 INC H; 0x25 DEC H; 0x26 LD H, n */
|
||||
INC_INC_DEC_LD(index, index.bytes.high),
|
||||
INC_INC_DEC_LD(index, index.halves.high),
|
||||
|
||||
/* 0x27 DAA */ StdInstr({MicroOp::DAA}),
|
||||
/* 0x28 JR Z */ JR(TestZ), /* 0x29 ADD HL, HL */ ADD16(index, index),
|
||||
/* 0x2a LD HL, (nn) */ StdInstr(Read16Inc(pc_, temp16_), Read16(temp16_, index)),
|
||||
|
||||
/* 0x2b DEC HL; 0x2c INC L; 0x2d DEC L; 0x2e LD L, n */
|
||||
DEC_INC_DEC_LD(index, index.bytes.low),
|
||||
DEC_INC_DEC_LD(index, index.halves.low),
|
||||
|
||||
/* 0x2f CPL */ StdInstr({MicroOp::CPL}),
|
||||
/* 0x30 JR NC */ JR(TestNC), /* 0x31 LD SP, nn */ StdInstr(Read16Inc(pc_, sp_)),
|
||||
@ -418,29 +418,29 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
|
||||
/* 0x3f CCF */ StdInstr({MicroOp::CCF}),
|
||||
|
||||
/* 0x40 LD B, B; 0x41 LD B, C; 0x42 LD B, D; 0x43 LD B, E; 0x44 LD B, H; 0x45 LD B, L; 0x46 LD B, (HL); 0x47 LD B, A */
|
||||
LD_GROUP(bc_.bytes.high, bc_.bytes.high),
|
||||
LD_GROUP(bc_.halves.high, bc_.halves.high),
|
||||
|
||||
/* 0x48 LD C, B; 0x49 LD C, C; 0x4a LD C, D; 0x4b LD C, E; 0x4c LD C, H; 0x4d LD C, L; 0x4e LD C, (HL); 0x4f LD C, A */
|
||||
LD_GROUP(bc_.bytes.low, bc_.bytes.low),
|
||||
LD_GROUP(bc_.halves.low, bc_.halves.low),
|
||||
|
||||
/* 0x50 LD D, B; 0x51 LD D, C; 0x52 LD D, D; 0x53 LD D, E; 0x54 LD D, H; 0x55 LD D, L; 0x56 LD D, (HL); 0x57 LD D, A */
|
||||
LD_GROUP(de_.bytes.high, de_.bytes.high),
|
||||
LD_GROUP(de_.halves.high, de_.halves.high),
|
||||
|
||||
/* 0x58 LD E, B; 0x59 LD E, C; 0x5a LD E, D; 0x5b LD E, E; 0x5c LD E, H; 0x5d LD E, L; 0x5e LD E, (HL); 0x5f LD E, A */
|
||||
LD_GROUP(de_.bytes.low, de_.bytes.low),
|
||||
LD_GROUP(de_.halves.low, de_.halves.low),
|
||||
|
||||
/* 0x60 LD H, B; 0x61 LD H, C; 0x62 LD H, D; 0x63 LD H, E; 0x64 LD H, H; 0x65 LD H, L; 0x66 LD H, (HL); 0x67 LD H, A */
|
||||
LD_GROUP(index.bytes.high, hl_.bytes.high),
|
||||
LD_GROUP(index.halves.high, hl_.halves.high),
|
||||
|
||||
/* 0x68 LD L, B; 0x69 LD L, C; 0x6a LD L, D; 0x6b LD L, E; 0x6c LD L, H; 0x6d LD H, L; 0x6e LD L, (HL); 0x6f LD L, A */
|
||||
LD_GROUP(index.bytes.low, hl_.bytes.low),
|
||||
LD_GROUP(index.halves.low, hl_.halves.low),
|
||||
|
||||
/* 0x70 LD (HL), B */ StdInstr(INDEX(), Write3(INDEX_ADDR(), bc_.bytes.high)),
|
||||
/* 0x71 LD (HL), C */ StdInstr(INDEX(), Write3(INDEX_ADDR(), bc_.bytes.low)),
|
||||
/* 0x72 LD (HL), D */ StdInstr(INDEX(), Write3(INDEX_ADDR(), de_.bytes.high)),
|
||||
/* 0x73 LD (HL), E */ StdInstr(INDEX(), Write3(INDEX_ADDR(), de_.bytes.low)),
|
||||
/* 0x74 LD (HL), H */ StdInstr(INDEX(), Write3(INDEX_ADDR(), hl_.bytes.high)), // neither of these stores parts of the index register;
|
||||
/* 0x75 LD (HL), L */ StdInstr(INDEX(), Write3(INDEX_ADDR(), hl_.bytes.low)), // they always store exactly H and L.
|
||||
/* 0x70 LD (HL), B */ StdInstr(INDEX(), Write3(INDEX_ADDR(), bc_.halves.high)),
|
||||
/* 0x71 LD (HL), C */ StdInstr(INDEX(), Write3(INDEX_ADDR(), bc_.halves.low)),
|
||||
/* 0x72 LD (HL), D */ StdInstr(INDEX(), Write3(INDEX_ADDR(), de_.halves.high)),
|
||||
/* 0x73 LD (HL), E */ StdInstr(INDEX(), Write3(INDEX_ADDR(), de_.halves.low)),
|
||||
/* 0x74 LD (HL), H */ StdInstr(INDEX(), Write3(INDEX_ADDR(), hl_.halves.high)), // neither of these stores parts of the index register;
|
||||
/* 0x75 LD (HL), L */ StdInstr(INDEX(), Write3(INDEX_ADDR(), hl_.halves.low)), // they always store exactly H and L.
|
||||
/* 0x76 HALT */ StdInstr({MicroOp::HALT}),
|
||||
/* 0x77 LD (HL), A */ StdInstr(INDEX(), Write3(INDEX_ADDR(), a_)),
|
||||
|
||||
@ -478,16 +478,16 @@ void ProcessorStorage::assemble_base_page(InstructionPage &target, RegisterPair
|
||||
/* 0xc7 RST 00h */ RST(),
|
||||
/* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ StdInstr(Pop(pc_)),
|
||||
/* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */StdInstr(FINDEX(), {MicroOp::SetInstructionPage, &cb_page}),
|
||||
/* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(ReadInc(pc_, temp16_.bytes.low), Read4Inc(pc_, temp16_.bytes.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}),
|
||||
/* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ StdInstr(ReadInc(pc_, temp16_.halves.low), Read4Inc(pc_, temp16_.halves.high), Push(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}),
|
||||
/* 0xce ADC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::ADC8, &temp8_}),
|
||||
/* 0xcf RST 08h */ RST(),
|
||||
/* 0xd0 RET NC */ RET(TestNC), /* 0xd1 POP DE */ StdInstr(Pop(de_)),
|
||||
/* 0xd2 JP NC */ JP(TestNC), /* 0xd3 OUT (n), A */StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::Move8, &a_, &temp16_.bytes.high}, Output(temp16_, a_)),
|
||||
/* 0xd2 JP NC */ JP(TestNC), /* 0xd3 OUT (n), A */StdInstr(ReadInc(pc_, temp16_.halves.low), {MicroOp::Move8, &a_, &temp16_.halves.high}, Output(temp16_, a_)),
|
||||
/* 0xd4 CALL NC */ CALL(TestNC), /* 0xd5 PUSH DE */ Instr(6, Push(de_)),
|
||||
/* 0xd6 SUB n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SUB8, &temp8_}),
|
||||
/* 0xd7 RST 10h */ RST(),
|
||||
/* 0xd8 RET C */ RET(TestC), /* 0xd9 EXX */ StdInstr({MicroOp::EXX}),
|
||||
/* 0xda JP C */ JP(TestC), /* 0xdb IN A, (n) */StdInstr(ReadInc(pc_, temp16_.bytes.low), {MicroOp::Move8, &a_, &temp16_.bytes.high}, Input(temp16_, a_)),
|
||||
/* 0xda JP C */ JP(TestC), /* 0xdb IN A, (n) */StdInstr(ReadInc(pc_, temp16_.halves.low), {MicroOp::Move8, &a_, &temp16_.halves.high}, Input(temp16_, a_)),
|
||||
/* 0xdc CALL C */ CALL(TestC), /* 0xdd [DD page] */StdInstr({MicroOp::SetInstructionPage, &dd_page_}),
|
||||
/* 0xde SBC A, n */ StdInstr(ReadInc(pc_, temp8_), {MicroOp::SBC8, &temp8_}),
|
||||
/* 0xdf RST 18h */ RST(),
|
||||
|
@ -118,10 +118,10 @@ class ProcessorStorage {
|
||||
void install_default_instruction_set();
|
||||
|
||||
uint8_t a_;
|
||||
RegisterPair bc_, de_, hl_;
|
||||
RegisterPair afDash_, bcDash_, deDash_, hlDash_;
|
||||
RegisterPair ix_, iy_, pc_, sp_;
|
||||
RegisterPair ir_, refresh_addr_;
|
||||
RegisterPair16 bc_, de_, hl_;
|
||||
RegisterPair16 afDash_, bcDash_, deDash_, hlDash_;
|
||||
RegisterPair16 ix_, iy_, pc_, sp_;
|
||||
RegisterPair16 ir_, refresh_addr_;
|
||||
bool iff1_ = false, iff2_ = false;
|
||||
int interrupt_mode_ = 0;
|
||||
uint16_t pc_increment_ = 1;
|
||||
@ -153,7 +153,7 @@ class ProcessorStorage {
|
||||
bool wait_line_ = false;
|
||||
|
||||
uint8_t operation_;
|
||||
RegisterPair temp16_, memptr_;
|
||||
RegisterPair16 temp16_, memptr_;
|
||||
uint8_t temp8_;
|
||||
|
||||
const MicroOp *scheduled_program_counter_ = nullptr;
|
||||
@ -214,7 +214,7 @@ class ProcessorStorage {
|
||||
|
||||
void assemble_fetch_decode_execute(InstructionPage &target, int length);
|
||||
void assemble_ed_page(InstructionPage &target);
|
||||
void assemble_cb_page(InstructionPage &target, RegisterPair &index, bool add_offsets);
|
||||
void assemble_base_page(InstructionPage &target, RegisterPair &index, bool add_offsets, InstructionPage &cb_page);
|
||||
void assemble_cb_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets);
|
||||
void assemble_base_page(InstructionPage &target, RegisterPair16 &index, bool add_offsets, InstructionPage &cb_page);
|
||||
|
||||
};
|
||||
|
174
ROMImages/AtariST/doc/announce.txt
Normal file
174
ROMImages/AtariST/doc/announce.txt
Normal file
@ -0,0 +1,174 @@
|
||||
Dear Atari Community!
|
||||
|
||||
|
||||
We are happy to announce a new public release of EmuTOS:
|
||||
|
||||
EmuTOS 0.9.10 -- December 23, 2018
|
||||
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
|
||||
EmuTOS is a single-user single-tasking operating system for 32-bit Atari
|
||||
computers, clones and emulators. It can be used as a replacement for the
|
||||
TOS images typically needed by emulators and can also run on some real
|
||||
hardware, including the Atari ST(e), TT, and Falcon, and the FireBee. It
|
||||
can even run on non-Atari hardware such as Amiga and ColdFire Evaluation
|
||||
Boards. All the source code is open and free, licensed under the GNU
|
||||
General Public License (GPL).
|
||||
|
||||
|
||||
|
||||
CHANGES SINCE RELEASE 0.9.4
|
||||
|
||||
For a quick summary of changes by release since release 0.9.4, please
|
||||
refer to doc/changelog.txt.
|
||||
|
||||
For a detailed list of all changes since the project started, refer to
|
||||
the Git repository.
|
||||
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
EmuTOS is basically made up of the following:
|
||||
|
||||
- The BIOS, which is the basic input output system
|
||||
- The XBIOS, which provides the interface to the hardware
|
||||
- The BDOS, which are the high level OS routines, often known as GEMDOS
|
||||
- The VDI, the virtual device interface, i.e. the screen driver
|
||||
- The AES, the application environment services or window manager
|
||||
- The EmuDesk desktop, which is the graphical shell to the user
|
||||
- EmuCON2, the command-line interpreter
|
||||
|
||||
The BIOS and XBIOS code is our own development. It is written from
|
||||
scratch and implements all relevant TOS 3 BIOS & XBIOS functionality,
|
||||
and a bit more, e.g. hard disk access. See doc/status.txt for details.
|
||||
|
||||
The GEMDOS part is based on Digital Research's GEMDOS sources, which were
|
||||
made available under GPL license in 1999 by Caldera.
|
||||
|
||||
The graphical parts like VDI and AES are now more or less fully
|
||||
implemented up to TOS v1.04 level. They work in all the graphics modes
|
||||
of the original Atari ST, with some extensions. For example, systems with
|
||||
VIDEL support 256 colours and 640x480 screen resolution. Some emulators
|
||||
can patch EmuTOS to work with much bigger screen resolutions.
|
||||
|
||||
The desktop is now almost as nice as the one in TOS 2 or higher (although
|
||||
there is still work to be done). Of course you are always free to use a
|
||||
more advanced desktop replacement like TeraDesk.
|
||||
|
||||
EmuCON2 is a basic but useful command-line interpreter, written from scratch
|
||||
by Roger Burrows in 2013 to replace the original CLI.
|
||||
|
||||
Since EmuTOS just implements TOS functionality, you might want to use
|
||||
MiNT on top of it in order to run more modern software. EmuTOS is not
|
||||
an alternative to MiNT, but it's the only free base OS to boot MiNT.
|
||||
|
||||
|
||||
|
||||
EMULATION AND FUTURE PLATFORMS
|
||||
|
||||
EmuTOS and MiNT cooperate well. Both can utilize the Native Features
|
||||
(NatFeats) interface for emulators:
|
||||
https://github.com/aranym/aranym/wiki/natfeats-about
|
||||
|
||||
EmuTOS uses this new standard interface for all the relevant native
|
||||
functions supported by an emulator on which it's running. This interface
|
||||
proxies the calls to the underlying host OS so that these features don't
|
||||
need to be emulated. This is both faster and can provide features that
|
||||
would be infeasible on a real machine. It may allow using modern graphics
|
||||
cards, provide fast native filesystem access and enable you to use
|
||||
networking with all bells and whistles - and many other things you might
|
||||
not have even dreamed of.
|
||||
|
||||
The ARAnyM emulator has the most extensive support for NatFeats.
|
||||
The Hatari emulator supports the basic NatFeats facilities.
|
||||
|
||||
|
||||
|
||||
HARDWARE
|
||||
|
||||
Making EmuTOS run natively on a new hardware platform is more or less just
|
||||
a question of driver support for EmuTOS. The same for MiNT, if you'd like
|
||||
to have it running on top of EmuTOS.
|
||||
|
||||
This is the currently supported original Atari hardware:
|
||||
- CPU support for M68000, M68030
|
||||
- FPU detection
|
||||
- 68030 MMU and cache
|
||||
- Memory controller (both ST and Falcon)
|
||||
- TT-RAM
|
||||
- Monitor type detection (mono, RGB or VGA)
|
||||
- DMA controller
|
||||
- WD 1772 / AJAX Floppy disk controller
|
||||
- MFP, MFP #2
|
||||
- PSG
|
||||
- ST shifter
|
||||
- STe shifter
|
||||
- TT shifter
|
||||
- VIDEL
|
||||
- ACIAs, IKBD protocol, mouse
|
||||
- MegaST Real-Time Clock (set clock not tested)
|
||||
- NVRAM (including RTC)
|
||||
- Blitter
|
||||
- Microwire
|
||||
- SCC
|
||||
- IDE
|
||||
- SCSI
|
||||
- ACSI
|
||||
|
||||
EmuTOS also supports the following Atari-compatible hardware:
|
||||
- CPU support for M68010, M68020, M68040, M68060, ColdFire V4e, and Apollo 68080
|
||||
- ICD AdSCSI Plus ST Real-Time Clock
|
||||
- MonSTer expansion card
|
||||
- Nova/ET4000 graphics card
|
||||
- SD/MMC
|
||||
- The Native Features interface to some degree
|
||||
|
||||
Currently unsupported hardware features:
|
||||
- DSP
|
||||
|
||||
EmuTOS is also available on some non-Atari hardware:
|
||||
- Amiga (floppy or ROM for any Amiga, including MapROM support)
|
||||
- ColdFire Evaluation Boards (M5484LITE, M5485EVB)
|
||||
|
||||
|
||||
|
||||
AVAILABILITY
|
||||
|
||||
The EmuTOS home page is:
|
||||
|
||||
http://emutos.sourceforge.net/
|
||||
|
||||
The project home is on SourceForge:
|
||||
|
||||
http://sourceforge.net/projects/emutos/
|
||||
|
||||
The latest releases can be downloaded from:
|
||||
|
||||
http://sourceforge.net/projects/emutos/files/emutos/
|
||||
|
||||
Development snapshots allow you to test the current development progress:
|
||||
|
||||
http://sourceforge.net/projects/emutos/files/snapshots/
|
||||
|
||||
The latest sources are always available on GitHub:
|
||||
|
||||
https://github.com/emutos/emutos
|
||||
|
||||
If you are just curious or would like to help us develop this nice little
|
||||
OS, you are invited to subscribe to our mailing list for developers at:
|
||||
|
||||
https://lists.sourceforge.net/lists/listinfo/emutos-devel
|
||||
|
||||
|
||||
We hope that you like EmuTOS. If you have any suggestions or comments, we
|
||||
always appreciate hearing both the good and the bad things about it.
|
||||
|
||||
|
||||
The EmuTOS development team.
|
||||
|
||||
--
|
||||
Originally written by Martin Doering
|
||||
http://emutos.sourceforge.net/
|
254
ROMImages/AtariST/doc/authors.txt
Normal file
254
ROMImages/AtariST/doc/authors.txt
Normal file
@ -0,0 +1,254 @@
|
||||
EmuTOS source code consists of several parts, and includes code taken from
|
||||
other projects - Many thanks to them and to their authors for releasing the
|
||||
code under GPL.
|
||||
|
||||
The 'historical' authors - those who wrote the code before the start of the
|
||||
EmuTOS project - are mentioned in the individual files they've authored.
|
||||
Major 'historical' parts are:
|
||||
- BDOS, VDI - both come from the latest known GEMDOS version from
|
||||
Digital Research (later versions seem to have been developed by Atari).
|
||||
- AES, desktop - The C source code for GEM comes from the x86 version.
|
||||
- Some GEM assembler files come from the AES for the Apple LISA.
|
||||
|
||||
All these historical parts were released under the General Public License
|
||||
by Caldera, Inc. in mid april 2000 (?) (For the record, Caldera bought it
|
||||
from Novell in 1997 along with DR-DOS; later Caldera disappeared and this
|
||||
is the copyright notice that refers to Lineo)
|
||||
|
||||
Minor borrowed stuff:
|
||||
- the printf and memcpy stuff is inspired by the Minix kernel and library;
|
||||
- the processor/FPU detection is taken from the MiNT kernel;
|
||||
- "Bug" includes parts of the original gettext source code;
|
||||
- some low-level hardware stuff comes from the Linux kernel;
|
||||
|
||||
While the main Amiga support was written from scratch by the EmuTOS team,
|
||||
some advanced code (FastRAM support for ROM versions) has been borrowed from the
|
||||
AROS project. Due to license incompatibilities, that code is shipped in the
|
||||
source archive, but not compiled into the official binaries.
|
||||
|
||||
The following is a list of 'recent' contributors - individuals involved in the
|
||||
EmuTOS project. In this project virtually everybody modifies every file;
|
||||
nevertheless here is an attempt at identifying who's guilty of what:
|
||||
|
||||
Roger Burrows (RFB) <rfburrows at ymail.com>
|
||||
- Current project admin
|
||||
- Support for SD/MMC Cards on the FireBee
|
||||
- SCSI support
|
||||
- Improvements to IDE, CompactFlash, ACSI, and other mass-storage support
|
||||
- FAT16 partitions up to 2 GB (inspired by Didier Méquignon's BDOS fork)
|
||||
- Full support for Falcon video hardware
|
||||
- Real Falcon 030 support (cache, MMU, SCC, HD floppy)
|
||||
- Real TT 030 support (video, MFP2)
|
||||
- Blitter support for horizontal lines/filled rectangles/raster graphics
|
||||
- Desktop and file selector improvements
|
||||
- EmuCON2
|
||||
- Tools: erd (EmuTOS Resource Decompiler) & draft (deletes items from desktop resource)
|
||||
- Various bugfixes and cleanups
|
||||
|
||||
Vincent Rivière (VRI) <vincent.riviere at freesbee.fr>
|
||||
- Many improvements to the build and configuration process
|
||||
- Moved project from CVS to Git, and from SourceForge to GitHub
|
||||
- Implemented automatic builds via Travis CI
|
||||
- Patches for compiling with GCC 4.x
|
||||
- ColdFire CPU and FireBee support
|
||||
- Initial IDE driver
|
||||
- Big improvements to FastRAM/Alt-RAM handling
|
||||
- Amiga support
|
||||
- ColdFire Evaluation Boards support
|
||||
- Apollo 68080 support
|
||||
- Various bug fixes and cleanups
|
||||
|
||||
Thomas Huth (THH) <huth at tuxfamily.org>
|
||||
- Lots of bugfixes & cleanups all over the place
|
||||
- Integration and maintenance of the AES and GEM-Desktop
|
||||
- XBIOS DMA sound functions
|
||||
|
||||
Petr Stehlik (PES) <pstehlik at sophics.cz>
|
||||
- BIOS disk interface, BDOS filesystem
|
||||
- Falcon and ARAnyM support
|
||||
|
||||
Laurent Vogel (LVL) <lvl at club-internet.fr>
|
||||
- Original ST hardware (MFP, ACIA, parport, sound, floppy, ACSI)
|
||||
- Makefile tricks and tools
|
||||
- NLS support
|
||||
|
||||
Martin Doering (MAD) <mdoering at users.sourceforge.net>
|
||||
- Original project initiator (but retired many years ago)
|
||||
- Memory setup, VT52 console, Line A, mouse
|
||||
- Virtually everything not modified later by the others
|
||||
|
||||
|
||||
Thanks to all current and previous translators, who have helped us keep
|
||||
EmuTOS multi-lingual:
|
||||
|
||||
- Czech translation
|
||||
Bohdan Milar <milarb at volny.cz>
|
||||
Petr Stehlik <pstehlik at sophics.cz>
|
||||
Pavel Salač <salac.pavel at gmail.com>
|
||||
Jan Krupka <krupkaj at centrum.cz>
|
||||
|
||||
- Finnish translation
|
||||
Eero Tamminen
|
||||
|
||||
- French translation
|
||||
Laurent Vogel
|
||||
Vincent Rivière
|
||||
|
||||
- German translation
|
||||
Thomas Huth
|
||||
|
||||
- Greek translation
|
||||
George Nakos
|
||||
Christos Tziotzis <ctziotzis at gmail.com>
|
||||
|
||||
- Italian translation
|
||||
Lodovico Zanier <lvc958 at libero.it>
|
||||
|
||||
- Spanish translation
|
||||
Gabriel Huertas
|
||||
David Gálvez <dgalvez75 at gmail.com>
|
||||
Jordi Mestres Ruiz <ataristfan at gmail.com>
|
||||
|
||||
- Russian translation
|
||||
Dima Sobolev <avtandil33 at gmail.com>
|
||||
|
||||
|
||||
Thanks also to all mailing list contributors for their help, and
|
||||
especially:
|
||||
|
||||
Stanislav Opichal (SOP) <opichals at seznam.cz>
|
||||
- FreeMiNT kernel bootstrap via BOOTSTRAP NatFeat
|
||||
|
||||
Frank Naumann
|
||||
- FreeMiNT
|
||||
|
||||
Ctirad Fertr <phanatic at volny.cz>,
|
||||
Milan Jurik <M.Jurik at sh.cvut.cz>
|
||||
- The ARanyM team
|
||||
|
||||
Johan Klockars <rand at cd.chalmers.se>
|
||||
- fVDI
|
||||
|
||||
Henk Robbers <h.robbers at chello.nl>
|
||||
- XaAES, AHCC
|
||||
|
||||
Jacques-Etienne Rahon "Kevin Flynn" <kevin.flynn at wanadoo.fr>
|
||||
- Extensive demo testing on STeeM
|
||||
|
||||
Patrice Mandin and Markus Oberhumer
|
||||
- Hints and patches for compiling EmuTOS with GCC 3.x
|
||||
|
||||
Eero Tamminen
|
||||
- Many bug reports, extensive testing, testcases supply
|
||||
- Many documentation updates
|
||||
- Finnish keyboard mapping
|
||||
- Hatari debug symbols
|
||||
- Static source analysis and cleanup
|
||||
- Line-A implementation
|
||||
|
||||
Gerhard Stoll
|
||||
- Improved our nvmaccess() function
|
||||
- TOS hypertext
|
||||
|
||||
Roger Crettol
|
||||
- Found and fixed a bug in GEMDOS Pterm() function
|
||||
- Support for swiss german keyboard
|
||||
- Some EmuCON improvements
|
||||
|
||||
David Savinkoff
|
||||
- Bug fixes for the BIOS parallel port code
|
||||
- Improved Isqrt() function
|
||||
- Other various bugfixes
|
||||
|
||||
Olivier Landemarre <olivier.landemarre at free.fr>
|
||||
- Renamed internal VDI functions to avoid name conflicts
|
||||
|
||||
Jean-François Del Nero <jeanfrancoisdelnero at free.fr>
|
||||
- Improved memory detection on cold boot
|
||||
- Tested the EmuTOS ROM on real STe hardware
|
||||
- Various bugfixes
|
||||
- Invaluable HxC Floppy Emulator for tests on real hardware
|
||||
|
||||
David Gálvez <dgalvez75 at gmail.com>
|
||||
- XHNewCookie() implementation
|
||||
|
||||
Fredi Aschwanden <mcs at kingx.com>
|
||||
and all the ACP team
|
||||
- Tests on the FireBee hardware
|
||||
|
||||
James Boulton <james.boulton at eiconic.com>
|
||||
- floprw() fix for reading multiple sectors
|
||||
|
||||
Stephen Leary <sleary at vavi.co.uk>
|
||||
- Fixed support for IDE slave device
|
||||
|
||||
Miro Kropáček <miro.kropacek at gmail.com>
|
||||
- Experimental 68040 MMU support
|
||||
|
||||
WongCK on Atari-Forum
|
||||
- Tests on real Falcon 030
|
||||
|
||||
Michaël Gibs on English Amiga Board
|
||||
- Tests on Amiga 1200 with Blizzard 1260 accelerator
|
||||
|
||||
Amiman99 on English Amiga Board
|
||||
- Tests on Amiga 1000
|
||||
|
||||
Radoslaw Kujawa
|
||||
- Compilation fix on 64-bit build systems
|
||||
|
||||
Hampa Hug
|
||||
- Fixed ACSI bugs
|
||||
|
||||
Markus Fröschle
|
||||
- Tests on the FireBee and BaS_gcc support
|
||||
- Inspired the support for the blitter
|
||||
- Fix various AES & VDI bugs
|
||||
|
||||
Christian Zietz <czietz at gmx.net>
|
||||
- ROM tests on real ST/STe hardware
|
||||
- Fix floppy/ACSI bug
|
||||
- Fix memory detection to support STs as well as STes
|
||||
- Support for extended MBR partitions
|
||||
- Add IDE 'twisted cable' support
|
||||
- IDE performance improvements
|
||||
- Fix cold boot problems caused by some ST MMUs
|
||||
- Fix screen corruption after a reset on some Mega(STe) systems
|
||||
- ET4000/Nova support
|
||||
- Miscellaneous bug fixes
|
||||
|
||||
Jo Even Skarstein <joska at online.no>
|
||||
- Support for Norwegian & Swedish keyboards
|
||||
- Support for MonSTer add-on board
|
||||
|
||||
Thorsten Otto <admin at tho-otto.de>
|
||||
- Make EmuTOS more compatible with Atari TOS in several areas
|
||||
- Add check_read_byte() workaround for ARAnyM-JIT
|
||||
- Fixes to 68040 PMMU setup
|
||||
- Inspired the support for window/desktop background configuration
|
||||
- Found many bugs in desktop shortcut handling
|
||||
- Help with resource manipulation programs
|
||||
- Miscellaneous bug fixes
|
||||
- Lots of source code cleanup
|
||||
|
||||
Apollo Team: Gunnar von Boehn, Philippe Flype, Simo Koivukoski,
|
||||
pisklak, guibrush, TuKo, and all other members...
|
||||
- Apollo 68080 and Amiga support
|
||||
|
||||
Steven Seagal
|
||||
- Steem SSE support
|
||||
|
||||
Stefan Niestegge
|
||||
- ROM tests on real hardware: STe, Falcon and Amiga 600
|
||||
|
||||
Ingo Uhlemann
|
||||
- ROM tests on real TT hardware
|
||||
|
||||
Stefan Haubenthal
|
||||
- EmuTOS packaging on Aminet: http://aminet.net/package/misc/emu/emutos
|
||||
|
||||
Christian Quante
|
||||
- Various desktop bug fixes & improvements
|
||||
|
||||
Keli Hlodversson
|
||||
- Replaced form_alert() icons with more TOS-like ones
|
59
ROMImages/AtariST/doc/bugs.txt
Normal file
59
ROMImages/AtariST/doc/bugs.txt
Normal file
@ -0,0 +1,59 @@
|
||||
AES/VDI/Line-A bugs:
|
||||
- The right side of outline characters are clipped e.g. in "LaserChess",
|
||||
"Diamond miner" & "Minigolf" games, and in vditext tester:
|
||||
https://sourceforge.net/p/emutos/mailman/message/29276993/
|
||||
This is due to a bug somewhere in the ugly text_blt() assembler
|
||||
function in vdi_tblit.S.
|
||||
- Thick arcs going partly outside of screen have incorrectly
|
||||
drawn pixels at top of screen in vdiline tester.
|
||||
- In "MathMaze" and "The Ultimate Minesweeper", game win and score
|
||||
dialogs leave left/bottom outline on screen when they close.
|
||||
- Dialog box at the end of Glücksrad game is missing text from
|
||||
the dialog button (and the button width isn't correct)
|
||||
- Line-A polygons are one pixel short at both sides. This is
|
||||
because clc_flit() function does it for VDI (where perimeter
|
||||
is drawn separately). It is visible e.g. in "Japlish" game.
|
||||
|
||||
Video problems:
|
||||
- Omega's XiTec presentations "swing.prg" throws privilege exception
|
||||
on exit. Both TOS v3 & EmuTOS survive that OK, but in EmuTOS both
|
||||
screen and mouse acceleration are messed up: EmuTOS exception restore
|
||||
is missing videomode & mouse reset.
|
||||
|
||||
Atari Falcon / TOS v4 compatibility bugs:
|
||||
- Escape Paint icons don't show in image operations window and their
|
||||
place in toolbar window is inverted on mouse click.
|
||||
- Falcon FalcAMP button icons aren't visible as EmuTOS doesn't support
|
||||
new style RSC files with CICONs.
|
||||
|
||||
Problems that also occur in Atari TOS:
|
||||
- VDI: when drawing a wide polyline with squared ends and more than one
|
||||
segment, if the width of the line is greater than twice the length of
|
||||
an ending segment, the end will have a bump rather than being square.
|
||||
This is because wideline segments are joined by using filled circles
|
||||
whose radius is half the width of the line: the bump is a protruding
|
||||
part of the circle that joins the end segment to the previous one.
|
||||
|
||||
Links to programs listed above:
|
||||
- Diamond Miner:
|
||||
http://www.atarimania.com/game-atari-st-diamond-miner_31993.html
|
||||
- Escape Paint:
|
||||
http://www.pouet.net/prod.php?which=25328
|
||||
- FalcAMP:
|
||||
http://deunstg.free.fr/sct1/falcamp/
|
||||
- Glücksrad:
|
||||
http://www.atarimania.com/game-atari-st-glucksrad-st_22001.html
|
||||
- Japlish:
|
||||
http://www.ntrautanen.fi/marko/arkisto.atari.org/sivut/menu_pelit.htm
|
||||
- Laserchess:
|
||||
http://www.atarimania.com/game-atari-st-laserchess_31257.html
|
||||
- Minigolf (GFA):
|
||||
http://eerott.mbnet.fi/hatari/sources/minigolf.zip
|
||||
- Swing:
|
||||
http://www.pouet.net/prod.php?which=52370
|
||||
- The Ultimate Minesweeper:
|
||||
http://www.pouet.net/prod.php?which=28904
|
||||
- VDI line/text tester:
|
||||
http://eerott.mbnet.fi/hatari/programs.shtml#vditest
|
||||
|
||||
(Links missing to: mathmaze.)
|
361
ROMImages/AtariST/doc/changelog.txt
Normal file
361
ROMImages/AtariST/doc/changelog.txt
Normal file
@ -0,0 +1,361 @@
|
||||
CHANGES BETWEEN RELEASE 0.9.9.1 AND RELEASE 0.9.10
|
||||
|
||||
Major changes:
|
||||
- AES: Avoid unnecessary redraws by AES window manager
|
||||
- AES: Fix shutdown bug in shel_write()
|
||||
- BDOS: Improve BDOS write file performance
|
||||
- BDOS: Improve BDOS sector caching algorithm
|
||||
- BDOS: Avoid unnecessary directory sector writes in BDOS
|
||||
- BDOS: Improve Fsnext() performance
|
||||
- BIOS: Add SCSI support for TT and Falcon
|
||||
- BIOS: Implement support for ET4000 graphics card
|
||||
- BIOS: Implement automatic verify for floppy writes
|
||||
- BIOS: Improve IDE data transfer speed
|
||||
- BIOS: Improve TT RAM size detection for Storm cards
|
||||
- BIOS: Fix reboot loop if Ctrl+Alt+Del held down
|
||||
- EmuCON: Allow resolution change in EmuCON
|
||||
- EmuDesk: Clean up if EmuDesk terminates abnormally
|
||||
- EmuDesk: Fix bug in EmuDesk copy function
|
||||
- EmuDesk: Fix EmuDesk out-of-sequence redraws
|
||||
- EmuDesk: Make EmuDesk menu for icon/text selection like Atari TOS
|
||||
- VDI: Improve the appearance of VDI curved lines
|
||||
|
||||
Other changes:
|
||||
- AES: Do not set the scrap directory in appl_init()
|
||||
- AES: Do not validate the path supplied to scrp_write()
|
||||
- AES: Fix appl_tplay()
|
||||
- AES: Fix appl_trecord()
|
||||
- AES: Fix bug in setting application directory
|
||||
- AES: Fix file selector bug
|
||||
- AES: Handle SHADOWED correctly for form_center()
|
||||
- AES: Make form_center() behave like Atari TOS
|
||||
- AES: Preserve DTA address across shel_find()
|
||||
- BDOS: Increase max length of fully-qualified filename
|
||||
- BIOS: Fix bug in VT52 emulation
|
||||
- BIOS: Fix bug in rsconf handling for SCC
|
||||
- BIOS: Fix bugs in keyboard mouse emulation
|
||||
- BIOS: Fix end-of-partition test in Rwabs()
|
||||
- BIOS: Fix screen corruption on some (Mega)STe systems
|
||||
- BIOS: Improve FAT12/FAT16/FAT32 detection
|
||||
- BIOS: Increase default keyboard auto-repeat speed
|
||||
- BIOS: Remove IDE delay on Amiga
|
||||
- BIOS: Remove unneeded delay when accessing the FDC
|
||||
- EmuDesk: Allow 'Show item' to handle multiple items
|
||||
- EmuDesk: Fix bug in EmuDesk change resolution handling
|
||||
- EmuDesk: Fix bug in EmuDesk copy process when disk is full
|
||||
- EmuDesk: Fix display bug in EmuDesk initialisation
|
||||
- EmuDesk: Fix EmuDesk mouse cursor initialisation
|
||||
- EmuDesk: Fix label bug when formatting floppy
|
||||
- EmuDesk: Fix 'name conflict' bug in copy/move folders
|
||||
- LineA: Fix bug that affected Aegis Animator
|
||||
- LineA: Implement early abort for lineA seedfill()
|
||||
- VDI: Fix bug in v_opnvwk()
|
||||
- VDI: Fix contourfill() for 8 planes
|
||||
- VDI: Fix design bug in VDI workstation creation
|
||||
- XBIOS: Fix crash if Vsetscreen() sets TrueColor mode
|
||||
- XBIOS: Improve performance of Flopver()
|
||||
- The usual source code cleanup and minor bug fixes
|
||||
|
||||
|
||||
CHANGES BETWEEN RELEASE 0.9.9 AND RELEASE 0.9.9.1
|
||||
|
||||
There was only one change, to fix a major bug in EmuDesk: if a desktop
|
||||
shortcut for a file/folder was dragged to the trash or a disk icon or
|
||||
an open window, then all the folders at the same level as the selected
|
||||
file/folder were included in the operation, causing unwanted deletes/
|
||||
moves/copies.
|
||||
|
||||
|
||||
CHANGES BETWEEN RELEASE 0.9.8 AND RELEASE 0.9.9
|
||||
|
||||
Major changes:
|
||||
- AES: Allow mouse cursors to be loaded at boot time
|
||||
- EmuDesk: Add 'Desktop configuration' dialog
|
||||
- EmuDesk: Allow configuration of window/desktop backgrounds
|
||||
- EmuDesk: Allow desktop window file mask to be specified
|
||||
- EmuDesk: Omit unused desktop menu items
|
||||
- EmuDesk: Open new window with Alt+doubleclick on folder
|
||||
- General: Automatically build snapshot releases when a commit is pushed
|
||||
- VDI: Add blitter support for horizontal line drawing
|
||||
- VDI: Add blitter support for filled rectangle drawing
|
||||
- VDI: Add blitter support for raster graphics
|
||||
|
||||
Other changes:
|
||||
- AES: Add growbox/shrinkbox effects to form_dial()
|
||||
- AES: Allow AES USERDEFs to clobber a2/d2 (improve compatibility)
|
||||
- AES: Call dsptch() on every AES call (improve responsiveness)
|
||||
- AES: Ensure all DAs see AC_CLOSE before app exits
|
||||
- AES: Fix problem with mouse clicks being ignored
|
||||
- AES: Improve mouse cursor images
|
||||
- AES: Only wait for interrupts when nobody is ready to run
|
||||
- AES: Replace icons used in alerts
|
||||
- BIOS: Do not use stack until memory is initialized
|
||||
- BIOS: Ensure ST MMU register contains valid value
|
||||
- BIOS: Ensure GetBPB() returns NULL for non-FAT partitions
|
||||
- BIOS: Fix Mega STe boot problem
|
||||
- BIOS: Fix XHDrvMap() to return correct value
|
||||
- BIOS: Fix bug in memset/bzero clearing only 16MB at most
|
||||
- BIOS: Implement XHDOSLimits (read only)
|
||||
- BIOS: Amiga/Vampire V2: do not enable Fast IDE by default
|
||||
- EmuDesk: Add blitter menu item to desktop
|
||||
- EmuDesk: Add support for desktop drag-and-drop in window
|
||||
- EmuDesk: Allow any character as date separator
|
||||
- EmuDesk: Allow copy/move to desktop shortcut for a folder
|
||||
- EmuDesk: Always issue alert if no windows are available
|
||||
- EmuDesk: Do not open desktop directory if error occurs
|
||||
- EmuDesk: Dragging to desktop shortcut for program now launches it
|
||||
- EmuDesk: Fix 'Install application' bug w/ desktop shortcut
|
||||
- EmuDesk: Fix alignment of desktop icons on a grid
|
||||
- EmuDesk: Fix bug: desktop didn't open window for empty drives
|
||||
- EmuDesk: Fix default dir for programs launched from desktop
|
||||
- EmuDesk: Fix tail passed by desktop to shel_write()
|
||||
- EmuDesk: Highlight file shortcut when dropping file on it
|
||||
- EmuDesk: Improve launching of programs via desktop shortcut
|
||||
- EmuDesk: Include wildcard spec in desktop window name
|
||||
- EmuDesk: Make the desktop shel_write() the full pathname
|
||||
- VDI: Add support for lineA TextBlt write modes 4-19
|
||||
- VDI: Fix VDI crash when running MiNT + memory protect
|
||||
- VDI: Fix crash when font scaling in lineA text_blt()
|
||||
- VDI: Handle bad rotation value in gdp_justified()
|
||||
- VDI: Translate text_blt() high level code to C
|
||||
- XBIOS: Fix EsetColor() when color < 0
|
||||
- The usual source code cleanup and minor bug fixes
|
||||
|
||||
|
||||
CHANGES BETWEEN RELEASE 0.9.7 AND RELEASE 0.9.8
|
||||
|
||||
Major changes:
|
||||
- Amiga: New boot floppy target
|
||||
- Amiga: Rewrite floppy routines
|
||||
- Amiga: Support multiple video modes
|
||||
- BIOS: Autodetect IDE interface with twisted cable at run-time
|
||||
- EmuDesk: Add support for desktop shortcuts
|
||||
- EmuDesk: Add support for formatting floppies
|
||||
- EmuDesk: Add support for user-assignable desktop icons
|
||||
|
||||
Other changes:
|
||||
- AES: Adjust file selector scroll bar width according to resolution
|
||||
- AES: Allocate Alt-RAM instead of ST-RAM where possible
|
||||
- AES: Do not use shel_find() to find autorun program
|
||||
- AES: Fix bug in rsrc_load() that affected PixArt4
|
||||
- AES: Fix error message if autorun program is not found
|
||||
- AES: Fix possible data corruption when launching accessories
|
||||
- AES: Increase min height of slider in file selector
|
||||
- Amiga: Add support for IKBD keyboard/mouse/joysticks on RS-232
|
||||
- Amiga: Fix interlaced display with fast CPU
|
||||
- Amiga: Add target to build ROM optimized for Vampire V2
|
||||
- Amiga: Add XBIOS joystick support
|
||||
- Amiga: Improve IDE performance on Vampire V2
|
||||
- Amiga: Improve IDE support
|
||||
- Amiga: Add proper floppy media change support
|
||||
- BDOS: Allow environment to be allocated in Alt-RAM
|
||||
- BDOS: Fix bug in updating date when month rolls over
|
||||
- BDOS: Fix Fsfirst(): wrong name format in DTA for label
|
||||
- BDOS: Speed up Dfree() for 16-bit FATs
|
||||
- BIOS: Add movep emulation for 68060
|
||||
- BIOS: Enable data cache on 68040 & 68060
|
||||
- BIOS: Enable instruction & branch caches on 68060
|
||||
- BIOS: Fix ACSI bug: non-word-aligned transfers failed
|
||||
- BIOS: Fix bug in IDE detection of slower devices
|
||||
- BIOS: Fix crash with unaligned IDE R/W buffer on 68000
|
||||
- BIOS: Fix floppy bug: non-word-aligned I/Os failed
|
||||
- BIOS: Improve IDE performance
|
||||
- BIOS: Improve mediachange detection
|
||||
- ColdFire: Add RAM TOS target for ColdFire Evaluation Boards
|
||||
- EmuDesk: Add documentation for new features
|
||||
- EmuDesk: Add read-only indicator for show-as-text display
|
||||
- EmuDesk: Allocate Alt-RAM instead of ST-RAM where possible
|
||||
- EmuDesk: Fix various bugs in desktop copy/move
|
||||
- EmuDesk: Handle desktop move/copy of folder to itself
|
||||
- EmuDesk: Holding Control at startup now bypasses all initialisation files
|
||||
- EmuDesk: Lookup desktop shortcuts directly in menu
|
||||
- EmuDesk: Make alt-X open the root of X in a window
|
||||
- EmuDesk: Make desktop keyboard shortcuts use Ctrl modifier
|
||||
- EmuDesk: Make desktop shortcut keys work for all keyboards
|
||||
- EmuDesk: Split preferences dialog to allow longer text
|
||||
- General: Allow EmuTOS static RAM to be allocated in Alt-RAM
|
||||
- The usual source code cleanup and minor bug fixes
|
||||
|
||||
|
||||
CHANGES BETWEEN RELEASE 0.9.6 AND RELEASE 0.9.7
|
||||
|
||||
Major changes:
|
||||
- BIOS: add support for extended MBR partitions
|
||||
- BIOS: add support for MonSTer board
|
||||
- BIOS: configure & size ST-RAM on TT
|
||||
- BIOS: add support for Eiffel on CAN bus on ColdFire EVB
|
||||
- BIOS: add _5MS cookie to support FreeMiNT on non-Atari hardware
|
||||
- BIOS: add support for Apollo Core 68080
|
||||
- BDOS: set archive flag when file is created/modified
|
||||
- EmuDesk: allow disk delete via desktop File menu item
|
||||
- EmuDesk: implement desktop 'Install devices'
|
||||
- EmuDesk: implement desktop 'Install icon'
|
||||
- EmuDesk: implement desktop 'Remove desktop icon'
|
||||
- EmuDesk: rewrite 'Install application'
|
||||
- EmuCON2: provide a standalone version of EmuCON2
|
||||
|
||||
Other changes:
|
||||
- AES: allow autorun program to start in character mode
|
||||
- AES: fix bug when File Selector accesses empty drive
|
||||
- AES: fix loop in file selector if filemask is too long
|
||||
- AES: fix bug: the file selector modified the DTA pointer
|
||||
- AES: rewrite wildcmp() to fix bug
|
||||
- BDOS: fix GEMDOS standard handle numbers
|
||||
- BDOS: rewrite Fsfirst/Fsnext to fix design problem
|
||||
- BDOS: use single pool for all internal memory requests
|
||||
- BDOS: fix I/O status for redirected character devices
|
||||
- BDOS: fix date stamp in . and .. directory entries
|
||||
- BDOS: fix return code for Fsfirst()
|
||||
- BDOS: make EmuTOS respect user-assigned FRB
|
||||
- BDOS: make ctl-C interrupt Cconin
|
||||
- BDOS: return EOF indicator on redirected char devices
|
||||
- BDOS: validate attribute bits passed to Fattrib()
|
||||
- BDOS: validate handles for Fseek()/Fread()/Fwrite()/Fdatime()
|
||||
- BIOS: add Norwegian & Swedish keyboard support
|
||||
- BIOS: add support for byte-swapped IDE cable (disabled by default)
|
||||
- BIOS: allow configuration of max logical sector size
|
||||
- BIOS: fix VDI->hardware colour calculation
|
||||
- BIOS: fix os_conf value and usage in multilanguage ROMs
|
||||
- BIOS: improve performance of Rwabs() on floppy disks
|
||||
- BIOS: make Ikbdws()/Midiws() handle 'cnt' like Atari TOS
|
||||
- BIOS: set density for read/write/format of HD floppies
|
||||
- BIOS: fix boot on Amiga with 68000 CPU
|
||||
- BIOS: fix RAM size with BaS_gcc on ColdFire EVB
|
||||
- BIOS: fix _FPU cookie for 68060 without FPU
|
||||
- BIOS: fix values returned by VgetRGB()/vq_color()
|
||||
- EmuDesk: make desktop shift-click behave the same as TOS
|
||||
- EmuDesk: prompt if folder name conflict during move/copy
|
||||
- EmuDesk: make many desktop and AES dialogs more concise
|
||||
- EmuDesk: fix desktop icon drag and drop positioning
|
||||
- EmuDesk: allow 'Too many windows' alert to be issued
|
||||
- EmuDesk: always issue extra alert if deleting entire disk
|
||||
- EmuDesk: always keep part of the mover gadget onscreen
|
||||
- EmuDesk: avoid unnecessary window refreshes
|
||||
- EmuDesk: handle name conflict during copy like Atari TOS
|
||||
- EmuDesk: support additional keys during "Show file"
|
||||
- EmuDesk: add copyright year in EmuDesk about dialog
|
||||
- General: display total RAM on welcome screen
|
||||
- General: fix _drvbits tests for drives > P
|
||||
- VDI: fix rectangle drawing errors
|
||||
- VDI: fix bug: v_bar() draws perimeter wrongly
|
||||
- VDI: fix vq_curaddress(), vs_curaddress()
|
||||
- Lots of source code cleanup and minor bug fixes
|
||||
|
||||
|
||||
CHANGES BETWEEN RELEASE 0.9.5 AND RELEASE 0.9.6
|
||||
|
||||
Major changes:
|
||||
- AES: fix pattern problem in window title line
|
||||
- AES: prevent crash when NVDI is installed
|
||||
- BDOS: fix bug: memory allocated by a TSR could be freed
|
||||
- BDOS: implement etv_term()
|
||||
- BIOS: clean up pending IRQ from flopunlk(), fixes some ACSI problems
|
||||
- BIOS: clear data cache after DMA read, fixes ACSI problem on TT
|
||||
- BIOS: do not clear the free ST-RAM on startup
|
||||
- BIOS: enable MIDI input
|
||||
- BIOS: initialise DMA sound matrix on Falcon
|
||||
- BIOS: fix Flopxxx XBIOS calls to work with FastRAM
|
||||
- BIOS: fix floppy motor-on problem during initialisation
|
||||
- BIOS: fix memory bank detection to work on ST and STe
|
||||
- BIOS: prevent reset vector being called on cold reset
|
||||
- EmuCON2: add 'mode' command
|
||||
- EmuCON2: fix EmuCON crash if system call is intercepted
|
||||
- EmuDesk: allow TT desktop to select TT medium res
|
||||
- EmuDesk: fix bug: copy/move could target the wrong folder
|
||||
- EmuDesk: fix display of numeric values in desktop dialogs
|
||||
- EmuDesk: fix rubber-banding for text-mode desktop windows
|
||||
- EmuDesk: hide Shutdown if the machine can't shutdown
|
||||
- EmuDesk: improve desktop move performance by using rename if possible
|
||||
- EmuDesk: change menu bar to be more like Atari TOS
|
||||
- General: fix EmuTOS to run on real TT hardware
|
||||
- General: merge boot.prg + ramtos.img into emutos.prg
|
||||
- VDI: fully implement VDI support for TT video
|
||||
|
||||
Other changes:
|
||||
- AES: clean up if program fails to issue appl_exit()
|
||||
- AES: fix loop when deleting non-existent object
|
||||
- AES: fix handling of Delete key by objc_edit()
|
||||
- AES: fix value returned by evnt_button()/evnt_multi()
|
||||
- AES: reset the default drive on resolution change
|
||||
- BDOS: fix volume label handling to conform to TOS standards
|
||||
- BIOS: add new cookie _MCF to the cookiejar
|
||||
- BIOS: add support for RTC on ICD AdSCSI Plus board
|
||||
- BIOS: add support for TT MFP (MFP #2)
|
||||
- BIOS: add support to run "reset-resident" code
|
||||
- BIOS: allow EmuTOS floppy to boot other floppies
|
||||
- BIOS: clear system variables if EmuTOS loads into RAM
|
||||
- BIOS: fix console font height with Hatari extended video modes
|
||||
- BIOS: fix ide_identify() on Amiga
|
||||
- BIOS: fix NVRAM year on TT
|
||||
- BIOS: fix return codes for dmasound functions on ST
|
||||
- BIOS: fix return codes for TT shifter functions
|
||||
- BIOS: fix some NVRAM reset problems
|
||||
- BIOS: fix sound volume on TT
|
||||
- BIOS: fix _screenpt processing for TT, Falcon
|
||||
- BIOS: flush the data cache before a warm or cold reset
|
||||
- BIOS: initialize the IKBD clock on first boot only
|
||||
- BIOS: rewrite MegaST(e) real time clock handler
|
||||
- EmuCON2: fix EmuCON welcome message for ST-Low
|
||||
- EmuDesk: add 'No sort' to desktop sort options
|
||||
- EmuDesk: add desktop shortcuts for scroll-by-page
|
||||
- EmuDesk: ensure desktop menu bar fits within screen
|
||||
- EmuDesk: fix display of volume label in disk info dialog
|
||||
- EmuDesk: improve EMUDESK.INF error checking
|
||||
- EmuDesk: show the emulated machine name on Hatari even with --natfeats yes
|
||||
- General: always use STOP instruction in 'wait for interrupt' loops
|
||||
- General: create valid filesystem with hidden EmuTOS image on auto-booting floppy
|
||||
- General: do not wait for a key at EMUTOS.PRG startup
|
||||
- General: pretend to be TOS 1.04 in 192k ROMs
|
||||
- General: use country id as part of emutos.prg/emutos.st name
|
||||
- VDI: fix v_curtext()
|
||||
- VDI: implement vq_curaddress()
|
||||
- VDI: improve performance of cursor display routine
|
||||
- VDI: rewrite vr_trnfm() to fix bugs and save space
|
||||
- Lots of source code cleanup and minor bug fixes
|
||||
|
||||
|
||||
CHANGES BETWEEN RELEASE 0.9.4 AND RELEASE 0.9.5
|
||||
|
||||
Major changes:
|
||||
- AES/BIOS: implement critical error handler
|
||||
- BDOS: fix file not found issues with Steem hard disk emulation
|
||||
- BDOS: implement Pexec mode 7
|
||||
- BIOS: add alt-arrow support (mouse actions via keyboard)
|
||||
- BIOS: add dual keyboard support (for Greek/Russian keyboards)
|
||||
- BIOS: allow user to specify boot partition at startup
|
||||
- BIOS: allow EmuTOS to recover from program exceptions in user programs
|
||||
- BIOS: auto-detect multiple IDE interfaces
|
||||
- BIOS: fix detection of C: drive with Steem
|
||||
- BIOS: fix early stack initialization on Amiga
|
||||
- EmuDesk: improve text object alignment for translated strings
|
||||
- VDI: add line-A flood fill; all line-A opcodes are now supported
|
||||
|
||||
Other changes:
|
||||
- AES: increase button spacing in alerts
|
||||
- AES: increase AES stack size for ColdFire machines
|
||||
- BDOS: evaluate TPAsize flags in Pexec processing
|
||||
- BDOS: fix bug in cross-directory rename
|
||||
- BIOS: use interrupts for serial console instead of polling
|
||||
- BIOS: fix FPU detection: 68881/68882 are now differentiated correctly
|
||||
- BIOS: fix delay_loop() timing for M548X machines
|
||||
- BIOS: fix key repeat bug when entering values via alt-keypad
|
||||
- BIOS: implement XHInqDriver() XHDI function
|
||||
- BIOS: fix some XHDI return codes (EDRIVE and EWRPRO)
|
||||
- BIOS: add explicit delay for parallel port strobe (fixes printing on fast systems)
|
||||
- BIOS: fix nationality code in ROM header
|
||||
- EmuCON2: translate text (note: some country codes use English by choice)
|
||||
- EmuDesk: allow folders being displayed in an open window to be moved/deleted
|
||||
- EmuDesk: allow desktop "rubber-banding" in all directions
|
||||
- EmuDesk: display year as 4 digits where possible
|
||||
- EmuDesk: use _IDT cookie for EmuDesk date/time formatting
|
||||
- EmuDesk: fix bug in "sort by date" for directory display
|
||||
- EmuDesk: allocate screen objects dynamically
|
||||
- General: convert source code repository to Git
|
||||
- General: implement error checking for translated alerts
|
||||
- General: replace "make release-version" with "make version"
|
||||
- VDI: ignore lineA variable 'multifill' for linea_rect() and linea_polygon()
|
||||
- VDI: speed up drawing of horizontal lines by v_pline()
|
||||
- VDI: fix lineA rectangle fill bugs
|
||||
- VDI: fix gap in circle drawn by v_arc()
|
||||
- VDI: fix VDI wideline display in 320x480 resolution
|
||||
- Lots of source code cleanup and minor bug fixes
|
295
ROMImages/AtariST/doc/emudesk.txt
Normal file
295
ROMImages/AtariST/doc/emudesk.txt
Normal file
@ -0,0 +1,295 @@
|
||||
A brief user's guide to the newer features of EmuDesk, the EmuTOS desktop
|
||||
=========================================================================
|
||||
|
||||
The current version of EmuDesk is based on the TOS 1 desktop, but with
|
||||
many improvements inspired by the TOS 2/3/4 desktop, including:
|
||||
|
||||
1) new menu items
|
||||
. set file mask
|
||||
. install icon
|
||||
. install application
|
||||
. install devices
|
||||
. remove desktop icon
|
||||
. desktop configuration
|
||||
. blitter
|
||||
Due to space limitations, the implementation of the above is somewhat
|
||||
restricted in the 192K ROMs (see the detailed descriptions below). If
|
||||
you make any changes to the desktop using the above features, you must
|
||||
save the desktop to preserve the changes.
|
||||
|
||||
2) other new features
|
||||
. user-assignable icons
|
||||
. user-assignable mouse cursors
|
||||
. open disk window via keyboard shortcut
|
||||
. desktop shortcuts
|
||||
Due to space limitations, desktop shortcuts are not available in the
|
||||
192K ROMs. Desktop shortcuts are preserved when you save the desktop.
|
||||
|
||||
|
||||
Set file mask
|
||||
=============
|
||||
192K ROMs:
|
||||
This is not available.
|
||||
|
||||
Other ROMs:
|
||||
This is used to change the file mask of the currently-topped window, to
|
||||
control which files are displayed within the window. Note that folders
|
||||
are always displayed; the mask affects the display of files only. The
|
||||
default file mask when a window is opened is "*.*"
|
||||
|
||||
|
||||
Install icon
|
||||
============
|
||||
192K ROMs:
|
||||
This may be used to associate a specific icon with a desktop item (disk
|
||||
or trash). You may select an existing desktop item and click on "Install
|
||||
icon...", or you may click on "Install icon..." with no item selected.
|
||||
If you click on a window icon (file or folder), it will be ignored.
|
||||
|
||||
Other ROMs:
|
||||
This may be used to associate a specific icon with a desktop item (disk
|
||||
or trash), or a window item (file or folder). You may select an existing
|
||||
icon and click on "Install icon...", or you may click on "Install icon..."
|
||||
with no item selected. In the latter case, you'll get a dialog requesting
|
||||
you to select the type of icon (desktop or window).
|
||||
|
||||
. Installing a desktop icon
|
||||
You may select the type (drive or trash), the label (displayed beneath
|
||||
it on the desktop), and the icon shape (use the up & down arrows to
|
||||
scroll through the available shapes). In addition, for drives you can
|
||||
select the drive letter.
|
||||
|
||||
. Installing a window icon
|
||||
If you pre-selected an icon, you may only change the shape of the icon
|
||||
for that specific file or folder. If you did not pre-select an item,
|
||||
you can select the files that the icon will apply to (standard TOS
|
||||
wildcards may be used), the type of item (file or folder), and the icon
|
||||
shape. In either case, to change the icon shape, use the up & down
|
||||
arrows to scroll through the available shapes.
|
||||
|
||||
|
||||
Install application
|
||||
===================
|
||||
The basic purpose of "Install application..." is to link an application
|
||||
to data files with a specified extension. After you have done this, when
|
||||
you use the desktop to open a file with the specified extension, the
|
||||
corresponding application is launched. For example, you could associate
|
||||
all .TXT files with a text editor; then, double-clicking on a .TXT file
|
||||
would automatically launch the editor.
|
||||
|
||||
In addition, you can assign a function key to an application; pressing
|
||||
the function key at the desktop will then launch the application.
|
||||
|
||||
Finally, you can set "autoboot" for one application (only): this will
|
||||
launch that application during system initialisation, immediately before
|
||||
the desktop itself runs.
|
||||
|
||||
To use "Install application...", highlight one or more applications and
|
||||
click on "Install application...". In the dialog box, the application
|
||||
name of the first application selected will be prefilled. The following
|
||||
fields and buttons specify in detail how the application is run:
|
||||
|
||||
. Arguments
|
||||
If you need to pass information (in addition to the name of the data
|
||||
file) to the application when it starts, you may specify it here. This
|
||||
is typically only relevant to utility programs, and the information
|
||||
needed will be in the application documentation. In most cases, you
|
||||
should leave this blank.
|
||||
|
||||
. Document type
|
||||
This specifies the extension to associate with this application, for
|
||||
example TXT or RSC, and is required. Wildcards are allowed.
|
||||
|
||||
. Install as F__
|
||||
This specifies the function key that will launch the application;
|
||||
values from 1 to 20 are allowed (11-20 are shift-F1 through shift-F10).
|
||||
Leaving this blank is valid, and means that no function key will launch
|
||||
the application.
|
||||
|
||||
. Boot status
|
||||
Select "Auto" to autoboot this application (see above). Since only one
|
||||
autoboot application is allowed, if you set "Auto" for an application,
|
||||
EmuTOS will automatically disable "Auto" for any existing autoboot
|
||||
application.
|
||||
|
||||
. Application type
|
||||
Selecting TOS or TTP will launch the program in character mode; GEM or
|
||||
GTP will launch the application in graphics mode. The appropriate
|
||||
value will be prefilled according to the type of application selected,
|
||||
and should not normally be changed.
|
||||
|
||||
. Default dir
|
||||
This specifies the default directory when the application is launched:
|
||||
either the directory of the application itself, or the top window (i.e.
|
||||
the directory of the data file). The one to choose depends on the
|
||||
specific application. If the application has supporting files (such as
|
||||
resource or help files), it typically will look for them in the default
|
||||
directory. For such an application, you will need to specify a default
|
||||
directory of "Application". Otherwise, specify "Window".
|
||||
|
||||
. Parameter
|
||||
When a program is launched due to it being an installed application,
|
||||
the desktop provides the application with the name of the data file
|
||||
that caused the launch: this is known as a parameter. In most cases,
|
||||
the application expects that the full path of the data file will be
|
||||
provided. Some (usually older) programs may expect the filename only.
|
||||
Unless the application's documentation indicates otherwise, you should
|
||||
normally try "Full path" first; if that does not work, you can try
|
||||
"File name", although that may require you to modify the "Default dir"
|
||||
specified above.
|
||||
|
||||
At the bottom of the dialog box are the following exit buttons:
|
||||
|
||||
. Install
|
||||
Installs the application. You must save the desktop afterwards if you
|
||||
want the change to be saved across boots.
|
||||
|
||||
. Remove
|
||||
Removes an existing installed application. You must save the desktop
|
||||
afterwards if you want the change to be saved across boots.
|
||||
|
||||
. Skip
|
||||
Skips installing/removing the current application, and moves on to the
|
||||
next one you specified. If you only specified one application, this
|
||||
is the same as Cancel.
|
||||
|
||||
. Cancel
|
||||
Skip installing/removing all remaining applications.
|
||||
|
||||
|
||||
Install devices
|
||||
===============
|
||||
This automatically installs icons for all devices that are currently
|
||||
known to GEMDOS (have an entry in _drvbits) and that do not currently
|
||||
have an icon. If the device is A: or B:, a floppy icon is installed;
|
||||
otherwise a hard disk icon is installed.
|
||||
|
||||
|
||||
Remove desktop icon
|
||||
===================
|
||||
This is used to remove a disk or trash icon. Highlight the icon you
|
||||
wish to remove, and click on "Remove desktop icon".
|
||||
|
||||
|
||||
Desktop configuration
|
||||
=====================
|
||||
192K ROMs:
|
||||
This is not available.
|
||||
|
||||
Other ROMs:
|
||||
This is a simplified version of the corresponding Atari TOS menu item.
|
||||
It allows you to specify the default directory and input parameter for
|
||||
all applications that are not installed applications. See "Install
|
||||
application" above, under 'Default dir' and 'Parameter', for further
|
||||
information about these options.
|
||||
|
||||
|
||||
Blitter
|
||||
=======
|
||||
This item allows you to enable or disable the use of the blitter by the
|
||||
desktop. The item is greyed-out if the system does not have a blitter.
|
||||
|
||||
|
||||
User-assignable icons
|
||||
=====================
|
||||
When EmuDesk starts, it looks for a file called EMUICON.RSC in the root
|
||||
of the boot drive. This file should be a standard Atari resource file,
|
||||
with at least eight icons. All icons in the file must be 32x32-pixel
|
||||
monochrome icons. If the file is found, these icons are used for the
|
||||
desktop and window displays; if not found, a standard set of eight
|
||||
builtin icons is used instead. The builtin icons (or the first eight
|
||||
of the loaded icons, if EMUICON.RSC is in use) have the following usage:
|
||||
0 hard drive
|
||||
1 floppy drive
|
||||
2 folder
|
||||
3 trash
|
||||
4 printer
|
||||
5 removable disk
|
||||
6 generic application icon
|
||||
7 generic document icon
|
||||
Icons 8 and above can be used as you wish.
|
||||
|
||||
Note that, for historical reasons, these assignments are different from
|
||||
those used by Atari TOS, so if you have an equivalent RSC file that works
|
||||
with Atari TOS, you will need to move the icons around to get the same
|
||||
desktop display.
|
||||
|
||||
A default EMUICON.RSC file (currently containing 41 icons) is shipped
|
||||
with the release; the first 8 icons are the same as the builtin ones.
|
||||
Also shipped is the corresponding EMUICON.DEF file for use by a resource
|
||||
editor. You should be aware that each icon consumes about 300 bytes of
|
||||
RAM, so if you are short of memory, avoid putting too many icons in
|
||||
EMUICON.RSC.
|
||||
|
||||
|
||||
User-assignable mouse cursors
|
||||
=============================
|
||||
When the AES starts, it looks for a file called EMUCURS.RSC in the root
|
||||
of the boot drive. This file should be a standard Atari resource file,
|
||||
containing 8 ICONBLKs; each ICONBLK is a container for a mouse cursor.
|
||||
If the file is found, these cursors are used instead of the builtin
|
||||
cursors. The usage is as described for the AES graf_mouse() call:
|
||||
0 arrow
|
||||
1 text cursor / i-beam
|
||||
2 busy bee / hourglass
|
||||
3 pointing hand
|
||||
4 flat hand
|
||||
5 thin cross
|
||||
6 thick cross
|
||||
7 outline cross
|
||||
|
||||
A default EMUCURS.RSC file is shipped with the release; the mouse cursors
|
||||
in it are the same as the builtin ones. Also shipped is the corresponding
|
||||
EMUCURS.DEF file for use by a resource editor.
|
||||
|
||||
NOTE: Because the mouse cursors are not really ICONBLKs (though they are
|
||||
stored as such within the resource), editing them with a standard resource
|
||||
editor is difficult. Thorsten Otto's ORCS resource editor has special
|
||||
support for mouse cursors and is the recommended tool for modifying them.
|
||||
|
||||
|
||||
Open disk window via keyboard shortcut
|
||||
======================================
|
||||
You may now use a keyboard shortcut to display the root directory of a
|
||||
drive in a new window. To display drive X, hold the Alt key down and
|
||||
type X, e.g. Alt-C displays drive C, Alt-D displays drive D, and so on.
|
||||
As in TOS2/3/4, these shortcuts are permanently assigned and cannot be
|
||||
changed by the user.
|
||||
|
||||
NOTE: unlike TOS2/3/4, shortcuts with the Ctrl modifier do NOT update
|
||||
the drive assigned to the currently topped window; instead, they are
|
||||
assigned to menu item shortcuts. At the moment, these assignments are
|
||||
also permanent.
|
||||
|
||||
|
||||
Desktop shortcuts
|
||||
=================
|
||||
You may now drag a file or folder to the desktop to create a desktop icon
|
||||
that is a shortcut to the original file/folder: manipulating the icon
|
||||
will have the same effect as manipulating the original file or folder.
|
||||
For example, it may be opened, copied, or moved or deleted; it may have
|
||||
an "Info/rename" performed on it. Currently, by design, the shortcut is
|
||||
NOT updated automatically if the original file or folder is moved or
|
||||
deleted.
|
||||
|
||||
The name and shape of the shortcut icon itself may be modified by the
|
||||
"Install icon" menu item; this does not change the name of the file or
|
||||
folder that the icon points to. The shortcut icon may be deleted by the
|
||||
"Remove icon" menu item. To preserve shortcut information across boots,
|
||||
you must save the desktop.
|
||||
|
||||
You may drag a file or folder to a desktop shortcut, with the following
|
||||
results:
|
||||
. dragging documents to a desktop shortcut for a folder will copy (or
|
||||
move, if the control key is held down) them to the folder
|
||||
. dragging documents to a desktop shortcut for a program will launch the
|
||||
program, passing the full pathname of the first document
|
||||
. dragging documents to a desktop shortcut for a non-executable file will
|
||||
do nothing
|
||||
|
||||
If you open a desktop shortcut that points to a file or folder that no
|
||||
longer exists, an alert will be issued, giving you the choice of removing
|
||||
the shortcut, locating the desired file or folder, or cancelling the
|
||||
action. If you choose locate, a file selector will be displayed to
|
||||
allow you to choose the desired file or folder, and the shortcut will be
|
||||
updated with the new information.
|
227
ROMImages/AtariST/doc/incompatible.txt
Normal file
227
ROMImages/AtariST/doc/incompatible.txt
Normal file
@ -0,0 +1,227 @@
|
||||
Programs incompatible with EmuTOS
|
||||
=================================
|
||||
This is a list of programs that have program bugs or shortcomings that
|
||||
prevent them from running properly with EmuTOS, and whose problem has
|
||||
been definitively identified. It is mainly intended to prevent these
|
||||
programs from being added to 'bugs.txt' in the future.
|
||||
|
||||
|
||||
Program: STOS programs
|
||||
----------------------
|
||||
Error 1: joystick and/or keyboard input doesn't work.
|
||||
|
||||
Bug analysis:
|
||||
STOS Basic compiler routines check for input using undocumented and
|
||||
TOS-specific locations. Programs using these routines work only with
|
||||
specific TOS versions, and not with EmuTOS.
|
||||
|
||||
Workaround:
|
||||
Use version of the program that has been fixed to work with modern TOS
|
||||
versions.
|
||||
|
||||
Error 2: STOS error message "Error #046, press any key" during startup.
|
||||
|
||||
Bug analysis:
|
||||
This is caused by a divide-by-zero error in vsm_height() when the
|
||||
program is run from the AUTO folder. VDI initialisation does not occur
|
||||
until after AUTO-folder programs have been run, so if a VDI function is
|
||||
called by an AUTO-folder program, internal variables have not been
|
||||
initialised. STOS tries to initialise these variables itself, based on
|
||||
a built-in table of TOS-specific locations. These locations are invalid
|
||||
for EmuTOS, so the required variables remain zero, causing the error.
|
||||
|
||||
Workaround:
|
||||
Move the program from the AUTO folder to the root of the drive, and run
|
||||
it from there. While STOS programs will then start, most of them will
|
||||
remain unusable due to error 1 above.
|
||||
|
||||
|
||||
Program: old game using fixed addresses
|
||||
---------------------------------------
|
||||
Error: panic during game startup.
|
||||
|
||||
Bug analysis:
|
||||
Several old, floppy-only games load their data into fixed memory
|
||||
addresses, which won't work when EmuTOS has loaded something else
|
||||
there. This can be detected by tracing programs' OS calls with Hatari
|
||||
(--trace os_all) and checking the used addresses. For example, under
|
||||
older EmuTOS versions, the Gods game demo (from an ST Format cover disk)
|
||||
overwrote itself with its game data because of this, and crashed.
|
||||
|
||||
Workarounds:
|
||||
In some games this can be worked around by either using the cartridge
|
||||
version of EmuTOS (which uses less memory) or by using a custom high-RAM
|
||||
build of EmuTOS, that uses higher RAM addresses for loading programs and
|
||||
for memory allocation:
|
||||
make 512 UNIQUE=uk DEF="-DSTATIC_ALT_RAM_ADDRESS=0x00080000 -DCONF_WITH_FRB=0"
|
||||
|
||||
However, this doesn't help with programs which also expect undocumented,
|
||||
OS internal functions and variables to be at certain locations. The
|
||||
best workaround is to use a version of the game that has been fixed to
|
||||
run from HD and with modern TOS versions.
|
||||
|
||||
|
||||
Program: Awele v1.01
|
||||
--------------------
|
||||
Error: mono desktop colours are inverted after exiting program.
|
||||
|
||||
Bug analysis:
|
||||
This version of Awele was compiled with PureC and linked with a very
|
||||
early version of Windform. During WinDOM initialisation, malloc() is
|
||||
called to allocate an area to save the palette in. However, although
|
||||
malloc() returns the pointer in A0, the WinDOM code assumes it is in D0.
|
||||
As a result, an area of low memory is pointed to, which is overwritten
|
||||
during Awele execution. At program termination, the palette is restored
|
||||
from the overwritten area, resulting in the error seen.
|
||||
|
||||
Workaround:
|
||||
Use v1.02 of the game.
|
||||
|
||||
|
||||
Program: Cameleon
|
||||
-----------------
|
||||
Error 1: program exits immediately when 'Start game' is selected.
|
||||
|
||||
Bug analysis:
|
||||
The program requires an STe. In order to determine whether it is
|
||||
running on an STe, it checks the contents of location 0x995 (hardcoded).
|
||||
On Atari TOS, this is where TOS initialisation happens to store the _MCH
|
||||
cookie but this is *not* how Atari says you should locate it (and it's
|
||||
not where EmuTOS stores it).
|
||||
|
||||
Error 2: program crashes with a Trace exception on any exit.
|
||||
|
||||
Bug analysis:
|
||||
During startup, the program switches to supervisor state via the Super()
|
||||
system call. Subsequently, the supervisor stack overwrites the program's
|
||||
user stack. On exit, the user stack pointer is restored and during this
|
||||
a corrupted value is loaded into the SR, causing a trace excpetion.
|
||||
|
||||
|
||||
Program: (VDI) Invaders and Anduril
|
||||
-----------------------------------
|
||||
Error: keys to move an object are ignored (in Invaders, the '-' key; in
|
||||
Anduril, the 'h' & 'j' keys)
|
||||
|
||||
Bug analysis:
|
||||
Both programs were written by "M.Dheus" who found that the most recent
|
||||
key input from the keyboard was stored at offset 0x6d from the address
|
||||
returned by Kbdvbase(), and used that to read the keyboard. This was
|
||||
never documented by Atari, but was apparently true for all versions of
|
||||
TOS 1. However it is not true for TOS 2, 3, or 4 (or EmuTOS).
|
||||
|
||||
|
||||
Program: Ramses
|
||||
---------------
|
||||
Error: panic
|
||||
|
||||
Bug analysis:
|
||||
Program calls the Line A initialization $A00A and gets the routine
|
||||
vectors in a2. It gets the address of _v_hide_c, then starts doing
|
||||
undocumented things with the bytes of the actual routine:
|
||||
https://sourceforge.net/p/emutos/mailman/message/30605378/
|
||||
|
||||
|
||||
Program: STVidPlay
|
||||
------------------
|
||||
Error: "Error in getting file location"
|
||||
|
||||
Bug analysis:
|
||||
Program looks for a specific 2-byte sequence in the hard disk driver
|
||||
code pointed to by hdv_rw ($476). If it doesn't find that sequence
|
||||
within bytes 6-48 (or thereabouts) of the start of the driver, it
|
||||
gives the error message.
|
||||
|
||||
|
||||
Program: Cubase Lite
|
||||
--------------------
|
||||
Error: panic
|
||||
|
||||
Bug analysis:
|
||||
On TOS 1.62 etv_timer vector is a delegate to an internal private
|
||||
function. Cubase Lite tries to guess the address of that private
|
||||
function in an undocumented way, which crashes on EmuTOS. (Somebody
|
||||
could write a loader or TSR to change the etv_timer function so that
|
||||
Cubase will not crash.)
|
||||
|
||||
|
||||
Program: Reservoir Gods games (Bugger, Bunion, SkyFall, Sworm)
|
||||
--------------------------------------------------------------
|
||||
Error: panic
|
||||
|
||||
Bug analysis:
|
||||
Games use an undocumented TOS4 vector for keyboard input instead of
|
||||
accessing kbdvec correctly. This causes EmuTOS to panic.
|
||||
|
||||
Workaround:
|
||||
This can be worked around with the following hack.prg:
|
||||
https://sourceforge.net/p/emutos/mailman/message/26841274/
|
||||
|
||||
|
||||
Program: OMIKRON.BASIC V3.01 (interpreter)
|
||||
------------------------------------------
|
||||
Error: Panic (bus error) during start
|
||||
|
||||
Bug analysis:
|
||||
The program relies on undocumented internal TOS variables at several
|
||||
points. First, it expects A0 upon return from Mediach (BIOS function)
|
||||
to point to wplatch (floppy write protect latch variable). On EmuTOS
|
||||
A0 is 0 and hence a bus error occurs when the program wants to modify
|
||||
that variable. Second, it parses the bytes of the 0xA00A (hide cursor)
|
||||
line-A routine to get the address of a variable reflecting the internal
|
||||
state of the mouse cursor. This is done with the same code used in
|
||||
"Ramses" (see above). This also fails on EmuTOS, resulting in another
|
||||
bus error. There may be more accesses to undocumented variables.
|
||||
|
||||
|
||||
Program: STSpeech v2.0
|
||||
----------------------
|
||||
Error: panics due to stack corruption
|
||||
|
||||
Bug analysis:
|
||||
The program installs a custom Timer A interrupt handler, and calls the
|
||||
XBIOS from it. If the Timer A interrupt happens to occur just when an
|
||||
unrelated BIOS/XBIOS call is manipulating _savptr (saving registers),
|
||||
then the nested XBIOS call inside the Timer A handler will trash that
|
||||
BIOS/XBIOS save area, possibly modifying the stack pointer. In the
|
||||
"Hitchhiker's Guide to the BIOS", Atari documented a workaround for this,
|
||||
but STSpeech does not use it.
|
||||
|
||||
Workaround:
|
||||
Because this problem is timing-dependent, it does not show up on Atari
|
||||
TOS, and only shows up in EmuTOS if BigDOS is installed (BigDOS issues
|
||||
many XBIOS calls). Use program without BigDOS, or anything else doing
|
||||
a lot of XBIOS calls.
|
||||
|
||||
|
||||
Program: Protracker v2 STE (Equinox version)
|
||||
--------------------------------------------
|
||||
Error: crash when "DISK OP." button is selected
|
||||
|
||||
Bug analysis:
|
||||
The program relies on a TOS-specific code sequence, as follows:
|
||||
1. it searches the ROM (pointed to by location 4) for the first word
|
||||
equal to 0x47e
|
||||
2. when found, it uses the longword immediately before as a pointer to
|
||||
an address; in TOS2, this is a pointer to the mediachange handler
|
||||
3. it stores the long at offset 0x1c from that address in its data
|
||||
segment; in TOS2, this is a pointer to (I think) two bytes of
|
||||
status for the floppy drives
|
||||
Subsequently, when "DISK OP." is selected, the stored long is used as a
|
||||
pointer. In TOS2, the value stored is $4216; in EmuTOS, it's zero,
|
||||
resulting in a crash.
|
||||
|
||||
|
||||
Program: Spectrum 512
|
||||
---------------------
|
||||
Error: crash during program initialisation
|
||||
|
||||
Bug analysis:
|
||||
The program relies on a TOS-specific code sequence, as follows:
|
||||
1. it searches the VBL handler (pointed to by location $70) for the
|
||||
first word containing a value of 0x6100
|
||||
2. when found, it uses the word immediately following as an index to
|
||||
generate an address, and starts searching at that address for a
|
||||
word containing a value of 0x8606
|
||||
Under EmuTOS, the address generated is a nonsense address which happens
|
||||
to be odd, causing an immediate address error.
|
339
ROMImages/AtariST/doc/license.txt
Normal file
339
ROMImages/AtariST/doc/license.txt
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 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 Lesser General
|
||||
Public License instead of this License.
|
583
ROMImages/AtariST/doc/status.txt
Normal file
583
ROMImages/AtariST/doc/status.txt
Normal file
@ -0,0 +1,583 @@
|
||||
This file documents the status of the individual parts of EmuTOS.
|
||||
|
||||
Here is a quick list of supported emulators/hardware:
|
||||
This table should be updated regularly. When indicating failure,
|
||||
if possible add a line telling in which version it did run.
|
||||
Unless otherwise specified in 'details', systems were tested using
|
||||
a ROM version of EmuTOS.
|
||||
|
||||
system | ok? | who | date | details
|
||||
--------------------+-------+-----+-------------+----------------
|
||||
Emulators | | | |
|
||||
ARAnyM 1.0.2 | yes | VRI | 17 Dec 2018 |
|
||||
Hatari v2.1.0 | yes | VRI | 16 Dec 2018 |
|
||||
Pacifist v0.48 | yes | LVL | winter 2001 |
|
||||
SainT v2.40 | yes | (1) | 10 Dec 2017 | 192k ROM only
|
||||
STeem SSE 3.9.4 | yes | VRI | 16 Dec 2018 |
|
||||
STonC v0.8.1 | yes | LVL | 9 Feb 2003 |
|
||||
STonX 0.6.7.6 | yes | THH | 14 Nov 2008 |
|
||||
TOSBox 1.10a | no | ? | < Sep 2002 |
|
||||
WinSTon V0.1r2 | no | ? | < Sep 2002 |
|
||||
WinUAE 4.1.0 | yes | VRI | 19 Dec 2018 |
|
||||
--------------------+-------+-----+-------------+----------------
|
||||
Atari & compatibles | | | |
|
||||
STfm | yes | (1) | 23 Nov 2017 |
|
||||
Mega ST | yes | (8) | 7 Dec 2018 | tested with PRG
|
||||
STe | yes | (1) | 23 Nov 2017 |
|
||||
Mega STe | yes | (2) | 26 Jun 2004 | only RAMTOS tested
|
||||
TT030 | yes | RFB | 30 Nov 2018 | tested with PRG
|
||||
Falcon030 | yes | (7) | 31 Dec 2016 |
|
||||
Falcon030 | yes | RFB | 29 Nov 2018 | tested with PRG
|
||||
Falcon030 + CT60 | yes | RFB | 29 Nov 2018 | tested with PRG
|
||||
Suska III-C (2K15B) | yes | (5) | 23 Apr 2016 |
|
||||
--------------------+-------+-----+-------------+----------------
|
||||
Other systems | | | |
|
||||
Amiga Blizzard 1260 | yes | (3) | Aug 2012 | tested with BlizKick
|
||||
Amiga 500 + Vampire | yes | VRI | 21 Dec 2018 |
|
||||
Amiga 600 + Vampire | yes | (6) | Mar 2017 |
|
||||
Amiga 1000 | yes | (4) | Jul 2012 |
|
||||
FireBee | yes | VRI | 18 Dec 2018 |
|
||||
M5484LITE | yes | VRI | 18 Dec 2018 |
|
||||
|
||||
(1) reported by Christian Zietz
|
||||
(2) reported to LVL by Frédéric Pécourt
|
||||
(3) reported by Michaël Gibs
|
||||
(4) reported by amiman99
|
||||
(5) reported by Markus Fröschle
|
||||
(6) reported by Flype
|
||||
(7) reported by Stefan Niestegge
|
||||
(8) reported by Claude Labelle
|
||||
|
||||
Now let's talk about the different subsystems, and what is implemented.
|
||||
NOTE: the information in the following table may be somewhat dated. For
|
||||
example, most GEMDOS/BIOS/XBIOS functions are known to work without
|
||||
problems.
|
||||
|
||||
|
||||
This is what the first field of the following table means:
|
||||
|
||||
? status unknown
|
||||
- Not yet implemented
|
||||
> Partially implemented
|
||||
X Fully implemented and untested
|
||||
t Fully implemented and partially tested
|
||||
T tested and working on an emulator or real hardware
|
||||
|
||||
|
||||
Hardware initialization
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
T CPU setting, tested on: 68000 (real & emu), 68030 (real & emu), 68040 (emu),
|
||||
68060 (real), 68080 (real), V4e (real)
|
||||
T FPU
|
||||
T 68030 MMU and cache initialization
|
||||
T Memory controller (both ST and Falcon)
|
||||
T DMA controller
|
||||
T WD 1772 / AJAX Floppy disk controller
|
||||
T MFP, MFP#2
|
||||
T PSG
|
||||
T ST shifter
|
||||
T STe shifter
|
||||
T TT shifter
|
||||
T VIDEL
|
||||
T ACIAs, IKBD protocol
|
||||
t MegaST Real-Time Clock (set clock not tested)
|
||||
T NVRAM (including RTC)
|
||||
T Blitter
|
||||
T Microwire
|
||||
t DMA sound
|
||||
- DSP
|
||||
T SCC
|
||||
T IDE
|
||||
T ACSI
|
||||
T SCSI
|
||||
T SD/MMC
|
||||
T NatFeats (a framework for native features on emulators)
|
||||
|
||||
|
||||
BOOT sequence
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
T configure memory
|
||||
T execute reset routine
|
||||
T detect monitor type
|
||||
T detect graphics resolution
|
||||
T detect processor type, FPU type and hardware features
|
||||
T setup a cookie jar with system cookies
|
||||
...
|
||||
T init floppy drives
|
||||
T boot floppy
|
||||
t boot DMA (note it does not work with e.g. AHDI)
|
||||
T execute reset-resident prgs: undocumented TOS feature, disabled by default
|
||||
T run AUTO prgs
|
||||
T run 'command.prg'
|
||||
T run the default shell, EmuCON
|
||||
T run the GEM desktop
|
||||
|
||||
|
||||
BIOS devices
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
t 0 PRN: parallel port
|
||||
t 1 AUX: default serial port
|
||||
T 2 CON: console (screen)
|
||||
T 3 MIDI
|
||||
T 4 IKBD
|
||||
T 5 raw screen
|
||||
T 6 ST-compatible serial port
|
||||
T 7 SCC channel B
|
||||
T 8 TT-MFP serial port
|
||||
T 9 SCC channel A
|
||||
|
||||
|
||||
ACIA interrupt handlers
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
- midierr
|
||||
- ikbderr
|
||||
t midi input
|
||||
T ikbd key events
|
||||
T IKBD clock
|
||||
T mouse
|
||||
t joysticks
|
||||
|
||||
|
||||
BIOS Functions
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
T 0x00 Getmpb
|
||||
T 0x01 Bconstat
|
||||
T 0x02 Bconin
|
||||
T 0x03 Bconout
|
||||
T 0x04 Rwabs
|
||||
T 0x05 Setexc
|
||||
T 0x06 Tickcal
|
||||
T 0x07 Getbpb
|
||||
T 0x08 Bcostat
|
||||
T 0x09 Mediach
|
||||
T 0x0a Drvmap
|
||||
T 0x0b Kbshift
|
||||
|
||||
|
||||
XBIOS Functions
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
All XBIOS versions:
|
||||
X 0x00 Initmous
|
||||
- 0x01 Ssbrk (useless - will not be implemented)
|
||||
T 0x02 Physbase
|
||||
T 0x03 Logbase
|
||||
T 0x04 Getrez
|
||||
T 0x05 Setscreen
|
||||
T 0x06 Setpalette
|
||||
T 0x07 Setcolor
|
||||
T 0x08 Floprd
|
||||
T 0x09 Flopwr
|
||||
T 0x0a Flopfmt
|
||||
- 0x0b Dbmsg (useless - will not be implemented)
|
||||
T 0x0c Midiws
|
||||
X 0x0d Mfpint
|
||||
X 0x0e Iorec
|
||||
T 0x0f Rsconf
|
||||
T 0x10 Keytbl
|
||||
T 0x11 Random
|
||||
T 0x12 Protobt
|
||||
T 0x13 Flopver
|
||||
- 0x14 Scrdmp
|
||||
T 0x15 Cursconf
|
||||
T 0x16 Settime
|
||||
T 0x17 Gettime
|
||||
T 0x18 Bioskeys
|
||||
T 0x19 Ikbdws
|
||||
T 0x1a Jdisint
|
||||
T 0x1b Jenabint
|
||||
T 0x1c Giaccess
|
||||
T 0x1d Offgibit
|
||||
T 0x1e Ongibit
|
||||
T 0x1f Xbtimer
|
||||
T 0x20 Dosound
|
||||
- 0x21 Setprt (useless - will not be implemented)
|
||||
X 0x22 Kbdvbase
|
||||
T 0x23 Kbrate
|
||||
- 0x24 Prtblk (useless - will not be implemented)
|
||||
T 0x25 Vsync
|
||||
T 0x26 Supexec
|
||||
- 0x27 Puntaes (useless - will not be implemented)
|
||||
|
||||
TOS v1.02:
|
||||
T 0x29 Floprate
|
||||
T 0x40 Blitmode
|
||||
|
||||
TOS v2.0:
|
||||
t 0x2a DMAread
|
||||
t 0x2b DMAwrite
|
||||
t 0x2c Bconmap
|
||||
|
||||
TOS v3.00:
|
||||
T 0x2e NVMaccess
|
||||
|
||||
t 0x50 EsetShift (for TT shifter only)
|
||||
t 0x51 EgetShift (for TT shifter only)
|
||||
t 0x52 EsetBank (for TT shifter only)
|
||||
t 0x53 EsetColor (for TT shifter only)
|
||||
t 0x54 EsetPalette (for TT shifter only)
|
||||
t 0x55 EgetPalette (for TT shifter only)
|
||||
t 0x56 EsetGray (for TT shifter only)
|
||||
t 0x57 EsetSmear (for TT shifter only)
|
||||
|
||||
TOS v4.00:
|
||||
t 0x58 Vsetmode (for Falcon Videl only)
|
||||
t 0x59 Vmontype (for Falcon Videl only)
|
||||
t 0x5a VsetSync (for Falcon Videl only)
|
||||
t 0x5b VgetSize (for Falcon Videl only)
|
||||
|
||||
t 0x5d VsetRGB (for Falcon Videl only)
|
||||
t 0x5e VgetRGB (for Falcon Videl only)
|
||||
|
||||
- 0x96 VsetMask (for Falcon Videl only)
|
||||
|
||||
2nd bit in _SND is set:
|
||||
t 0x80 LockSnd
|
||||
t 0x81 UnlockSnd
|
||||
t 0x82 Soundcmd
|
||||
t 0x83 Setbuffer
|
||||
t 0x84 Setmode
|
||||
t 0x85 Settracks
|
||||
t 0x86 Setmontracks
|
||||
t 0x87 Setinterrupt
|
||||
t 0x8c Sndstatus
|
||||
|
||||
3rd bit in _SND is set:
|
||||
t 0x88 Buffoper
|
||||
t 0x8a Gpio
|
||||
t 0x8b Devconnect
|
||||
t 0x8d Buffptr
|
||||
|
||||
3&4 bits in _SND are set:
|
||||
t 0x89 Dsptristate
|
||||
|
||||
5th bit in _SND is set:
|
||||
- 0x60-0x7F, 32 Dsp_* functions
|
||||
|
||||
TOS v4 extended XBIOS functionality:
|
||||
- 16-bit Videl resolution setting
|
||||
|
||||
|
||||
GEMDOS Functions
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
All GEMDOS versions:
|
||||
T 0x00 Pterm0
|
||||
T 0x01 Cconin
|
||||
T 0x02 Cconout
|
||||
T 0x03 Cauxin
|
||||
T 0x04 Cauxout
|
||||
T 0x05 Cprnout
|
||||
T 0x06 Crawio
|
||||
T 0x07 Crawin
|
||||
T 0x08 Cnecin
|
||||
T 0x09 Cconws
|
||||
T 0x0a Cconrs
|
||||
T 0x0b Cconis
|
||||
|
||||
T 0x0e Dsetdrv
|
||||
|
||||
T 0x10 Cconos
|
||||
T 0x11 Cprnos
|
||||
T 0x12 Cauxis
|
||||
T 0x13 Cauxos
|
||||
|
||||
T 0x19 Dgetdrv
|
||||
T 0x1a Fsetdta
|
||||
|
||||
T 0x20 Super
|
||||
|
||||
T 0x2a Tgetdate
|
||||
T 0x2b Tsetdate
|
||||
T 0x2c Tgettime
|
||||
T 0x2d Tsettime
|
||||
|
||||
T 0x2f Fgetdta
|
||||
T 0x30 Sversion
|
||||
T 0x31 Ptermres
|
||||
|
||||
T 0x36 Dfree
|
||||
|
||||
T 0x39 Dcreate
|
||||
T 0x3a Ddelete
|
||||
T 0x3b Dsetpath
|
||||
T 0x3c Fcreate
|
||||
T 0x3d Fopen
|
||||
T 0x3e Fclose
|
||||
T 0x3f Fread
|
||||
T 0x40 Fwrite
|
||||
T 0x41 Fdelete
|
||||
T 0x42 Fseek
|
||||
T 0x43 Fattrib
|
||||
|
||||
T 0x45 Fdup
|
||||
T 0x46 Fforce
|
||||
T 0x47 Dgetpath
|
||||
T 0x48 Malloc
|
||||
T 0x49 Mfree
|
||||
T 0x4a Mshrink
|
||||
T 0x4b Pexec
|
||||
T 0x4c Pterm
|
||||
|
||||
T 0x4e Fsfirst
|
||||
T 0x4f Fsnext
|
||||
|
||||
T 0x56 Frename
|
||||
T 0x57 Fdatime
|
||||
|
||||
GEMDOS v0.19 (TOS v2):
|
||||
T 0x14 Maddalt
|
||||
T 0x44 Mxalloc
|
||||
(and Pexec mode 6)
|
||||
|
||||
|
||||
Line-A functions
|
||||
----------------------------------------------------------------------------
|
||||
T $0 - Initialization
|
||||
t $1 - Put pixel
|
||||
t $2 - Get pixel
|
||||
t $3 - Arbitrary line
|
||||
t $4 - Horizontal line
|
||||
t $5 - Filled rectangle
|
||||
t $6 - Filled polygon (see bugs.txt)
|
||||
t $7 - Bit block transfer (may miss options not needed by VDI)
|
||||
t $8 - Text block transfer
|
||||
T $9 - Show mouse
|
||||
T $A - Hide mouse
|
||||
t $B - Transform mouse
|
||||
t $C - Undraw sprite
|
||||
t $D - Draw sprite
|
||||
t $E - Copy raster form
|
||||
t $F - Seedfill
|
||||
|
||||
|
||||
VDI functions
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
All TOS 1.0 calls are implemented.
|
||||
|
||||
T v_opnwk
|
||||
X v_clswk
|
||||
T v_opnvwk
|
||||
T v_clsvwk
|
||||
T v_clrwk
|
||||
- v_updwk
|
||||
> vst_load_fonts (needs GDOS or equivalent)
|
||||
> vst_unload_fonts (needs GDOS or equivalent)
|
||||
t vs_clip
|
||||
T v_pline
|
||||
T v_pmarker
|
||||
T v_gtext
|
||||
T v_fillarea
|
||||
- v_cellarray (not supported by any current VDI driver)
|
||||
T v_contourfill
|
||||
T vr_recfl
|
||||
T v_bar
|
||||
T v_arc
|
||||
T v_pieslice
|
||||
T v_circle
|
||||
T v_ellipse
|
||||
T v_ellarc
|
||||
T v_ellpie
|
||||
X v_rbox
|
||||
T v_rfbox
|
||||
T v_justified
|
||||
T vswr_mode
|
||||
> vs_color
|
||||
T vsl_type
|
||||
X vsl_udsty
|
||||
T vsl_width
|
||||
> vsl_color
|
||||
T vsl_ends
|
||||
T vsm_type
|
||||
T vsm_height
|
||||
> vsm_color
|
||||
T vst_height
|
||||
T vst_point
|
||||
T vst_rotation
|
||||
X vst_font
|
||||
> vst_color
|
||||
T vst_effects
|
||||
T vst_alignment
|
||||
T vsf_interior
|
||||
T vsf_style
|
||||
t vsf_color
|
||||
T vsf_perimeter
|
||||
X vsf_udpat
|
||||
t vro_cpyfm
|
||||
> vrt_cpyfm
|
||||
T vr_trnfm
|
||||
> v_get_pixel
|
||||
X vsin_mode
|
||||
X vrq_locator
|
||||
X vsm_locator
|
||||
- vrq_valuator
|
||||
- vsm_valuator
|
||||
X vrq_choice
|
||||
X vsm_choice
|
||||
X vrq_string
|
||||
X vsm_string
|
||||
X vsc_form
|
||||
X vex_timv
|
||||
T v_show_c
|
||||
T v_hide_c
|
||||
X vq_mouse
|
||||
T vex_butv
|
||||
T vex_motv
|
||||
T vex_curv
|
||||
X vq_key_s
|
||||
t vq_extnd
|
||||
> vq_color
|
||||
> vql_attributes
|
||||
> vqm_attributes
|
||||
> vqf_attributes
|
||||
> vqt_attributes
|
||||
> vqt_extent
|
||||
X vqt_width
|
||||
X vqt_name
|
||||
- vq_cellarray (not supported by any current VDI driver)
|
||||
X vqin_mode
|
||||
X vqt_fontinfo
|
||||
T vq_chcells
|
||||
T v_exit_cur
|
||||
T v_enter_cur
|
||||
T v_curup
|
||||
T v_curdown
|
||||
T v_curright
|
||||
T v_curleft
|
||||
T v_curhome
|
||||
T v_eeos
|
||||
T v_eeol
|
||||
T vs_curaddress
|
||||
T v_curtext
|
||||
T v_rvon
|
||||
T v_rvoff
|
||||
T vq_curaddress
|
||||
T vq_tabstatus
|
||||
- v_hardcopy
|
||||
T v_dspcur (Atari docs are incorrect for this call)
|
||||
T v_rmcur (Atari docs are incorrect for this call)
|
||||
- v_form_adv
|
||||
- v_output_window
|
||||
- v_clear_disp_list
|
||||
- v_bit_image
|
||||
- vs_palette
|
||||
- vqp_films
|
||||
- vqp_state
|
||||
- vsp_state
|
||||
- vsp_save
|
||||
- vsp_message
|
||||
- vqp_error
|
||||
- v_meta_extents
|
||||
- v_write_meta
|
||||
- vm_filename
|
||||
|
||||
TOS v4 extended VDI functionality:
|
||||
- 16-bit support for graphics functions (for now, use fVDI)
|
||||
|
||||
|
||||
AES functions
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
All AES versions:
|
||||
t appl_init
|
||||
X appl_read
|
||||
X appl_write
|
||||
t appl_find
|
||||
t appl_tplay
|
||||
X appl_trecord
|
||||
X appl_yield (PC-GEM call)
|
||||
t appl_exit
|
||||
X evnt_keybd
|
||||
t evnt_button
|
||||
X evnt_mouse
|
||||
t evnt_mesag
|
||||
X evnt_timer
|
||||
t evnt_multi
|
||||
X evnt_dclick
|
||||
t menu_bar
|
||||
t menu_icheck
|
||||
X menu_ienable
|
||||
X menu_tnormal
|
||||
X menu_text
|
||||
t menu_register
|
||||
X menu_unregister (PC-GEM call)
|
||||
X menu_click (PC-GEM call)
|
||||
X objc_add
|
||||
X objc_delete
|
||||
t objc_draw
|
||||
X objc_find
|
||||
t objc_offset
|
||||
X objc_order
|
||||
X objc_edit
|
||||
t objc_change
|
||||
t form_do
|
||||
t form_dial
|
||||
t form_alert
|
||||
X form_error
|
||||
t form_center
|
||||
X form_keybd
|
||||
X form_button
|
||||
t graf_rubberbox
|
||||
X graf_dragbox
|
||||
X graf_mbox
|
||||
T graf_growbox
|
||||
T graf_shrinkbox
|
||||
X graf_watchbox
|
||||
X graf_slidebox
|
||||
t graf_handle
|
||||
t graf_mouse
|
||||
t graf_mkstate
|
||||
X scrp_read
|
||||
X scrp_write
|
||||
X scrp_clear (PC-GEM call)
|
||||
X fsel_input
|
||||
t wind_create
|
||||
t wind_open
|
||||
t wind_close
|
||||
t wind_delete
|
||||
t wind_get
|
||||
X wind_set
|
||||
X wind_find
|
||||
t wind_update
|
||||
t wind_calc
|
||||
t rsrc_load
|
||||
t rsrc_free
|
||||
t rsrc_gaddr
|
||||
X rsrc_saddr
|
||||
t rsrc_obfix
|
||||
X shel_read
|
||||
X shel_write
|
||||
X shel_get
|
||||
X shel_put
|
||||
T shel_find
|
||||
X shel_envrn
|
||||
X shel_rdef (PC-GEM call)
|
||||
X shel_wdef (PC-GEM call)
|
||||
|
||||
AES v1.40 (TOS >= v1.04):
|
||||
T fsel_exinput
|
||||
t wind_new
|
||||
|
||||
AES v3.30 (TOS > v3.06):
|
||||
- menu_attach
|
||||
- menu_istart
|
||||
- menu_popup
|
||||
- menu_settings
|
||||
|
||||
AES v3.40 (TOS >= v4):
|
||||
- objc_sysvar (3D look)
|
||||
|
||||
TOS v4 extended AES functionality:
|
||||
- RSC file color icon support
|
||||
|
||||
|
||||
Misc desktop functions
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
- Cartridge file system support (useless - will not be implemented)
|
25
ROMImages/AtariST/doc/todo.txt
Normal file
25
ROMImages/AtariST/doc/todo.txt
Normal file
@ -0,0 +1,25 @@
|
||||
General
|
||||
|
||||
BIOS/XBIOS
|
||||
- implement missing XBIOS calls (e.g. Falcon DSP functions)
|
||||
- reduce the number of 'extern' in .c files
|
||||
- check that RAM disks work
|
||||
- misc. TODOs in floppy.c
|
||||
- implement full XHDI 1.30
|
||||
- let EmuTOS set up correct MMU tree on 68040 (?)
|
||||
|
||||
BDOS (GEMDOS)
|
||||
- move mem-only routines out of proc.c into umem.c or iumem.c
|
||||
|
||||
VDI
|
||||
- The linemask for dashed lines is not calculated correct, depending on
|
||||
the internal calculations of increase in x direction, like in original TOS.
|
||||
|
||||
AES
|
||||
- Implement AES v3.x functions (TOS v3 menu functions and v4 3D look)
|
||||
|
||||
DESK
|
||||
- Add a dialog for configuring the NVRAM (keyboard, languages, ...)
|
||||
- Support for loading DESKTOP.INF (needs remapping of the icon indexes)
|
||||
|
||||
CLI
|
22
ROMImages/AtariST/doc/xhdi.txt
Normal file
22
ROMImages/AtariST/doc/xhdi.txt
Normal file
@ -0,0 +1,22 @@
|
||||
FUNCTION XHDI VERSION SUPPORTED BY EMUTOS
|
||||
----------------------------------------------------------------------
|
||||
XHGETVERSION 0 ALL YES
|
||||
XHINQTARGET 1 ALL YES
|
||||
XHRESERVE 2 ALL NO
|
||||
XHLOCK 3 ALL NO
|
||||
XHSTOP 4 ALL NO
|
||||
XHEJECT 5 ALL NO
|
||||
XHDRVMAP 6 ALL YES
|
||||
XHINQDEV 7 ALL YES
|
||||
XHINQDRIVER 8 ALL YES
|
||||
XHNEWCOOKIE 9 OPTIONAL YES
|
||||
XHREADWRITE 10 ALL YES
|
||||
XHINQTARGET2 11 >= 1.01 YES
|
||||
XHINQDEV2 12 >= 1.10 YES
|
||||
XHDRIVERSPECIAL 13 OPTIONAL NO
|
||||
XHGETCAPACITY 14 OPTIONAL YES
|
||||
XHMEDIUMCHANGED 15 OPTIONAL NO
|
||||
XHMINTINFO 16 OPTIONAL NO
|
||||
XHDOSLIMITS 17 OPTIONAL YES
|
||||
XHLASTACCESS 18 >= 1.25 NO
|
||||
XHREACCESS 19 >= 1.25 NO
|
BIN
ROMImages/AtariST/etos192uk.img
Normal file
BIN
ROMImages/AtariST/etos192uk.img
Normal file
Binary file not shown.
7
ROMImages/AtariST/readme.txt
Normal file
7
ROMImages/AtariST/readme.txt
Normal file
@ -0,0 +1,7 @@
|
||||
THIS EMULATOR DOES NOT EMULATE THE ATARI ST.
|
||||
|
||||
Included here are Atari ST-targeted versions of EmuTOS, being a significant chunk of freely available and redistributable 68000 code that can be used to test the 68000-in-progress.
|
||||
|
||||
EmuTOS is distributed under the GPL. See its licence and other information within the doc/ subdirectory.
|
||||
|
||||
It was obtained via http://emutos.sourceforge.net/en/
|
BIN
ROMImages/SinclairQL/js.rom
Normal file
BIN
ROMImages/SinclairQL/js.rom
Normal file
Binary file not shown.
5
ROMImages/SinclairQL/readme.txt
Normal file
5
ROMImages/SinclairQL/readme.txt
Normal file
@ -0,0 +1,5 @@
|
||||
Supplied files:
|
||||
|
||||
js.rom
|
||||
|
||||
This file is copyright Amstrad but non-profit redistribution is permitted.
|
Loading…
Reference in New Issue
Block a user