diff --git a/Components/DiskII/DiskII.cpp b/Components/DiskII/DiskII.cpp new file mode 100644 index 000000000..0c92ad670 --- /dev/null +++ b/Components/DiskII/DiskII.cpp @@ -0,0 +1,9 @@ +// +// DiskII.cpp +// Clock Signal +// +// Created by Thomas Harte on 20/04/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#include "DiskII.hpp" diff --git a/Components/DiskII/DiskII.hpp b/Components/DiskII/DiskII.hpp new file mode 100644 index 000000000..49006bf3e --- /dev/null +++ b/Components/DiskII/DiskII.hpp @@ -0,0 +1,40 @@ +// +// DiskII.hpp +// Clock Signal +// +// Created by Thomas Harte on 20/04/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef DiskII_hpp +#define DiskII_hpp + +#include "../../ClockReceiver/ClockReceiver.hpp" +#include + +namespace Apple { + +/*! + Provides an emulation of the Apple Disk II. +*/ +class DiskII { + public: + enum class Control { + P0, P1, P2, P3, + Motor, + }; + enum class Mode { + Read, Write + }; + void set_control(Control control, bool on); + void set_mode(Mode mode); + void select_drive(int drive); + void set_shift_register(uint8_t value); + uint8_t get_shift_register(); + + void run_for(const Cycles cycles); +}; + +} + +#endif /* DiskII_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 432e5621c..18ab9f86b 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -157,6 +157,8 @@ 4B2C45421E3C3896002A2389 /* cartridge.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B2C45411E3C3896002A2389 /* cartridge.png */; }; 4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; }; 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; }; + 4B302184208A550100773308 /* DiskII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B302183208A550100773308 /* DiskII.cpp */; }; + 4B302185208A550100773308 /* DiskII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B302183208A550100773308 /* DiskII.cpp */; }; 4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B30512B1D989E2200B4FED8 /* Drive.cpp */; }; 4B3051301D98ACC600B4FED8 /* Plus3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B30512E1D98ACC600B4FED8 /* Plus3.cpp */; }; 4B322E011F5A2990004EB04C /* Z80AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B322DFD1F5A2981004EB04C /* Z80AllRAM.cpp */; }; @@ -579,6 +581,8 @@ 4BB299F81B587D8400A49093 /* txsn in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298EC1B587D8400A49093 /* txsn */; }; 4BB299F91B587D8400A49093 /* tyan in Resources */ = {isa = PBXBuildFile; fileRef = 4BB298ED1B587D8400A49093 /* tyan */; }; 4BB2A9AF1E13367E001A5C23 /* CRCTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */; }; + 4BB2CB2A208BDDCF00FD192E /* AppleGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB2CB28208BDDCF00FD192E /* AppleGCR.cpp */; }; + 4BB2CB2B208BDDCF00FD192E /* AppleGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB2CB28208BDDCF00FD192E /* AppleGCR.cpp */; }; 4BB697CB1D4B6D3E00248BDF /* TimedEventLoop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */; }; 4BB697CE1D4BA44400248BDF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; }; 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BB73EA11B587A5100552FC2 /* AppDelegate.swift */; }; @@ -754,6 +758,8 @@ 4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = ""; }; 4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = ""; }; 4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = ""; }; + 4B302182208A550100773308 /* DiskII.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskII.hpp; sourceTree = ""; }; + 4B302183208A550100773308 /* DiskII.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskII.cpp; sourceTree = ""; }; 4B30512B1D989E2200B4FED8 /* Drive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drive.cpp; sourceTree = ""; }; 4B30512C1D989E2200B4FED8 /* Drive.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Drive.hpp; sourceTree = ""; }; 4B30512E1D98ACC600B4FED8 /* Plus3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Plus3.cpp; path = Electron/Plus3.cpp; sourceTree = ""; }; @@ -1275,6 +1281,8 @@ 4BB298EC1B587D8400A49093 /* txsn */ = {isa = PBXFileReference; lastKnownFileType = file; path = txsn; sourceTree = ""; }; 4BB298ED1B587D8400A49093 /* tyan */ = {isa = PBXFileReference; lastKnownFileType = file; path = tyan; sourceTree = ""; }; 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CRCTests.mm; sourceTree = ""; }; + 4BB2CB28208BDDCF00FD192E /* AppleGCR.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = AppleGCR.cpp; path = Encodings/AppleGCR.cpp; sourceTree = ""; }; + 4BB2CB29208BDDCF00FD192E /* AppleGCR.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = AppleGCR.hpp; path = Encodings/AppleGCR.hpp; sourceTree = ""; }; 4BB697C61D4B558F00248BDF /* Factors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Factors.hpp; path = ../../NumberTheory/Factors.hpp; sourceTree = ""; }; 4BB697C91D4B6D3E00248BDF /* TimedEventLoop.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimedEventLoop.cpp; sourceTree = ""; }; 4BB697CA1D4B6D3E00248BDF /* TimedEventLoop.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TimedEventLoop.hpp; sourceTree = ""; }; @@ -1674,6 +1682,15 @@ name = Electron; sourceTree = ""; }; + 4B302181208A550100773308 /* DiskII */ = { + isa = PBXGroup; + children = ( + 4B302182208A550100773308 /* DiskII.hpp */, + 4B302183208A550100773308 /* DiskII.cpp */, + ); + path = DiskII; + sourceTree = ""; + }; 4B31B88E1FBFBCD800C140D5 /* Configurable */ = { isa = PBXGroup; children = ( @@ -2630,9 +2647,11 @@ 4BB697CF1D4BA44900248BDF /* Encodings */ = { isa = PBXGroup; children = ( - 4B7136831F78724F008B8ED9 /* MFM */, + 4BB2CB28208BDDCF00FD192E /* AppleGCR.cpp */, 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */, + 4BB2CB29208BDDCF00FD192E /* AppleGCR.hpp */, 4BB697CD1D4BA44400248BDF /* CommodoreGCR.hpp */, + 4B7136831F78724F008B8ED9 /* MFM */, ); name = Encodings; sourceTree = ""; @@ -2850,6 +2869,7 @@ 4BC9DF4A1D04691600F44158 /* Components */ = { isa = PBXGroup; children = ( + 4B302181208A550100773308 /* DiskII */, 4B595FAA2086DFBA0083CAA8 /* AudioToggle */, 4BD468F81D8DF4290084958B /* 1770 */, 4BC9DF4B1D04691600F44158 /* 6522 */, @@ -3598,6 +3618,7 @@ 4B894525201967B4007DE474 /* Tape.cpp in Sources */, 4B055ACD1FAE9B030060FFFF /* Keyboard.cpp in Sources */, 4B055AB21FAE860F0060FFFF /* CommodoreTAP.cpp in Sources */, + 4BB2CB2B208BDDCF00FD192E /* AppleGCR.cpp in Sources */, 4B055ADF1FAE9B4C0060FFFF /* IRQDelegatePortHandler.cpp in Sources */, 4B055AB51FAE860F0060FFFF /* TapePRG.cpp in Sources */, 4B055AE01FAE9B660060FFFF /* CRT.cpp in Sources */, @@ -3623,6 +3644,7 @@ 4BB0A65C2044FD3000FB3688 /* SN76489.cpp in Sources */, 4B595FAE2086DFBA0083CAA8 /* AudioToggle.cpp in Sources */, 4B055AB91FAE86170060FFFF /* Acorn.cpp in Sources */, + 4B302185208A550100773308 /* DiskII.cpp in Sources */, 4B055A931FAE85B50060FFFF /* BinaryDump.cpp in Sources */, 4B89452D201967B4007DE474 /* Tape.cpp in Sources */, 4B055AD61FAE9B130060FFFF /* MemoryFuzzer.cpp in Sources */, @@ -3654,6 +3676,7 @@ 4B4518A01F75FD1C00926311 /* CPCDSK.cpp in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4B322E041F5A2E3C004EB04C /* Z80Base.cpp in Sources */, + 4BB2CB2A208BDDCF00FD192E /* AppleGCR.cpp in Sources */, 4B894530201967B4007DE474 /* StaticAnalyser.cpp in Sources */, 4B4518A31F75FD1C00926311 /* HFE.cpp in Sources */, 4B1B88BB202E2EC100B67DFF /* MultiKeyboardMachine.cpp in Sources */, @@ -3707,6 +3730,7 @@ 4B448E811F1C45A00009ABD6 /* TZX.cpp in Sources */, 4BEBFB512002DB30000708CC /* DiskROM.cpp in Sources */, 4B89451C201967B4007DE474 /* Disk.cpp in Sources */, + 4B302184208A550100773308 /* DiskII.cpp in Sources */, 4BEA52631DF339D7007E74F2 /* SoundGenerator.cpp in Sources */, 4BAE495920328897004BE78E /* ZX8081OptionsPanel.swift in Sources */, 4B89451A201967B4007DE474 /* ConfidenceSummary.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme index f9049689f..782b17c09 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal.xcscheme @@ -68,7 +68,7 @@ (five_and_three_encoding_for_value( source[0] >> 3 )); + destination[1] = static_cast(five_and_three_encoding_for_value( (source[0] << 2) | (source[1] >> 6) )); + destination[2] = static_cast(five_and_three_encoding_for_value( source[1] >> 1 )); + destination[3] = static_cast(five_and_three_encoding_for_value( (source[1] << 4) | (source[2] >> 4) )); + destination[4] = static_cast(five_and_three_encoding_for_value( (source[2] << 1) | (source[3] >> 7) )); + destination[5] = static_cast(five_and_three_encoding_for_value( source[3] >> 2 )); + destination[6] = static_cast(five_and_three_encoding_for_value( (source[3] << 3) | (source[4] >> 5) )); + destination[7] = static_cast(five_and_three_encoding_for_value( source[4] )); +} + +unsigned int AppleGCR::six_and_two_encoding_for_value(int value) { + static const unsigned int values[] = { + 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, + 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, + 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, + 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + return values[value & 0x3f]; +} + +void AppleGCR::encode_six_and_two_block(uint8_t *destination, uint8_t *source) { + destination[0] = static_cast(six_and_two_encoding_for_value( source[0] >> 2 )); + destination[1] = static_cast(six_and_two_encoding_for_value( (source[0] << 4) | (source[1] >> 4) )); + destination[2] = static_cast(six_and_two_encoding_for_value( (source[1] << 2) | (source[2] >> 6) )); + destination[3] = static_cast(six_and_two_encoding_for_value( source[2] )); +} diff --git a/Storage/Disk/Encodings/AppleGCR.hpp b/Storage/Disk/Encodings/AppleGCR.hpp new file mode 100644 index 000000000..f152bb4b2 --- /dev/null +++ b/Storage/Disk/Encodings/AppleGCR.hpp @@ -0,0 +1,53 @@ +// +// AppleGCR.hpp +// Clock Signal +// +// Created by Thomas Harte on 21/04/2018. +// Copyright © 2018 Thomas Harte. All rights reserved. +// + +#ifndef AppleGCR_hpp +#define AppleGCR_hpp + +#include + +namespace Storage { +namespace Encodings { + +namespace AppleGCR { + + /*! + @returns the eight-bit 13-sector GCR encoding for the low five bits of @c value. + */ + unsigned int five_and_three_encoding_for_value(int value); + + /*! + @returns the eight-bit 16-sector GCR encoding for the low six bits of @c value. + */ + unsigned int six_and_two_encoding_for_value(int value); + + /*! + A block is defined to be five source bytes, which encodes to eight GCR bytes. + */ + void encode_five_and_three_block(uint8_t *destination, uint8_t *source); + + /*! + A block is defined to be three source bytes, which encodes to four GCR bytes. + */ + void encode_six_and_two_block(uint8_t *destination, uint8_t *source); + + /*! + @returns the four bit nibble for the five-bit GCR @c quintet if a valid GCR value; INT_MAX otherwise. + */ +// unsigned int decoding_from_quintet(unsigned int quintet); + + /*! + @returns the byte composed by splitting the dectet into two qintets, decoding each and composing the resulting nibbles. + */ +// unsigned int decoding_from_dectet(unsigned int dectet); +} + +} +} + +#endif /* AppleGCR_hpp */ diff --git a/Storage/Disk/Encodings/CommodoreGCR.hpp b/Storage/Disk/Encodings/CommodoreGCR.hpp index 467b68691..fe78d9391 100644 --- a/Storage/Disk/Encodings/CommodoreGCR.hpp +++ b/Storage/Disk/Encodings/CommodoreGCR.hpp @@ -43,7 +43,7 @@ namespace CommodoreGCR { unsigned int decoding_from_quintet(unsigned int quintet); /*! - @returns the byte composted of the low five bit five-bit GCR + @returns the byte composed by splitting the dectet into two qintets, decoding each and composing the resulting nibbles. */ unsigned int decoding_from_dectet(unsigned int dectet); }