From 404873fe587e024b57e1da5192b62ccc120416a9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jun 2016 21:43:50 -0400 Subject: [PATCH 01/66] Started sketching out infrastructure for Vic-20 support. --- Machines/Vic-20/Vic20.cpp | 9 +++++ Machines/Vic-20/Vic20.hpp | 22 +++++++++++ .../Clock Signal.xcodeproj/project.pbxproj | 38 ++++++++++++++++++- .../Base.lproj/Atari2600Document.xib | 2 +- .../ClockSignal-Bridging-Header.h | 2 + .../Documents/Atari2600Document.swift | 8 ---- .../Documents/MachineDocument.swift | 5 +++ .../Documents/Vic20Document.swift | 24 ++++++++++++ OSBindings/Mac/Clock Signal/Info.plist | 14 +++++++ .../Mac/Clock Signal/Wrappers/CSVic20.h | 13 +++++++ .../Mac/Clock Signal/Wrappers/CSVic20.m | 13 +++++++ 11 files changed, 140 insertions(+), 10 deletions(-) create mode 100644 Machines/Vic-20/Vic20.cpp create mode 100644 Machines/Vic-20/Vic20.hpp create mode 100644 OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp new file mode 100644 index 000000000..58e027eaf --- /dev/null +++ b/Machines/Vic-20/Vic20.cpp @@ -0,0 +1,9 @@ +// +// Vic20.cpp +// Clock Signal +// +// Created by Thomas Harte on 04/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "Vic20.hpp" diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp new file mode 100644 index 000000000..59f16351a --- /dev/null +++ b/Machines/Vic-20/Vic20.hpp @@ -0,0 +1,22 @@ +// +// Vic20.hpp +// Clock Signal +// +// Created by Thomas Harte on 04/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef Vic20_hpp +#define Vic20_hpp + +#include "../../Processors/6502/CPU6502.hpp" +#include "../CRTMachine.hpp" + +namespace Vic20 { + +class Machine: public CPU6502::Processor, public CRTMachine::Machine { +}; + +} + +#endif /* Vic20_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 0edc27528..375490caa 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -28,6 +28,10 @@ 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; }; 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; }; 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; + 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; }; + 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; }; + 4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF01D03B517004291C3 /* Vic20.cpp */; }; + 4B886FF51D03B61E004291C3 /* CSVic20.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF41D03B61E004291C3 /* CSVic20.m */; }; 4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; }; 4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; }; 4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; }; @@ -373,6 +377,12 @@ 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapeUEF.cpp; sourceTree = ""; }; 4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TapeUEF.hpp; sourceTree = ""; }; 4B69FB451C4D950F00B5F0AA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 4B73C7191D036BD90074D992 /* Vic20Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vic20Document.swift; sourceTree = ""; }; + 4B73C71C1D036C030074D992 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = "Clock Signal/Base.lproj/Vic20Document.xib"; sourceTree = SOURCE_ROOT; }; + 4B886FF01D03B517004291C3 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vic20.cpp; path = "Vic-20/Vic20.cpp"; sourceTree = ""; }; + 4B886FF11D03B517004291C3 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Vic20.hpp; path = "Vic-20/Vic20.hpp"; sourceTree = ""; }; + 4B886FF31D03B61E004291C3 /* CSVic20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVic20.h; sourceTree = ""; }; + 4B886FF41D03B61E004291C3 /* CSVic20.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSVic20.m; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyCodes.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; @@ -793,6 +803,8 @@ 4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */, 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */, 4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */, + 4B886FF31D03B61E004291C3 /* CSVic20.h */, + 4B886FF41D03B61E004291C3 /* CSVic20.m */, 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */, ); path = Wrappers; @@ -806,6 +818,8 @@ 4B55CE571C3B7D360093A61B /* ElectronDocument.swift */, 4B2E2D931C399D1200138695 /* ElectronDocument.xib */, 4B55CE5E1C3B7D960093A61B /* MachineDocument.swift */, + 4B73C7191D036BD90074D992 /* Vic20Document.swift */, + 4B73C71B1D036C030074D992 /* Vic20Document.xib */, ); path = Documents; sourceTree = ""; @@ -848,6 +862,15 @@ path = Formats; sourceTree = ""; }; + 4B886FF61D03B632004291C3 /* Vic-20 */ = { + isa = PBXGroup; + children = ( + 4B886FF01D03B517004291C3 /* Vic20.cpp */, + 4B886FF11D03B517004291C3 /* Vic20.hpp */, + ); + name = "Vic-20"; + sourceTree = ""; + }; 4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */ = { isa = PBXGroup; children = ( @@ -1191,9 +1214,10 @@ 4BB73EDC1B587CA500552FC2 /* Machines */ = { isa = PBXGroup; children = ( + 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */, 4B2E2D961C3A06EC00138695 /* Atari2600 */, 4B2E2D9E1C3A070900138695 /* Electron */, - 4B046DC31CFE651500E9E45E /* CRTMachine.hpp */, + 4B886FF61D03B632004291C3 /* Vic-20 */, ); name = Machines; path = ../../Machines; @@ -1370,6 +1394,7 @@ 4BE5F85F1C3E1C2500C43F01 /* os.rom in Resources */, 4BCB70B41C947DDC005B1712 /* plus1.rom in Resources */, 4BB73EA71B587A5100552FC2 /* Atari2600Document.xib in Resources */, + 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */, 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, 4BE5F85E1C3E1C2500C43F01 /* basic.rom in Resources */, ); @@ -1667,11 +1692,14 @@ 4B55CE541C3B7ABF0093A61B /* CSElectron.mm in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */, + 4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */, 4BC3B74F1CD194CC00F86E85 /* Shader.cpp in Sources */, 4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */, 4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */, 4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */, 4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */, + 4B886FF51D03B61E004291C3 /* CSVic20.m in Sources */, + 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */, 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */, 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */, 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, @@ -1736,6 +1764,14 @@ path = ..; sourceTree = ""; }; + 4B73C71B1D036C030074D992 /* Vic20Document.xib */ = { + isa = PBXVariantGroup; + children = ( + 4B73C71C1D036C030074D992 /* Base */, + ); + name = Vic20Document.xib; + sourceTree = ""; + }; 4BB73EA51B587A5100552FC2 /* Atari2600Document.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib b/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib index 9e73f7195..e1f140fda 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib @@ -1,5 +1,5 @@ - + diff --git a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h index 552a4cbd4..c87782a47 100644 --- a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h +++ b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h @@ -3,8 +3,10 @@ // #import "CSMachine.h" + #import "CSAtari2600.h" #import "CSElectron.h" +#import "CSVic20.h" #import "CSOpenGLView.h" #import "AudioQueue.h" diff --git a/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift b/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift index e13fff8fa..fd546a79b 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift @@ -26,17 +26,9 @@ class Atari2600Document: MachineDocument { } override var windowNibName: String? { - // Returns the nib file name of the document - // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this property and override -makeWindowControllers instead. return "Atari2600Document" } - override func dataOfType(typeName: String) throws -> NSData { - // Insert code here to write your document to data of the specified type. If outError != nil, ensure that you create and set an appropriate error when returning nil. - // You can also choose to override fileWrapperOfType:error:, writeToURL:ofType:error:, or writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead. - throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) - } - override func readFromData(data: NSData, ofType typeName: String) throws { atari2600.setROM(data) } diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index e752f032f..3f8e8ec60 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -114,4 +114,9 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe func keyDown(event: NSEvent) {} func keyUp(event: NSEvent) {} func flagsChanged(newModifiers: NSEvent) {} + + // MARK: NSDocument overrides + override func dataOfType(typeName: String) throws -> NSData { + throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) + } } diff --git a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift new file mode 100644 index 000000000..08b9b6bc0 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift @@ -0,0 +1,24 @@ +// +// Vic20Document.swift +// Clock Signal +// +// Created by Thomas Harte on 04/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +import Foundation + +class Vic20Document: MachineDocument { + + private lazy var vic20 = CSVic20() + override func machine() -> CSMachine! { + return vic20 + } + + // MARK: NSDocument overrides + override init() { + super.init() + self.intendedCyclesPerSecond = 1022727 + // TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt + } +} diff --git a/OSBindings/Mac/Clock Signal/Info.plist b/OSBindings/Mac/Clock Signal/Info.plist index 07d3a41d5..3fbd5f02d 100644 --- a/OSBindings/Mac/Clock Signal/Info.plist +++ b/OSBindings/Mac/Clock Signal/Info.plist @@ -74,6 +74,20 @@ NSDocumentClass $(PRODUCT_MODULE_NAME).ElectronDocument + + CFBundleTypeExtensions + + prg + + CFBundleTypeName + Vic-20 Cartridge + CFBundleTypeRole + Viewer + LSTypeIsPackage + 0 + NSDocumentClass + Vic20Document + CFBundleExecutable $(EXECUTABLE_NAME) diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h new file mode 100644 index 000000000..039e6afb0 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h @@ -0,0 +1,13 @@ +// +// CSVic20.h +// Clock Signal +// +// Created by Thomas Harte on 04/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import "CSMachine.h" + +@interface CSVic20 : CSMachine + +@end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m new file mode 100644 index 000000000..64d7cdb49 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m @@ -0,0 +1,13 @@ +// +// CSVic20.m +// Clock Signal +// +// Created by Thomas Harte on 04/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#import "CSVic20.h" + +@implementation CSVic20 + +@end From eff28e95a4e6019e59f19a58ee438286fe827d9d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jun 2016 21:45:39 -0400 Subject: [PATCH 02/66] Added XIB file. --- .../Clock Signal/Base.lproj/Vic20Document.xib | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 OSBindings/Mac/Clock Signal/Base.lproj/Vic20Document.xib diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/Vic20Document.xib b/OSBindings/Mac/Clock Signal/Base.lproj/Vic20Document.xib new file mode 100644 index 000000000..e1f140fda --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Base.lproj/Vic20Document.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 06e1db8c858f18b9b2535e52cf0afe3898bc9a50 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jun 2016 21:49:03 -0400 Subject: [PATCH 03/66] This now gets as far as missing selectors. --- .../Mac/Clock Signal/Documents/Vic20Document.swift | 12 ++++++++++++ OSBindings/Mac/Clock Signal/Info.plist | 2 +- OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm | 1 - 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift index 08b9b6bc0..0741a6ed3 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift @@ -21,4 +21,16 @@ class Vic20Document: MachineDocument { self.intendedCyclesPerSecond = 1022727 // TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt } + + override class func autosavesInPlace() -> Bool { + return true + } + + override var windowNibName: String? { + return "Vic20Document" + } + + override func readFromData(data: NSData, ofType typeName: String) throws { + print("\(data.length)") + } } diff --git a/OSBindings/Mac/Clock Signal/Info.plist b/OSBindings/Mac/Clock Signal/Info.plist index 3fbd5f02d..212e82a8e 100644 --- a/OSBindings/Mac/Clock Signal/Info.plist +++ b/OSBindings/Mac/Clock Signal/Info.plist @@ -86,7 +86,7 @@ LSTypeIsPackage 0 NSDocumentClass - Vic20Document + $(PRODUCT_MODULE_NAME).Vic20Document CFBundleExecutable diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm index eefdec3fd..3f5cedbef 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm @@ -88,5 +88,4 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate { self.machine->get_crt()->draw_frame((unsigned int)pixelSize.width, (unsigned int)pixelSize.height, onlyIfDirty ? true : false); } - @end From b10a06e70080c7f164442fd9ca22c56915040405 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jun 2016 22:00:50 -0400 Subject: [PATCH 04/66] A CRT is still absent but this moves the ball back into the C++ side's court. --- Machines/Vic-20/Vic20.cpp | 7 +++++++ Machines/Vic-20/Vic20.hpp | 11 +++++++++++ OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj | 8 ++++---- .../Clock Signal/Wrappers/{CSVic20.m => CSVic20.mm} | 10 +++++++++- 4 files changed, 31 insertions(+), 5 deletions(-) rename OSBindings/Mac/Clock Signal/Wrappers/{CSVic20.m => CSVic20.mm} (55%) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 58e027eaf..e3e3b5e2b 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -7,3 +7,10 @@ // #include "Vic20.hpp" + +using namespace Vic20; + +unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) +{ + return 1; +} diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 59f16351a..03d79654b 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -15,6 +15,17 @@ namespace Vic20 { class Machine: public CPU6502::Processor, public CRTMachine::Machine { + public: + // to satisfy CPU6502::Processor + unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); + void synchronise() {} + + // to satisfy CRTMachine::Machine + virtual void setup_output(float aspect_ratio) {} + virtual void close_output() {} + virtual Outputs::CRT::CRT *get_crt() { return nullptr; } // TODO + virtual Outputs::Speaker *get_speaker() { return nullptr; } // TODO + virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor::run_for_cycles(number_of_cycles); } }; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 375490caa..39ae448ce 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -31,7 +31,7 @@ 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B73C7191D036BD90074D992 /* Vic20Document.swift */; }; 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; }; 4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF01D03B517004291C3 /* Vic20.cpp */; }; - 4B886FF51D03B61E004291C3 /* CSVic20.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF41D03B61E004291C3 /* CSVic20.m */; }; + 4B886FF51D03B61E004291C3 /* CSVic20.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF41D03B61E004291C3 /* CSVic20.mm */; }; 4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; }; 4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; }; 4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; }; @@ -382,7 +382,7 @@ 4B886FF01D03B517004291C3 /* Vic20.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vic20.cpp; path = "Vic-20/Vic20.cpp"; sourceTree = ""; }; 4B886FF11D03B517004291C3 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Vic20.hpp; path = "Vic-20/Vic20.hpp"; sourceTree = ""; }; 4B886FF31D03B61E004291C3 /* CSVic20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVic20.h; sourceTree = ""; }; - 4B886FF41D03B61E004291C3 /* CSVic20.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CSVic20.m; sourceTree = ""; }; + 4B886FF41D03B61E004291C3 /* CSVic20.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSVic20.mm; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyCodes.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; @@ -804,7 +804,7 @@ 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */, 4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */, 4B886FF31D03B61E004291C3 /* CSVic20.h */, - 4B886FF41D03B61E004291C3 /* CSVic20.m */, + 4B886FF41D03B61E004291C3 /* CSVic20.mm */, 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */, ); path = Wrappers; @@ -1698,7 +1698,7 @@ 4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */, 4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */, 4BBB14311CD2CECE00BDB55C /* IntermediateShader.cpp in Sources */, - 4B886FF51D03B61E004291C3 /* CSVic20.m in Sources */, + 4B886FF51D03B61E004291C3 /* CSVic20.mm in Sources */, 4B73C71A1D036BD90074D992 /* Vic20Document.swift in Sources */, 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */, 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm similarity index 55% rename from OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m rename to OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index 64d7cdb49..6447e5d49 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.m +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -8,6 +8,14 @@ #import "CSVic20.h" -@implementation CSVic20 +#import "Vic20.hpp" + +@implementation CSVic20 { + Vic20::Machine _vic20; +} + +- (CRTMachine::Machine * const)machine { + return &_vic20; +} @end From 4c33517228f3b091c8ae401ab1fb03ed389d6da8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 4 Jun 2016 22:03:38 -0400 Subject: [PATCH 05/66] Added ROMs to the project and ensured they don't get uploaded. --- .gitignore | 3 +- .../Clock Signal.xcodeproj/project.pbxproj | 48 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c2d42ca10..1d4cfe47f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,8 +18,9 @@ DerivedData *.xcuserstate .DS_Store -# Exclude Electron ROMs +# Exclude system ROMs OSBindings/Mac/Clock Signal/Resources/Electron/* +OSBindings/Mac/Clock Signal/Resources/Vic20/* # CocoaPods # diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 39ae448ce..a0498bf5f 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -32,6 +32,16 @@ 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; }; 4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF01D03B517004291C3 /* Vic20.cpp */; }; 4B886FF51D03B61E004291C3 /* CSVic20.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF41D03B61E004291C3 /* CSVic20.mm */; }; + 4B8870021D03BFEC004291C3 /* basic.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FF81D03BFEC004291C3 /* basic.bin */; }; + 4B8870031D03BFEC004291C3 /* characters-danish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FF91D03BFEC004291C3 /* characters-danish.bin */; }; + 4B8870041D03BFEC004291C3 /* characters-english.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFA1D03BFEC004291C3 /* characters-english.bin */; }; + 4B8870051D03BFEC004291C3 /* characters-japanese.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFB1D03BFEC004291C3 /* characters-japanese.bin */; }; + 4B8870061D03BFEC004291C3 /* characters-swedish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFC1D03BFEC004291C3 /* characters-swedish.bin */; }; + 4B8870071D03BFEC004291C3 /* kernel-danish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFD1D03BFEC004291C3 /* kernel-danish.bin */; }; + 4B8870081D03BFEC004291C3 /* kernel-japanese.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFE1D03BFEC004291C3 /* kernel-japanese.bin */; }; + 4B8870091D03BFEC004291C3 /* kernel-ntsc.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFF1D03BFEC004291C3 /* kernel-ntsc.bin */; }; + 4B88700A1D03BFEC004291C3 /* kernel-pal.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B8870001D03BFEC004291C3 /* kernel-pal.bin */; }; + 4B88700B1D03BFEC004291C3 /* kernel-swedish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B8870011D03BFEC004291C3 /* kernel-swedish.bin */; }; 4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; }; 4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; }; 4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; }; @@ -383,6 +393,16 @@ 4B886FF11D03B517004291C3 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Vic20.hpp; path = "Vic-20/Vic20.hpp"; sourceTree = ""; }; 4B886FF31D03B61E004291C3 /* CSVic20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVic20.h; sourceTree = ""; }; 4B886FF41D03B61E004291C3 /* CSVic20.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSVic20.mm; sourceTree = ""; }; + 4B886FF81D03BFEC004291C3 /* basic.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = basic.bin; sourceTree = ""; }; + 4B886FF91D03BFEC004291C3 /* characters-danish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-danish.bin"; sourceTree = ""; }; + 4B886FFA1D03BFEC004291C3 /* characters-english.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-english.bin"; sourceTree = ""; }; + 4B886FFB1D03BFEC004291C3 /* characters-japanese.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-japanese.bin"; sourceTree = ""; }; + 4B886FFC1D03BFEC004291C3 /* characters-swedish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-swedish.bin"; sourceTree = ""; }; + 4B886FFD1D03BFEC004291C3 /* kernel-danish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-danish.bin"; sourceTree = ""; }; + 4B886FFE1D03BFEC004291C3 /* kernel-japanese.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-japanese.bin"; sourceTree = ""; }; + 4B886FFF1D03BFEC004291C3 /* kernel-ntsc.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-ntsc.bin"; sourceTree = ""; }; + 4B8870001D03BFEC004291C3 /* kernel-pal.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-pal.bin"; sourceTree = ""; }; + 4B8870011D03BFEC004291C3 /* kernel-swedish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-swedish.bin"; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyCodes.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; @@ -871,6 +891,23 @@ name = "Vic-20"; sourceTree = ""; }; + 4B886FF71D03BFEC004291C3 /* Vic20 */ = { + isa = PBXGroup; + children = ( + 4B886FF81D03BFEC004291C3 /* basic.bin */, + 4B886FF91D03BFEC004291C3 /* characters-danish.bin */, + 4B886FFA1D03BFEC004291C3 /* characters-english.bin */, + 4B886FFB1D03BFEC004291C3 /* characters-japanese.bin */, + 4B886FFC1D03BFEC004291C3 /* characters-swedish.bin */, + 4B886FFD1D03BFEC004291C3 /* kernel-danish.bin */, + 4B886FFE1D03BFEC004291C3 /* kernel-japanese.bin */, + 4B886FFF1D03BFEC004291C3 /* kernel-ntsc.bin */, + 4B8870001D03BFEC004291C3 /* kernel-pal.bin */, + 4B8870011D03BFEC004291C3 /* kernel-swedish.bin */, + ); + path = Vic20; + sourceTree = ""; + }; 4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */ = { isa = PBXGroup; children = ( @@ -1265,6 +1302,7 @@ 4BE5F85A1C3E1C2500C43F01 /* Resources */ = { isa = PBXGroup; children = ( + 4B886FF71D03BFEC004291C3 /* Vic20 */, 4BE5F85B1C3E1C2500C43F01 /* Electron */, ); path = Resources; @@ -1389,14 +1427,24 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4B8870021D03BFEC004291C3 /* basic.bin in Resources */, 4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */, + 4B88700B1D03BFEC004291C3 /* kernel-swedish.bin in Resources */, 4BB73EA91B587A5100552FC2 /* Assets.xcassets in Resources */, 4BE5F85F1C3E1C2500C43F01 /* os.rom in Resources */, 4BCB70B41C947DDC005B1712 /* plus1.rom in Resources */, + 4B8870071D03BFEC004291C3 /* kernel-danish.bin in Resources */, 4BB73EA71B587A5100552FC2 /* Atari2600Document.xib in Resources */, + 4B8870031D03BFEC004291C3 /* characters-danish.bin in Resources */, 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */, + 4B8870041D03BFEC004291C3 /* characters-english.bin in Resources */, + 4B88700A1D03BFEC004291C3 /* kernel-pal.bin in Resources */, 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, + 4B8870051D03BFEC004291C3 /* characters-japanese.bin in Resources */, + 4B8870091D03BFEC004291C3 /* kernel-ntsc.bin in Resources */, + 4B8870061D03BFEC004291C3 /* characters-swedish.bin in Resources */, 4BE5F85E1C3E1C2500C43F01 /* basic.rom in Resources */, + 4B8870081D03BFEC004291C3 /* kernel-japanese.bin in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 363e14a92fd2f9471af1da3ee7ca49233890d8bc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 08:33:01 -0400 Subject: [PATCH 06/66] Reorganised system ROMs out of the Mac-specific folder, adjusted Mac code to expect to find them organised hierarchically (as how many os.roms am I going to have?) and added readme files to explain what's missing from the Git repository. --- .gitignore | 3 +- .../Clock Signal.xcodeproj/project.pbxproj | 72 ++----------------- .../Documents/ElectronDocument.swift | 16 +++-- .../Documents/MachineDocument.swift | 9 +++ ROMImages/Electron/readme.txt | 16 +++++ ROMImages/Vic20/readme.txt | 17 +++++ 6 files changed, 57 insertions(+), 76 deletions(-) create mode 100644 ROMImages/Electron/readme.txt create mode 100644 ROMImages/Vic20/readme.txt diff --git a/.gitignore b/.gitignore index 1d4cfe47f..3eacdcc4a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,8 +19,7 @@ DerivedData .DS_Store # Exclude system ROMs -OSBindings/Mac/Clock Signal/Resources/Electron/* -OSBindings/Mac/Clock Signal/Resources/Vic20/* +ROMImages/* # CocoaPods # diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index a0498bf5f..6d16df570 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -32,16 +32,6 @@ 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B73C71B1D036C030074D992 /* Vic20Document.xib */; }; 4B886FF21D03B517004291C3 /* Vic20.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF01D03B517004291C3 /* Vic20.cpp */; }; 4B886FF51D03B61E004291C3 /* CSVic20.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B886FF41D03B61E004291C3 /* CSVic20.mm */; }; - 4B8870021D03BFEC004291C3 /* basic.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FF81D03BFEC004291C3 /* basic.bin */; }; - 4B8870031D03BFEC004291C3 /* characters-danish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FF91D03BFEC004291C3 /* characters-danish.bin */; }; - 4B8870041D03BFEC004291C3 /* characters-english.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFA1D03BFEC004291C3 /* characters-english.bin */; }; - 4B8870051D03BFEC004291C3 /* characters-japanese.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFB1D03BFEC004291C3 /* characters-japanese.bin */; }; - 4B8870061D03BFEC004291C3 /* characters-swedish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFC1D03BFEC004291C3 /* characters-swedish.bin */; }; - 4B8870071D03BFEC004291C3 /* kernel-danish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFD1D03BFEC004291C3 /* kernel-danish.bin */; }; - 4B8870081D03BFEC004291C3 /* kernel-japanese.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFE1D03BFEC004291C3 /* kernel-japanese.bin */; }; - 4B8870091D03BFEC004291C3 /* kernel-ntsc.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B886FFF1D03BFEC004291C3 /* kernel-ntsc.bin */; }; - 4B88700A1D03BFEC004291C3 /* kernel-pal.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B8870001D03BFEC004291C3 /* kernel-pal.bin */; }; - 4B88700B1D03BFEC004291C3 /* kernel-swedish.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B8870011D03BFEC004291C3 /* kernel-swedish.bin */; }; 4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; }; 4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; }; 4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; }; @@ -325,9 +315,7 @@ 4BC3B7521CD1956900F86E85 /* OutputShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC3B7501CD1956900F86E85 /* OutputShader.cpp */; }; 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; }; 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; }; - 4BCB70B41C947DDC005B1712 /* plus1.rom in Resources */ = {isa = PBXBuildFile; fileRef = 4BCB70B31C947DDC005B1712 /* plus1.rom */; }; - 4BE5F85E1C3E1C2500C43F01 /* basic.rom in Resources */ = {isa = PBXBuildFile; fileRef = 4BE5F85C1C3E1C2500C43F01 /* basic.rom */; }; - 4BE5F85F1C3E1C2500C43F01 /* os.rom in Resources */ = {isa = PBXBuildFile; fileRef = 4BE5F85D1C3E1C2500C43F01 /* os.rom */; }; + 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -393,16 +381,6 @@ 4B886FF11D03B517004291C3 /* Vic20.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Vic20.hpp; path = "Vic-20/Vic20.hpp"; sourceTree = ""; }; 4B886FF31D03B61E004291C3 /* CSVic20.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVic20.h; sourceTree = ""; }; 4B886FF41D03B61E004291C3 /* CSVic20.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSVic20.mm; sourceTree = ""; }; - 4B886FF81D03BFEC004291C3 /* basic.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = basic.bin; sourceTree = ""; }; - 4B886FF91D03BFEC004291C3 /* characters-danish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-danish.bin"; sourceTree = ""; }; - 4B886FFA1D03BFEC004291C3 /* characters-english.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-english.bin"; sourceTree = ""; }; - 4B886FFB1D03BFEC004291C3 /* characters-japanese.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-japanese.bin"; sourceTree = ""; }; - 4B886FFC1D03BFEC004291C3 /* characters-swedish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "characters-swedish.bin"; sourceTree = ""; }; - 4B886FFD1D03BFEC004291C3 /* kernel-danish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-danish.bin"; sourceTree = ""; }; - 4B886FFE1D03BFEC004291C3 /* kernel-japanese.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-japanese.bin"; sourceTree = ""; }; - 4B886FFF1D03BFEC004291C3 /* kernel-ntsc.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-ntsc.bin"; sourceTree = ""; }; - 4B8870001D03BFEC004291C3 /* kernel-pal.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-pal.bin"; sourceTree = ""; }; - 4B8870011D03BFEC004291C3 /* kernel-swedish.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "kernel-swedish.bin"; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyCodes.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; @@ -706,9 +684,7 @@ 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FIRFilter.cpp; sourceTree = ""; }; 4BC76E681C98E31700E6EF73 /* FIRFilter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FIRFilter.hpp; sourceTree = ""; }; 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; - 4BCB70B31C947DDC005B1712 /* plus1.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = plus1.rom; sourceTree = ""; }; - 4BE5F85C1C3E1C2500C43F01 /* basic.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = basic.rom; sourceTree = ""; }; - 4BE5F85D1C3E1C2500C43F01 /* os.rom */ = {isa = PBXFileReference; lastKnownFileType = file; path = os.rom; sourceTree = ""; }; + 4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -891,23 +867,6 @@ name = "Vic-20"; sourceTree = ""; }; - 4B886FF71D03BFEC004291C3 /* Vic20 */ = { - isa = PBXGroup; - children = ( - 4B886FF81D03BFEC004291C3 /* basic.bin */, - 4B886FF91D03BFEC004291C3 /* characters-danish.bin */, - 4B886FFA1D03BFEC004291C3 /* characters-english.bin */, - 4B886FFB1D03BFEC004291C3 /* characters-japanese.bin */, - 4B886FFC1D03BFEC004291C3 /* characters-swedish.bin */, - 4B886FFD1D03BFEC004291C3 /* kernel-danish.bin */, - 4B886FFE1D03BFEC004291C3 /* kernel-japanese.bin */, - 4B886FFF1D03BFEC004291C3 /* kernel-ntsc.bin */, - 4B8870001D03BFEC004291C3 /* kernel-pal.bin */, - 4B8870011D03BFEC004291C3 /* kernel-swedish.bin */, - ); - path = Vic20; - sourceTree = ""; - }; 4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */ = { isa = PBXGroup; children = ( @@ -1302,22 +1261,11 @@ 4BE5F85A1C3E1C2500C43F01 /* Resources */ = { isa = PBXGroup; children = ( - 4B886FF71D03BFEC004291C3 /* Vic20 */, - 4BE5F85B1C3E1C2500C43F01 /* Electron */, + 4BC9DF441D044FCA00F44158 /* ROMImages */, ); path = Resources; sourceTree = ""; }; - 4BE5F85B1C3E1C2500C43F01 /* Electron */ = { - isa = PBXGroup; - children = ( - 4BCB70B31C947DDC005B1712 /* plus1.rom */, - 4BE5F85C1C3E1C2500C43F01 /* basic.rom */, - 4BE5F85D1C3E1C2500C43F01 /* os.rom */, - ); - path = Electron; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1427,24 +1375,12 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4B8870021D03BFEC004291C3 /* basic.bin in Resources */, 4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */, - 4B88700B1D03BFEC004291C3 /* kernel-swedish.bin in Resources */, 4BB73EA91B587A5100552FC2 /* Assets.xcassets in Resources */, - 4BE5F85F1C3E1C2500C43F01 /* os.rom in Resources */, - 4BCB70B41C947DDC005B1712 /* plus1.rom in Resources */, - 4B8870071D03BFEC004291C3 /* kernel-danish.bin in Resources */, 4BB73EA71B587A5100552FC2 /* Atari2600Document.xib in Resources */, - 4B8870031D03BFEC004291C3 /* characters-danish.bin in Resources */, 4B73C71D1D036C030074D992 /* Vic20Document.xib in Resources */, - 4B8870041D03BFEC004291C3 /* characters-english.bin in Resources */, - 4B88700A1D03BFEC004291C3 /* kernel-pal.bin in Resources */, 4BB73EAC1B587A5100552FC2 /* MainMenu.xib in Resources */, - 4B8870051D03BFEC004291C3 /* characters-japanese.bin in Resources */, - 4B8870091D03BFEC004291C3 /* kernel-ntsc.bin in Resources */, - 4B8870061D03BFEC004291C3 /* characters-swedish.bin in Resources */, - 4BE5F85E1C3E1C2500C43F01 /* basic.rom in Resources */, - 4B8870081D03BFEC004291C3 /* kernel-japanese.bin in Resources */, + 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift index 9f73af395..6b523d636 100644 --- a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift @@ -20,16 +20,20 @@ class ElectronDocument: MachineDocument { return NSSize(width: 11.0, height: 10.0) } + private func rom(name: String) -> NSData? { + return dataForResource(name, ofType: "rom", inDirectory: "ROMImages/Electron") + } + override func windowControllerDidLoadNib(aController: NSWindowController) { super.windowControllerDidLoadNib(aController) self.intendedCyclesPerSecond = 2000000 - if let osPath = NSBundle.mainBundle().pathForResource("os", ofType: "rom") { - self.electron.setOSROM(NSData(contentsOfFile: osPath)!) + if let os = rom("os") { + self.electron.setOSROM(os) } - if let basicPath = NSBundle.mainBundle().pathForResource("basic", ofType: "rom") { - self.electron.setBASICROM(NSData(contentsOfFile: basicPath)!) + if let basic = rom("basic") { + self.electron.setBASICROM(basic) } establishStoredOptions() @@ -57,8 +61,8 @@ class ElectronDocument: MachineDocument { } override func readFromData(data: NSData, ofType typeName: String) throws { - if let plus1Path = NSBundle.mainBundle().pathForResource("plus1", ofType: "rom") { - electron.setROM(NSData(contentsOfFile: plus1Path)!, slot: 12) + if let plus1ROM = rom("plus1") { + electron.setROM(plus1ROM, slot: 12) } electron.setROM(data, slot: 15) } diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 3f8e8ec60..24c757c56 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -95,6 +95,15 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe lastTime = time } + // MARK: Utilities for children + func dataForResource(name : String, ofType type: String, inDirectory directory: String) -> NSData? { + if let path = NSBundle.mainBundle().pathForResource(name, ofType: type, inDirectory: directory) { + return NSData(contentsOfFile: path) + } + + return nil + } + // MARK: CSOpenGLViewDelegate func runForNumberOfCycles(numberOfCycles: Int32) { if actionLock.tryLock() { diff --git a/ROMImages/Electron/readme.txt b/ROMImages/Electron/readme.txt new file mode 100644 index 000000000..8e81ed5e6 --- /dev/null +++ b/ROMImages/Electron/readme.txt @@ -0,0 +1,16 @@ +ROM files would ordinarily go here; the copyright status of these is uncertain so they have not been included in this repository. + +Expected files: + +basic.rom +os.rom +plus1.rom + +Likely to be desired in the future: + +adfs.rom +ADFS-E00_1.rom +ADFS-E00_2.rom +DFSE00r3.rom +ElectronExpansionRomPresAP2-v1.23.rom +os300.rom diff --git a/ROMImages/Vic20/readme.txt b/ROMImages/Vic20/readme.txt new file mode 100644 index 000000000..360af257b --- /dev/null +++ b/ROMImages/Vic20/readme.txt @@ -0,0 +1,17 @@ +ROM files would ordinarily go here; the copyright status of these is uncertain so they have not been included in this repository. + +Expected files: + +basic.bin +characters-english.bin +kernel-ntsc.rom + +Likely to be desired in the future: + +characters-danish.bin +characters-japanese.bin +characters-swedish.bin +kernel-danish.bin +kernel-japanese.bin +kernel-pal.bin +kernel-swedish.bin \ No newline at end of file From 8052ce9223e7dccf30b376c65a7d8f94af74921e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 08:53:05 -0400 Subject: [PATCH 07/66] System ROMs are now supplied to the Vic-20 wrapper, though they stop there. I also factored key forwarding out of the ElectronDocument and into the superclass, depending upon the child conforming to CSKeyboardMachine. --- .../Clock Signal.xcodeproj/project.pbxproj | 2 ++ .../ClockSignal-Bridging-Header.h | 1 + .../Documents/ElectronDocument.swift | 27 ++------------- .../Documents/MachineDocument.swift | 33 ++++++++++++++++--- .../Documents/Vic20Document.swift | 11 +++++++ .../Mac/Clock Signal/Wrappers/CSElectron.h | 6 ++-- .../Clock Signal/Wrappers/CSKeyboardMachine.h | 14 ++++++++ .../Mac/Clock Signal/Wrappers/CSVic20.h | 8 ++++- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 18 ++++++++++ 9 files changed, 85 insertions(+), 35 deletions(-) create mode 100644 OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 6d16df570..1bf89a8f8 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -685,6 +685,7 @@ 4BC76E681C98E31700E6EF73 /* FIRFilter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FIRFilter.hpp; sourceTree = ""; }; 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = ""; }; + 4BC9DF461D04565200F44158 /* CSKeyboardMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSKeyboardMachine.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -796,6 +797,7 @@ 4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */, 4B55CE521C3B7ABF0093A61B /* CSElectron.h */, 4B55CE531C3B7ABF0093A61B /* CSElectron.mm */, + 4BC9DF461D04565200F44158 /* CSKeyboardMachine.h */, 4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */, 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */, 4B55CE4F1C3B78A80093A61B /* CSMachine+Subclassing.h */, diff --git a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h index c87782a47..62a210db7 100644 --- a/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h +++ b/OSBindings/Mac/Clock Signal/ClockSignal-Bridging-Header.h @@ -3,6 +3,7 @@ // #import "CSMachine.h" +#import "CSKeyboardMachine.h" #import "CSAtari2600.h" #import "CSElectron.h" diff --git a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift index 6b523d636..c9cfef538 100644 --- a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift @@ -21,7 +21,7 @@ class ElectronDocument: MachineDocument { } private func rom(name: String) -> NSData? { - return dataForResource(name, ofType: "rom", inDirectory: "ROMImages/Electron") + return dataForResource(name, ofType: "rom", inDirectory: "ROMImages/Electron") } override func windowControllerDidLoadNib(aController: NSWindowController) { @@ -29,10 +29,8 @@ class ElectronDocument: MachineDocument { self.intendedCyclesPerSecond = 2000000 - if let os = rom("os") { + if let os = rom("os"), basic = rom("basic") { self.electron.setOSROM(os) - } - if let basic = rom("basic") { self.electron.setBASICROM(basic) } @@ -97,25 +95,4 @@ class ElectronDocument: MachineDocument { electron.useTelevisionOutput = (displayType == 1) self.displayTypeButton.selectItemAtIndex(displayType) } - - // MARK: NSWindowDelegate - func windowDidResignKey(notification: NSNotification) { - electron.clearAllKeys() - } - - // MARK: CSOpenGLViewResponderDelegate - override func keyDown(event: NSEvent) { - electron.setKey(event.keyCode, isPressed: true) - } - - override func keyUp(event: NSEvent) { - electron.setKey(event.keyCode, isPressed: false) - } - - override func flagsChanged(newModifiers: NSEvent) { - electron.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.ShiftKeyMask)) - electron.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.ControlKeyMask)) - electron.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.CommandKeyMask)) - electron.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.AlternateKeyMask)) - } } diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 24c757c56..908c49cd5 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -119,13 +119,36 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe } } - // MARK: CSOpenGLViewResponderDelegate - func keyDown(event: NSEvent) {} - func keyUp(event: NSEvent) {} - func flagsChanged(newModifiers: NSEvent) {} - // MARK: NSDocument overrides override func dataOfType(typeName: String) throws -> NSData { throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil) } + + // MARK: Key forwarding + private func withKeyboardMachine(action: (CSKeyboardMachine) -> ()) { + if let keyboardMachine = self.machine() as? CSKeyboardMachine { + action(keyboardMachine) + } + } + + func windowDidResignKey(notification: NSNotification) { + self.withKeyboardMachine { $0.clearAllKeys() } + } + + func keyDown(event: NSEvent) { + self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: true) } + } + + func keyUp(event: NSEvent) { + self.withKeyboardMachine { $0.setKey(event.keyCode, isPressed: false) } + } + + func flagsChanged(newModifiers: NSEvent) { + self.withKeyboardMachine { + $0.setKey(VK_Shift, isPressed: newModifiers.modifierFlags.contains(.ShiftKeyMask)) + $0.setKey(VK_Control, isPressed: newModifiers.modifierFlags.contains(.ControlKeyMask)) + $0.setKey(VK_Command, isPressed: newModifiers.modifierFlags.contains(.CommandKeyMask)) + $0.setKey(VK_Option, isPressed: newModifiers.modifierFlags.contains(.AlternateKeyMask)) + } + } } diff --git a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift index 0741a6ed3..33c73a80a 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift @@ -20,6 +20,12 @@ class Vic20Document: MachineDocument { super.init() self.intendedCyclesPerSecond = 1022727 // TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt + + if let kernel = rom("kernel"), basic = rom("basic"), characters = rom("characters-english") { + vic20.setKernelROM(kernel) + vic20.setBASICROM(basic) + vic20.setCharactersROM(characters) + } } override class func autosavesInPlace() -> Bool { @@ -30,6 +36,11 @@ class Vic20Document: MachineDocument { return "Vic20Document" } + // MARK: machine setup + private func rom(name: String) -> NSData? { + return dataForResource(name, ofType: "bin", inDirectory: "ROMImages/Vic20") + } + override func readFromData(data: NSData, ofType typeName: String) throws { print("\(data.length)") } diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h index 04d8e51ac..7f546434f 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h @@ -8,17 +8,15 @@ #include "CSMachine.h" #import "KeyCodes.h" +#import "CSKeyboardMachine.h" -@interface CSElectron : CSMachine +@interface CSElectron : CSMachine - (void)setOSROM:(nonnull NSData *)rom; - (void)setBASICROM:(nonnull NSData *)rom; - (void)setROM:(nonnull NSData *)rom slot:(int)slot; - (BOOL)openUEFAtURL:(nonnull NSURL *)URL; -- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; -- (void)clearAllKeys; - @property (nonatomic, assign) BOOL useFastLoadingHack; @property (nonatomic, assign) BOOL useTelevisionOutput; diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h b/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h new file mode 100644 index 000000000..bba3b77b7 --- /dev/null +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h @@ -0,0 +1,14 @@ +// +// CSKeyboardMachine.h +// Clock Signal +// +// Created by Thomas Harte on 05/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +@protocol CSKeyboardMachine + +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; +- (void)clearAllKeys; + +@end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h index 039e6afb0..25d68ea8c 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h @@ -7,7 +7,13 @@ // #import "CSMachine.h" +#import "CSKeyboardMachine.h" -@interface CSVic20 : CSMachine +@interface CSVic20 : CSMachine + +- (void)setKernelROM:(nonnull NSData *)rom; +- (void)setBASICROM:(nonnull NSData *)rom; +- (void)setCharactersROM:(nonnull NSData *)rom; +- (void)setROM:(nonnull NSData *)rom address:(uint16_t)address; @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index 6447e5d49..ac49e7fb6 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -18,4 +18,22 @@ return &_vic20; } +- (void)setKernelROM:(nonnull NSData *)rom { +} + +- (void)setBASICROM:(nonnull NSData *)rom { +} + +- (void)setCharactersROM:(nonnull NSData *)rom { +} + +- (void)setROM:(nonnull NSData *)rom address:(uint16_t)address { +} + +- (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { +} + +- (void)clearAllKeys { +} + @end From b29b2a5d087dee5e2ec7ed3440ab604aaf654984 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 09:01:32 -0400 Subject: [PATCH 08/66] Added forwarding of a loaded PRG from the Swift document to the wrapper. So I think that possibly completes the Swift side of things? --- OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift | 2 +- OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h | 2 +- OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift index 33c73a80a..3f8018db3 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift @@ -42,6 +42,6 @@ class Vic20Document: MachineDocument { } override func readFromData(data: NSData, ofType typeName: String) throws { - print("\(data.length)") + vic20.setPRG(data) } } diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h index 25d68ea8c..6e5446a40 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h @@ -14,6 +14,6 @@ - (void)setKernelROM:(nonnull NSData *)rom; - (void)setBASICROM:(nonnull NSData *)rom; - (void)setCharactersROM:(nonnull NSData *)rom; -- (void)setROM:(nonnull NSData *)rom address:(uint16_t)address; +- (void)setPRG:(nonnull NSData *)rom; @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index ac49e7fb6..570ccb0a2 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -27,7 +27,7 @@ - (void)setCharactersROM:(nonnull NSData *)rom { } -- (void)setROM:(nonnull NSData *)rom address:(uint16_t)address { +- (void)setPRG:(nonnull NSData *)rom address:(uint16_t)address { } - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { From 12243c40ad9a09b76a037a9cf95fe734c570179b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 09:06:59 -0400 Subject: [PATCH 09/66] Kicking the ball a little further down the road, ROMs and PRGs now reach the actual emulated machine. --- Machines/Vic-20/Vic20.cpp | 8 ++++++++ Machines/Vic-20/Vic20.hpp | 10 ++++++++++ OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h | 2 +- OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm | 10 +++++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index e3e3b5e2b..008fcf955 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -14,3 +14,11 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { return 1; } + +void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data) +{ +} + +void Machine::add_prg(size_t length, const uint8_t *data) +{ +} diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 03d79654b..e7a0ee4d0 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -14,8 +14,18 @@ namespace Vic20 { +enum ROMSlot { + ROMSlotKernel, + ROMSlotBASIC, + ROMSlotCharacters, +}; + class Machine: public CPU6502::Processor, public CRTMachine::Machine { public: + + void set_rom(ROMSlot slot, size_t length, const uint8_t *data); + void add_prg(size_t length, const uint8_t *data); + // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); void synchronise() {} diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h index 6e5446a40..3a8339dd6 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.h @@ -14,6 +14,6 @@ - (void)setKernelROM:(nonnull NSData *)rom; - (void)setBASICROM:(nonnull NSData *)rom; - (void)setCharactersROM:(nonnull NSData *)rom; -- (void)setPRG:(nonnull NSData *)rom; +- (void)setPRG:(nonnull NSData *)prg; @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index 570ccb0a2..cee3469d3 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -18,16 +18,24 @@ return &_vic20; } +- (void)setROM:(nonnull NSData *)rom slot:(Vic20::ROMSlot)slot { + _vic20.set_rom(slot, rom.length, (const uint8_t *)rom.bytes); +} + - (void)setKernelROM:(nonnull NSData *)rom { + [self setROM:rom slot:Vic20::ROMSlotKernel]; } - (void)setBASICROM:(nonnull NSData *)rom { + [self setROM:rom slot:Vic20::ROMSlotBASIC]; } - (void)setCharactersROM:(nonnull NSData *)rom { + [self setROM:rom slot:Vic20::ROMSlotCharacters]; } -- (void)setPRG:(nonnull NSData *)rom address:(uint16_t)address { +- (void)setPRG:(nonnull NSData *)prg { + _vic20.add_prg(prg.length, (const uint8_t *)prg.bytes); } - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { From f922d38ed24e51e85d7678b6053c15ed7fa18664 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 10:51:07 -0400 Subject: [PATCH 10/66] The Vic now captures the ROMs sent to it and has just enough infrastructure to get to a black screen. Progress! --- Components/6560/6560.cpp | 21 +++++++++++++ Components/6560/6560.hpp | 27 ++++++++++++++++ Machines/Vic-20/Vic20.cpp | 23 ++++++++++++++ Machines/Vic-20/Vic20.hpp | 13 ++++++-- .../Clock Signal.xcodeproj/project.pbxproj | 31 +++++++++++++++++++ 5 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 Components/6560/6560.cpp create mode 100644 Components/6560/6560.hpp diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp new file mode 100644 index 000000000..7573de2d9 --- /dev/null +++ b/Components/6560/6560.cpp @@ -0,0 +1,21 @@ +// +// 6560.cpp +// Clock Signal +// +// Created by Thomas Harte on 05/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "6560.hpp" + +using namespace MOS; + +MOS6560::MOS6560() : + _crt(new Outputs::CRT::CRT(65, 1, Outputs::CRT::DisplayType::NTSC60, 1)) +{ + _crt->set_rgb_sampling_function( + "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" + "{" + "return vec3(1.0);" + "}"); +} diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp new file mode 100644 index 000000000..60d71395e --- /dev/null +++ b/Components/6560/6560.hpp @@ -0,0 +1,27 @@ +// +// 6560.hpp +// Clock Signal +// +// Created by Thomas Harte on 05/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef _560_hpp +#define _560_hpp + +#include "../../Outputs/CRT/CRT.hpp" + +namespace MOS { + +class MOS6560 { + public: + MOS6560(); + Outputs::CRT::CRT *get_crt() { return _crt.get(); } + + private: + std::unique_ptr _crt; +}; + +} + +#endif /* _560_hpp */ diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 008fcf955..3997aa193 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -8,15 +8,38 @@ #include "Vic20.hpp" +#include + using namespace Vic20; +Machine::Machine() +{} + unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) { return 1; } +void Machine::setup_output(float aspect_ratio) +{ + _mos6560 = std::unique_ptr(new MOS::MOS6560()); +} + void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data) { + uint8_t *target = nullptr; + switch(slot) + { + case ROMSlotKernel: target = _kernelROM; break; + case ROMSlotCharacters: target = _characterROM; break; + case ROMSlotBASIC: target = _basicROM; break; + } + + if(target) + { + size_t length_to_copy = std::max((size_t)0x1000, length); + memcpy(target, data, length_to_copy); + } } void Machine::add_prg(size_t length, const uint8_t *data) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index e7a0ee4d0..8c0bc00bb 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -10,6 +10,7 @@ #define Vic20_hpp #include "../../Processors/6502/CPU6502.hpp" +#include "../../Components/6560/6560.hpp" #include "../CRTMachine.hpp" namespace Vic20 { @@ -22,6 +23,7 @@ enum ROMSlot { class Machine: public CPU6502::Processor, public CRTMachine::Machine { public: + Machine(); void set_rom(ROMSlot slot, size_t length, const uint8_t *data); void add_prg(size_t length, const uint8_t *data); @@ -31,11 +33,18 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { void synchronise() {} // to satisfy CRTMachine::Machine - virtual void setup_output(float aspect_ratio) {} + virtual void setup_output(float aspect_ratio); virtual void close_output() {} - virtual Outputs::CRT::CRT *get_crt() { return nullptr; } // TODO + virtual Outputs::CRT::CRT *get_crt() { return _mos6560->get_crt(); } virtual Outputs::Speaker *get_speaker() { return nullptr; } // TODO virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor::run_for_cycles(number_of_cycles); } + + private: + uint8_t _characterROM[0x1000]; + uint8_t _basicROM[0x1000]; + uint8_t _kernelROM[0x1000]; + + std::unique_ptr _mos6560; }; } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 1bf89a8f8..b7b414066 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -316,6 +316,7 @@ 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC76E671C98E31700E6EF73 /* FIRFilter.cpp */; }; 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; }; 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; + 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -686,6 +687,8 @@ 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accelerate.framework; path = System/Library/Frameworks/Accelerate.framework; sourceTree = SDKROOT; }; 4BC9DF441D044FCA00F44158 /* ROMImages */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ROMImages; path = ../../../../ROMImages; sourceTree = ""; }; 4BC9DF461D04565200F44158 /* CSKeyboardMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSKeyboardMachine.h; sourceTree = ""; }; + 4BC9DF4D1D04691600F44158 /* 6560.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6560.cpp; sourceTree = ""; }; + 4BC9DF4E1D04691600F44158 /* 6560.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6560.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1148,6 +1151,7 @@ 4BB73EA01B587A5100552FC2 /* Clock Signal */, 4BB73EB51B587A5100552FC2 /* Clock SignalTests */, 4BB73EC01B587A5100552FC2 /* Clock SignalUITests */, + 4BC9DF4A1D04691600F44158 /* Components */, 4BB73EDC1B587CA500552FC2 /* Machines */, 4B366DFD1B5C165F0026627B /* Outputs */, 4BB73EDD1B587CA500552FC2 /* Processors */, @@ -1260,6 +1264,32 @@ path = Shaders; sourceTree = ""; }; + 4BC9DF4A1D04691600F44158 /* Components */ = { + isa = PBXGroup; + children = ( + 4BC9DF4B1D04691600F44158 /* 6522 */, + 4BC9DF4C1D04691600F44158 /* 6560 */, + ); + name = Components; + path = ../../Components; + sourceTree = ""; + }; + 4BC9DF4B1D04691600F44158 /* 6522 */ = { + isa = PBXGroup; + children = ( + ); + path = 6522; + sourceTree = ""; + }; + 4BC9DF4C1D04691600F44158 /* 6560 */ = { + isa = PBXGroup; + children = ( + 4BC9DF4D1D04691600F44158 /* 6560.cpp */, + 4BC9DF4E1D04691600F44158 /* 6560.hpp */, + ); + path = 6560; + sourceTree = ""; + }; 4BE5F85A1C3E1C2500C43F01 /* Resources */ = { isa = PBXGroup; children = ( @@ -1674,6 +1704,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */, 4BBF99151C8FBA6F0075DAFB /* CRTOpenGL.cpp in Sources */, 4B55CE541C3B7ABF0093A61B /* CSElectron.mm in Sources */, 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, From 0b221e773fb544bd1cad95cfafe158269c2399a1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 11:20:05 -0400 Subject: [PATCH 11/66] Fixed ROM naming and sizes, ensured machines without sound outputs don't end up with an audio queue. --- Machines/Vic-20/Vic20.cpp | 11 +++++++---- Machines/Vic-20/Vic20.hpp | 5 +++-- .../Mac/Clock Signal/Documents/MachineDocument.swift | 8 +++++--- .../Mac/Clock Signal/Documents/Vic20Document.swift | 2 +- OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 3997aa193..12566bc36 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -20,6 +20,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin return 1; } +#pragma mark - Setup + void Machine::setup_output(float aspect_ratio) { _mos6560 = std::unique_ptr(new MOS::MOS6560()); @@ -28,16 +30,17 @@ void Machine::setup_output(float aspect_ratio) void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data) { uint8_t *target = nullptr; + size_t max_length = 0x2000; switch(slot) { - case ROMSlotKernel: target = _kernelROM; break; - case ROMSlotCharacters: target = _characterROM; break; - case ROMSlotBASIC: target = _basicROM; break; + case ROMSlotKernel: target = _kernelROM; break; + case ROMSlotCharacters: target = _characterROM; max_length = 0x1000; break; + case ROMSlotBASIC: target = _basicROM; break; } if(target) { - size_t length_to_copy = std::max((size_t)0x1000, length); + size_t length_to_copy = std::min(max_length, length); memcpy(target, data, length_to_copy); } } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 8c0bc00bb..f9eba88ba 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -41,8 +41,9 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { private: uint8_t _characterROM[0x1000]; - uint8_t _basicROM[0x1000]; - uint8_t _kernelROM[0x1000]; + uint8_t _basicROM[0x2000]; + uint8_t _kernelROM[0x2000]; + uint8_t _ram[0x1000]; std::unique_ptr _mos6560; }; diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 908c49cd5..f75a85f77 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -48,9 +48,11 @@ class MachineDocument: NSDocument, CSOpenGLViewDelegate, CSOpenGLViewResponderDe // establish and provide the audio queue, taking advice as to an appropriate sampling rate let maximumSamplingRate = AudioQueue.preferredSamplingRate() let selectedSamplingRate = self.machine().idealSamplingRateFromRange(NSRange(location: 0, length: NSInteger(maximumSamplingRate))) - audioQueue = AudioQueue(samplingRate: Float64(selectedSamplingRate)) - self.machine().audioQueue = self.audioQueue - self.machine().setAudioSamplingRate(selectedSamplingRate) + if selectedSamplingRate > 0 { + audioQueue = AudioQueue(samplingRate: Float64(selectedSamplingRate)) + self.machine().audioQueue = self.audioQueue + self.machine().setAudioSamplingRate(selectedSamplingRate) + } } override func close() { diff --git a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift index 3f8018db3..875e90a08 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Vic20Document.swift @@ -21,7 +21,7 @@ class Vic20Document: MachineDocument { self.intendedCyclesPerSecond = 1022727 // TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt - if let kernel = rom("kernel"), basic = rom("basic"), characters = rom("characters-english") { + if let kernel = rom("kernel-ntsc"), basic = rom("basic"), characters = rom("characters-english") { vic20.setKernelROM(kernel) vic20.setBASICROM(basic) vic20.setCharactersROM(characters) diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm index 3f5cedbef..e3ba9ada8 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm @@ -43,7 +43,7 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate { { return speaker->get_ideal_clock_rate_in_range((int)range.location, (int)(range.location + range.length)); } - return (int)range.location; + return 0; } } From b56482607e7049bfb0299f0114b24b7c0b021676 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 11:44:29 -0400 Subject: [PATCH 12/66] Added just enough that the 6502 should now be operating correctly. --- Machines/Vic-20/Vic20.cpp | 30 +++++++++++++++++++++++++++++- Machines/Vic-20/Vic20.hpp | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 12566bc36..74d0fa12c 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -13,10 +13,38 @@ using namespace Vic20; Machine::Machine() -{} +{ + set_reset_line(true); +} unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) { + set_reset_line(false); + + if(isReadOperation(operation)) + { + uint8_t returnValue = 0xff; + + if(address < sizeof(_ram)) + returnValue &= _ram[address]; + + if(address >= 0x8000 && address < 0x9000) + returnValue &= _characterROM[address&0x0fff]; + + if(address >= 0xc000 && address < 0xe000) + returnValue &= _basicROM[address&0x1fff]; + + if(address >= 0xe000) + returnValue &= _kernelROM[address&0x1fff]; + + *value = returnValue; + } + else + { + if(address < sizeof(_ram)) + _ram[address] = *value; + } + return 1; } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index f9eba88ba..4c6f81416 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -43,7 +43,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { uint8_t _characterROM[0x1000]; uint8_t _basicROM[0x2000]; uint8_t _kernelROM[0x2000]; - uint8_t _ram[0x1000]; + uint8_t _ram[0x2000]; std::unique_ptr _mos6560; }; From 9566c875328b58b28dd68c3a68eda2e425b0ccd1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 12:11:12 -0400 Subject: [PATCH 13/66] Added enough to the machine that the 6560 can now produce output if it wishes. --- Components/6560/6560.cpp | 14 ++++++++++++++ Components/6560/6560.hpp | 5 +++++ Machines/Vic-20/Vic20.cpp | 28 +++++++++++----------------- Machines/Vic-20/Vic20.hpp | 8 ++++++++ 4 files changed, 38 insertions(+), 17 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 7573de2d9..f1fa17ce4 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -19,3 +19,17 @@ MOS6560::MOS6560() : "return vec3(1.0);" "}"); } + +void MOS6560::set_register(int address, uint8_t value) +{ + printf("%02x -> %d\n", value, address); +} + +uint16_t MOS6560::get_address() +{ + return 0; +} + +void MOS6560::set_graphics_value(uint8_t value) +{ +} diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 60d71395e..027e69bfd 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -18,6 +18,11 @@ class MOS6560 { MOS6560(); Outputs::CRT::CRT *get_crt() { return _crt.get(); } + uint16_t get_address(); + void set_graphics_value(uint8_t value); + + void set_register(int address, uint8_t value); + private: std::unique_ptr _crt; }; diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 74d0fa12c..38217047f 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -21,28 +21,22 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { set_reset_line(false); + // run the phase-1 part of this cycle, in which the VIC accesses memory + _mos6560->set_graphics_value(read_memory(_mos6560->get_address())); + + // run the phase-2 part of the cycle, which is whatever the 6502 said it should be if(isReadOperation(operation)) { - uint8_t returnValue = 0xff; - - if(address < sizeof(_ram)) - returnValue &= _ram[address]; - - if(address >= 0x8000 && address < 0x9000) - returnValue &= _characterROM[address&0x0fff]; - - if(address >= 0xc000 && address < 0xe000) - returnValue &= _basicROM[address&0x1fff]; - - if(address >= 0xe000) - returnValue &= _kernelROM[address&0x1fff]; - - *value = returnValue; + *value = read_memory(address); } else { - if(address < sizeof(_ram)) - _ram[address] = *value; + if(address < sizeof(_ram)) _ram[address] = *value; + else if((address&0xfff0) == 0x9000) + { + _mos6560->set_register(address - 0x9000, *value); + } + // TODO: the 6522 } return 1; diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 4c6f81416..1d528977f 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -45,6 +45,14 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { uint8_t _kernelROM[0x2000]; uint8_t _ram[0x2000]; + inline uint8_t read_memory(uint16_t address) { + if(address < sizeof(_ram)) return _ram[address]; + else if(address >= 0x8000 && address < 0x9000) return _characterROM[address&0x0fff]; + else if(address >= 0xc000 && address < 0xe000) return _basicROM[address&0x1fff]; + else if(address >= 0xe000) return _kernelROM[address&0x1fff]; + return 0xff; + } + std::unique_ptr _mos6560; }; From 3be1ce457b59b0dce62753858d820126a36491f4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 14:05:31 -0400 Subject: [PATCH 14/66] Made some attempt at discerning fields. --- Components/6560/6560.cpp | 41 +++++++++++++++++++++++++++++++++++++--- Components/6560/6560.hpp | 5 +++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index f1fa17ce4..be4b4de5f 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -11,7 +11,7 @@ using namespace MOS; MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65, 1, Outputs::CRT::DisplayType::NTSC60, 1)) + _crt(new Outputs::CRT::CRT(65 * 4, 4, Outputs::CRT::DisplayType::NTSC60, 1)) { _crt->set_rgb_sampling_function( "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" @@ -22,12 +22,47 @@ MOS6560::MOS6560() : void MOS6560::set_register(int address, uint8_t value) { - printf("%02x -> %d\n", value, address); + switch(address) + { + case 0x0: + _interlaced = !!(value&0x80); + _first_column_location = value & 0x7f; + break; + + case 0x1: + _first_row_location = value; + break; + + case 0x2: + _number_of_columns = value & 0x7f; + _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x3c00) | ((value & 0x80) << 2)); + break; + + case 0x3: + _number_of_rows = (value >> 1)&0x3f; + _wide_characters = !!(value&0x01); + break; + + case 0x5: + _character_cell_start_address = (uint16_t)((value & 0x0f) << 10); + _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0400) | ((value & 0xf0) << 5)); + break; + + case 0xf: + // TODO: colours + break; + + default: + break; + } + + printf("%02x: %02x\n", address, value); + printf("%04x %04x [%d by %d from %d, %d]\n", _character_cell_start_address, _video_matrix_start_address, _number_of_columns, _number_of_rows, _first_column_location, _first_row_location); } uint16_t MOS6560::get_address() { - return 0; + return 0x1c; } void MOS6560::set_graphics_value(uint8_t value) diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 027e69bfd..eedbf80f9 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -25,6 +25,11 @@ class MOS6560 { private: std::unique_ptr _crt; + + bool _interlaced, _wide_characters; + uint8_t _first_column_location, _first_row_location; + uint8_t _number_of_columns, _number_of_rows; + uint16_t _character_cell_start_address, _video_matrix_start_address; }; } From 2ab21e7a3c45b0fc8b27b14e8e311152ec0d2170 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 16:00:35 -0400 Subject: [PATCH 15/66] Switched to a real (unexpanded) memory map, meaning that nonsense is no longer being supplied to the VIC. --- Machines/Vic-20/Vic20.cpp | 3 ++- Machines/Vic-20/Vic20.hpp | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 38217047f..7d0ab6922 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -31,7 +31,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } else { - if(address < sizeof(_ram)) _ram[address] = *value; + uint8_t *ram = ram_pointer(address); + if(ram) *ram = *value; else if((address&0xfff0) == 0x9000) { _mos6560->set_register(address - 0x9000, *value); diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 1d528977f..2516ada94 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -43,10 +43,21 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { uint8_t _characterROM[0x1000]; uint8_t _basicROM[0x2000]; uint8_t _kernelROM[0x2000]; - uint8_t _ram[0x2000]; + + uint8_t _userBASICMemory[0x0400]; + uint8_t _screenMemory[0x1000]; + uint8_t _colorMemory[0x0200]; + + inline uint8_t *ram_pointer(uint16_t address) { + if(address < sizeof(_userBASICMemory)) return &_userBASICMemory[address]; + if(address >= 0x1000 && address < 0x1200) return &_screenMemory[address&0x0fff]; + if(address >= 0x9400 && address < 0x9600) return &_colorMemory[0x01ff]; + return nullptr; + } inline uint8_t read_memory(uint16_t address) { - if(address < sizeof(_ram)) return _ram[address]; + uint8_t *ram = ram_pointer(address); + if(ram) return *ram; else if(address >= 0x8000 && address < 0x9000) return _characterROM[address&0x0fff]; else if(address >= 0xc000 && address < 0xe000) return _basicROM[address&0x1fff]; else if(address >= 0xe000) return _kernelROM[address&0x1fff]; From 9e9e50edb1f283231d06d6996aba7ef922b53fd1 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 16:28:06 -0400 Subject: [PATCH 16/66] Added guess on how colour memory and the 12-bit bus possibly works. --- Components/6560/6560.cpp | 6 +++--- Components/6560/6560.hpp | 2 +- Machines/Vic-20/Vic20.cpp | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index be4b4de5f..7b8889e6a 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -56,8 +56,8 @@ void MOS6560::set_register(int address, uint8_t value) break; } - printf("%02x: %02x\n", address, value); - printf("%04x %04x [%d by %d from %d, %d]\n", _character_cell_start_address, _video_matrix_start_address, _number_of_columns, _number_of_rows, _first_column_location, _first_row_location); +// printf("%02x: %02x\n", address, value); +// printf("%04x %04x [%d by %d from %d, %d]\n", _character_cell_start_address, _video_matrix_start_address, _number_of_columns, _number_of_rows, _first_column_location, _first_row_location); } uint16_t MOS6560::get_address() @@ -65,6 +65,6 @@ uint16_t MOS6560::get_address() return 0x1c; } -void MOS6560::set_graphics_value(uint8_t value) +void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index eedbf80f9..92dd44f1d 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -19,7 +19,7 @@ class MOS6560 { Outputs::CRT::CRT *get_crt() { return _crt.get(); } uint16_t get_address(); - void set_graphics_value(uint8_t value); + void set_graphics_value(uint8_t value, uint8_t colour_value); void set_register(int address, uint8_t value); diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 7d0ab6922..ed3b72ca6 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -22,7 +22,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin set_reset_line(false); // run the phase-1 part of this cycle, in which the VIC accesses memory - _mos6560->set_graphics_value(read_memory(_mos6560->get_address())); + uint16_t video_address = _mos6560->get_address(); + _mos6560->set_graphics_value(read_memory(video_address), _colorMemory[video_address & 0x01ff]); // run the phase-2 part of the cycle, which is whatever the 6502 said it should be if(isReadOperation(operation)) From 444d3b69b6bd5b65636d6cd2e4e398cd6fa48d66 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 17:06:10 -0400 Subject: [PATCH 17/66] Made some elementary attempt to hit something like the correct states within the VIC. --- Components/6560/6560.cpp | 88 +++++++++++++++++++++++++++++++++++++--- Components/6560/6560.hpp | 10 +++++ 2 files changed, 93 insertions(+), 5 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 7b8889e6a..347e62251 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -10,8 +10,30 @@ using namespace MOS; +/* + 0 - 0000 Black + 1 - 0001 White + 2 - 0010 Red + 3 - 0011 Cyan + 4 - 0100 Purple + 5 - 0101 Green + 6 - 0110 Blue + 7 - 0111 Yellow + + 8 - 1000 Orange + 9 - 1001 Light orange + 10 - 1010 Pink + 11 - 1011 Light cyan + 12 - 1100 Light purple + 13 - 1101 Light green + 14 - 1110 Light blue + 15 - 1111 Light yellow +*/ + MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65 * 4, 4, Outputs::CRT::DisplayType::NTSC60, 1)) + _crt(new Outputs::CRT::CRT(65 * 4, 4, Outputs::CRT::DisplayType::NTSC60, 1)), + _horizontal_counter(0), + _vertical_counter(0) { _crt->set_rgb_sampling_function( "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" @@ -49,22 +71,78 @@ void MOS6560::set_register(int address, uint8_t value) break; case 0xf: - // TODO: colours + _invertedCells = !!((value >> 3)&1); + _borderColour = value & 0x07; + _backgroundColour = value >> 4; break; + // TODO: audio, primarily + default: break; } - -// printf("%02x: %02x\n", address, value); -// printf("%04x %04x [%d by %d from %d, %d]\n", _character_cell_start_address, _video_matrix_start_address, _number_of_columns, _number_of_rows, _first_column_location, _first_row_location); } uint16_t MOS6560::get_address() { + /* + Per http://tinyvga.com/6561 : + + The basic video timing is very simple. For + every character the VIC-I is about to display, it first fetches the + character code and colour, then the character appearance (from the + character generator memory). The character codes are read on every + raster line, thus making every line a "bad line". When the raster + beam is outside of the text window, the videochip reads from $001c for + most time. (Some videochips read from $181c instead.) The address + occasionally varies, but it might also be due to a flaky bus. (By + reading from unconnected address space, such as $9100-$910f, you can + read the data fetched by the videochip on the previous clock cycle.) + */ + + State this_state; + + // random guesses; who knows? + if(_horizontal_counter > 61) this_state = State::ColourBurst; + else if(_horizontal_counter > 57) this_state = State::Sync; + else + { + this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; + } + + _horizontal_counter++; + if(_horizontal_counter == 65) + { + _horizontal_counter = 0; + _vertical_counter++; + _column_counter = -1; + + if(_vertical_counter == 261) + { + _vertical_counter = 0; + _row_counter = -1; + } + + if(_row_counter >= 0) + { + _row_counter++; + if(_row_counter == _number_of_rows*8) _row_counter = -1; + } + else if(_vertical_counter >= _first_row_location * 2) _row_counter = 0; + } + + if(_column_counter >= 0) + { + _column_counter++; + if(_column_counter == _number_of_columns*2) + _column_counter = -1; + } + else if(_horizontal_counter == _first_column_location) _column_counter = 0; + return 0x1c; } void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { + } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 92dd44f1d..f598dde40 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -30,6 +30,16 @@ class MOS6560 { uint8_t _first_column_location, _first_row_location; uint8_t _number_of_columns, _number_of_rows; uint16_t _character_cell_start_address, _video_matrix_start_address; + uint8_t _backgroundColour, _borderColour; + bool _invertedCells; + + int _horizontal_counter, _vertical_counter; + + int _column_counter, _row_counter; + + enum State { + Sync, ColourBurst, Border, Pixels + }; }; } From 79e05a24134fe596d5bb9dce94a452ec264c937e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Jun 2016 18:02:49 -0400 Subject: [PATCH 18/66] Without yet figuring out what vertical sync is meant to do, moved just about far enough forwards to see _something_ that hopefully I can soon discern characters within. --- Components/6560/6560.cpp | 102 ++++++++++++++++++++++++++++++--------- Components/6560/6560.hpp | 9 +++- 2 files changed, 87 insertions(+), 24 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 347e62251..4fc5fa62b 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -38,7 +38,7 @@ MOS6560::MOS6560() : _crt->set_rgb_sampling_function( "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" "{" - "return vec3(1.0);" + "return vec3(texture(sampler, coordinate).r / 15.0);" "}"); } @@ -71,6 +71,11 @@ void MOS6560::set_register(int address, uint8_t value) break; case 0xf: + if(_this_state == State::Border) + { + output_border(_cycles_in_state * 4); + _cycles_in_state = 0; + } _invertedCells = !!((value >> 3)&1); _borderColour = value & 0x07; _backgroundColour = value >> 4; @@ -83,31 +88,21 @@ void MOS6560::set_register(int address, uint8_t value) } } +void MOS6560::output_border(unsigned int number_of_cycles) +{ + uint8_t *colour_pointer = _crt->allocate_write_area(1); + if(colour_pointer) *colour_pointer = _borderColour; + _crt->output_level(number_of_cycles); +} + uint16_t MOS6560::get_address() { - /* - Per http://tinyvga.com/6561 : - - The basic video timing is very simple. For - every character the VIC-I is about to display, it first fetches the - character code and colour, then the character appearance (from the - character generator memory). The character codes are read on every - raster line, thus making every line a "bad line". When the raster - beam is outside of the text window, the videochip reads from $001c for - most time. (Some videochips read from $181c instead.) The address - occasionally varies, but it might also be due to a flaky bus. (By - reading from unconnected address space, such as $9100-$910f, you can - read the data fetched by the videochip on the previous clock cycle.) - */ - - State this_state; - - // random guesses; who knows? - if(_horizontal_counter > 61) this_state = State::ColourBurst; - else if(_horizontal_counter > 57) this_state = State::Sync; + // determine output state; colour burst and sync timing are currently a guess + if(_horizontal_counter > 61) _this_state = State::ColourBurst; + else if(_horizontal_counter > 57) _this_state = State::Sync; else { - this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; + _this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; } _horizontal_counter++; @@ -139,10 +134,71 @@ uint16_t MOS6560::get_address() } else if(_horizontal_counter == _first_column_location) _column_counter = 0; + // update the CRT + if(_this_state != _output_state) + { + switch(_output_state) + { + case State::Sync: _crt->output_sync(_cycles_in_state * 4); break; + case State::ColourBurst: _crt->output_colour_burst(_cycles_in_state * 4, 0, 0); break; + case State::Border: output_border(_cycles_in_state * 4); break; + case State::Pixels: _crt->output_data(_cycles_in_state * 4, 1); break; + } + _output_state = _this_state; + _cycles_in_state = 0; + + pixel_pointer = nullptr; + if(_output_state == State::Pixels) + { + pixel_pointer = _crt->allocate_write_area(260); + } + } + _cycles_in_state++; + + // compute the address + if(_this_state == State::Pixels) + { + /* + Per http://tinyvga.com/6561 : + + The basic video timing is very simple. For + every character the VIC-I is about to display, it first fetches the + character code and colour, then the character appearance (from the + character generator memory). The character codes are read on every + raster line, thus making every line a "bad line". When the raster + beam is outside of the text window, the videochip reads from $001c for + most time. (Some videochips read from $181c instead.) The address + occasionally varies, but it might also be due to a flaky bus. (By + reading from unconnected address space, such as $9100-$910f, you can + read the data fetched by the videochip on the previous clock cycle.) + */ + // TODO: increment this address + if(_column_counter&1) + return _character_cell_start_address + _character_code*8; + else + return _video_matrix_start_address; + } + return 0x1c; } void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { - + if(_this_state == State::Pixels) + { + if(_column_counter&1) + { + // TODO: output proper pixels here + if(pixel_pointer) + { + *pixel_pointer = (uint8_t)rand(); + pixel_pointer++; + } + } + else + { + _character_code = value; + _character_colour = colour_value; + } + } } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index f598dde40..5cb7b3863 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -39,7 +39,14 @@ class MOS6560 { enum State { Sync, ColourBurst, Border, Pixels - }; + } _this_state, _output_state; + unsigned int _cycles_in_state; + + uint8_t _character_code, _character_colour; + + uint8_t *pixel_pointer; + + void output_border(unsigned int number_of_cycles); }; } From 64539a2b245f80b20d6398276eb53a64152da949 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2016 07:35:35 -0400 Subject: [PATCH 19/66] Advanced to having some characters displayed, even though they're obviously very much incorrect and the display is still rolling. --- Components/6560/6560.cpp | 64 +++++++++++++++++++++++++++++---------- Components/6560/6560.hpp | 3 +- Machines/Vic-20/Vic20.hpp | 2 +- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 4fc5fa62b..62a401baf 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -97,14 +97,6 @@ void MOS6560::output_border(unsigned int number_of_cycles) uint16_t MOS6560::get_address() { - // determine output state; colour burst and sync timing are currently a guess - if(_horizontal_counter > 61) _this_state = State::ColourBurst; - else if(_horizontal_counter > 57) _this_state = State::Sync; - else - { - _this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; - } - _horizontal_counter++; if(_horizontal_counter == 65) { @@ -123,16 +115,38 @@ uint16_t MOS6560::get_address() _row_counter++; if(_row_counter == _number_of_rows*8) _row_counter = -1; } - else if(_vertical_counter >= _first_row_location * 2) _row_counter = 0; + else if(_vertical_counter >= _first_row_location * 2) + { + _video_matrix_line_address_counter = _video_matrix_start_address; + _row_counter = 0; + } } if(_column_counter >= 0) { _column_counter++; if(_column_counter == _number_of_columns*2) + { _column_counter = -1; + if((_row_counter&7) == 7) + { + _video_matrix_line_address_counter = _video_matrix_address_counter; + } + } + } + else if(_horizontal_counter == _first_column_location) + { + _column_counter = 0; + _video_matrix_address_counter = _video_matrix_line_address_counter; + } + + // determine output state; colour burst and sync timing are currently a guess + if(_horizontal_counter > 61) _this_state = State::ColourBurst; + else if(_horizontal_counter > 57) _this_state = State::Sync; + else + { + _this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; } - else if(_horizontal_counter == _first_column_location) _column_counter = 0; // update the CRT if(_this_state != _output_state) @@ -172,11 +186,16 @@ uint16_t MOS6560::get_address() reading from unconnected address space, such as $9100-$910f, you can read the data fetched by the videochip on the previous clock cycle.) */ - // TODO: increment this address if(_column_counter&1) - return _character_cell_start_address + _character_code*8; + { + return _character_cell_start_address + (_character_code*8) + (_row_counter&7); + } else - return _video_matrix_start_address; + { + uint16_t result = _video_matrix_address_counter; + _video_matrix_address_counter++; + return result; + } } return 0x1c; @@ -188,15 +207,28 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { if(_column_counter&1) { - // TODO: output proper pixels here + _character_value = value; + if(pixel_pointer) { - *pixel_pointer = (uint8_t)rand(); - pixel_pointer++; + pixel_pointer[0] = ((value >> 7)&1) * 15; + pixel_pointer[1] = ((value >> 6)&1) * 15; + pixel_pointer[2] = ((value >> 5)&1) * 15; + pixel_pointer[3] = ((value >> 4)&1) * 15; + pixel_pointer += 4; } } else { + if(pixel_pointer) + { + pixel_pointer[0] = ((value >> 3)&1) * 15; + pixel_pointer[1] = ((value >> 2)&1) * 15; + pixel_pointer[2] = ((value >> 1)&1) * 15; + pixel_pointer[3] = ((value >> 0)&1) * 15; + pixel_pointer += 4; + } + _character_code = value; _character_colour = colour_value; } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 5cb7b3863..58497ba4f 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -36,13 +36,14 @@ class MOS6560 { int _horizontal_counter, _vertical_counter; int _column_counter, _row_counter; + uint16_t _video_matrix_address_counter, _video_matrix_line_address_counter; enum State { Sync, ColourBurst, Border, Pixels } _this_state, _output_state; unsigned int _cycles_in_state; - uint8_t _character_code, _character_colour; + uint8_t _character_code, _character_colour, _character_value; uint8_t *pixel_pointer; diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 2516ada94..b4af33e4b 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -50,7 +50,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { inline uint8_t *ram_pointer(uint16_t address) { if(address < sizeof(_userBASICMemory)) return &_userBASICMemory[address]; - if(address >= 0x1000 && address < 0x1200) return &_screenMemory[address&0x0fff]; + if(address >= 0x1000 && address < 0x2000) return &_screenMemory[address&0x0fff]; if(address >= 0x9400 && address < 0x9600) return &_colorMemory[0x01ff]; return nullptr; } From 89c87c3e81c65f87d3f2f0fe84333c3e23207a5c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2016 07:47:30 -0400 Subject: [PATCH 20/66] Some major hackiness gives the first line of expected text repeating endlessly (as the end of columns is never reached, as that's back to thinking it's 0x7f); I also don't yet know which actor is supposed to do the '+0x8000' (which probably shouldn't be that but might be a pin on the 6560 indicating what sort of value is being fetched, that effects chip select for the various bits of memory?) --- Components/6560/6560.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 62a401baf..110fe855b 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -188,7 +188,8 @@ uint16_t MOS6560::get_address() */ if(_column_counter&1) { - return _character_cell_start_address + (_character_code*8) + (_row_counter&7); + // TODO: don't add 0x8000. That's a hack. + return 0x8000 + (_character_cell_start_address + (_character_code*8) + (_row_counter&7)); } else { @@ -203,6 +204,10 @@ uint16_t MOS6560::get_address() void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { + // TODO: this isn't correct, as _character_value will be + // accessed second, then output will roll over. Probably it's + // correct (given the delays upstream) to output all 8 on an &1 + // and to adjust the signalling to the CRT above? if(_this_state == State::Pixels) { if(_column_counter&1) @@ -211,10 +216,10 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) if(pixel_pointer) { - pixel_pointer[0] = ((value >> 7)&1) * 15; - pixel_pointer[1] = ((value >> 6)&1) * 15; - pixel_pointer[2] = ((value >> 5)&1) * 15; - pixel_pointer[3] = ((value >> 4)&1) * 15; + pixel_pointer[0] = ((_character_value >> 7)&1) * 15; + pixel_pointer[1] = ((_character_value >> 6)&1) * 15; + pixel_pointer[2] = ((_character_value >> 5)&1) * 15; + pixel_pointer[3] = ((_character_value >> 4)&1) * 15; pixel_pointer += 4; } } @@ -222,10 +227,10 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { if(pixel_pointer) { - pixel_pointer[0] = ((value >> 3)&1) * 15; - pixel_pointer[1] = ((value >> 2)&1) * 15; - pixel_pointer[2] = ((value >> 1)&1) * 15; - pixel_pointer[3] = ((value >> 0)&1) * 15; + pixel_pointer[0] = ((_character_value >> 3)&1) * 15; + pixel_pointer[1] = ((_character_value >> 2)&1) * 15; + pixel_pointer[2] = ((_character_value >> 1)&1) * 15; + pixel_pointer[3] = ((_character_value >> 0)&1) * 15; pixel_pointer += 4; } From e8cb674073cb44190ea7d354e42c40618fa1c9a6 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2016 20:18:24 -0400 Subject: [PATCH 21/66] Made some attempt at colours, at least. --- Components/6560/6560.cpp | 60 +++++++++++++++++++++++++++------------- Components/6560/6560.hpp | 2 +- 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 110fe855b..a4f34c121 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -31,14 +31,20 @@ using namespace MOS; */ MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65 * 4, 4, Outputs::CRT::DisplayType::NTSC60, 1)), + _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YIQ, 65*4, 1, 1)), _horizontal_counter(0), _vertical_counter(0) { - _crt->set_rgb_sampling_function( - "vec3 rgb_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate)" + _crt->set_composite_sampling_function( + "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "{" - "return vec3(texture(sampler, coordinate).r / 15.0);" + "uint c = texture(texID, coordinate).r;" + "float y = 0.75 + (float(c & 8u) / 8.0) * 0.25 * step(1, c);" + + "uint iPhase = c & 7u;" + "float phaseOffset = float(iPhase + 3u) / 7.0;" // TODO: appropriate phaseOffset + + "return mix(step(1, c) * y, step(2, c) * step(mod(phase + phaseOffset, 6.283185308), 3.141592654), amplitude);" "}"); } @@ -70,6 +76,11 @@ void MOS6560::set_register(int address, uint8_t value) _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0400) | ((value & 0xf0) << 5)); break; + case 0xe: + _auxiliary_colour = value >> 4; + // TODO: sound amplitude + break; + case 0xf: if(_this_state == State::Border) { @@ -206,7 +217,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { // TODO: this isn't correct, as _character_value will be // accessed second, then output will roll over. Probably it's - // correct (given the delays upstream) to output all 8 on an &1 + // correct (given the delays upstream) to output all 8 on an &1 // and to adjust the signalling to the CRT above? if(_this_state == State::Pixels) { @@ -216,24 +227,35 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) if(pixel_pointer) { - pixel_pointer[0] = ((_character_value >> 7)&1) * 15; - pixel_pointer[1] = ((_character_value >> 6)&1) * 15; - pixel_pointer[2] = ((_character_value >> 5)&1) * 15; - pixel_pointer[3] = ((_character_value >> 4)&1) * 15; - pixel_pointer += 4; + uint8_t cell_colour = _character_colour & 0x7; + if(!(_character_colour&0x8)) + { + pixel_pointer[0] = ((_character_value >> 7)&1) ? cell_colour : _backgroundColour; + pixel_pointer[1] = ((_character_value >> 6)&1) ? cell_colour : _backgroundColour; + pixel_pointer[2] = ((_character_value >> 5)&1) ? cell_colour : _backgroundColour; + pixel_pointer[3] = ((_character_value >> 4)&1) ? cell_colour : _backgroundColour; + pixel_pointer[4] = ((_character_value >> 3)&1) ? cell_colour : _backgroundColour; + pixel_pointer[5] = ((_character_value >> 2)&1) ? cell_colour : _backgroundColour; + pixel_pointer[6] = ((_character_value >> 1)&1) ? cell_colour : _backgroundColour; + pixel_pointer[7] = ((_character_value >> 0)&1) ? cell_colour : _backgroundColour; + } + else + { + uint8_t colours[4] = {_backgroundColour, _borderColour, cell_colour, _auxiliary_colour}; + pixel_pointer[0] = + pixel_pointer[1] = colours[(_character_value >> 6)&3]; + pixel_pointer[2] = + pixel_pointer[3] = colours[(_character_value >> 4)&3]; + pixel_pointer[4] = + pixel_pointer[5] = colours[(_character_value >> 2)&3]; + pixel_pointer[6] = + pixel_pointer[7] = colours[(_character_value >> 0)&3]; + } + pixel_pointer += 8; } } else { - if(pixel_pointer) - { - pixel_pointer[0] = ((_character_value >> 3)&1) * 15; - pixel_pointer[1] = ((_character_value >> 2)&1) * 15; - pixel_pointer[2] = ((_character_value >> 1)&1) * 15; - pixel_pointer[3] = ((_character_value >> 0)&1) * 15; - pixel_pointer += 4; - } - _character_code = value; _character_colour = colour_value; } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 58497ba4f..554ea8b7a 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -30,7 +30,7 @@ class MOS6560 { uint8_t _first_column_location, _first_row_location; uint8_t _number_of_columns, _number_of_rows; uint16_t _character_cell_start_address, _video_matrix_start_address; - uint8_t _backgroundColour, _borderColour; + uint8_t _backgroundColour, _borderColour, _auxiliary_colour; bool _invertedCells; int _horizontal_counter, _vertical_counter; From c7c55528e2658328bc49cd81d3c1ed1090c3472d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2016 20:29:39 -0400 Subject: [PATCH 22/66] Realised that registers appear also to be readable. --- Components/6560/6560.cpp | 7 +++++++ Components/6560/6560.hpp | 3 +++ Machines/Vic-20/Vic20.cpp | 4 ++++ Machines/Vic-20/Vic20.hpp | 4 ++-- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index a4f34c121..9781f5657 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -50,6 +50,7 @@ MOS6560::MOS6560() : void MOS6560::set_register(int address, uint8_t value) { + _registers[address] = value; switch(address) { case 0x0: @@ -99,6 +100,12 @@ void MOS6560::set_register(int address, uint8_t value) } } +uint8_t MOS6560::get_register(int address) +{ + return _registers[address]; +} + + void MOS6560::output_border(unsigned int number_of_cycles) { uint8_t *colour_pointer = _crt->allocate_write_area(1); diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 554ea8b7a..21a7da4f3 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -22,6 +22,7 @@ class MOS6560 { void set_graphics_value(uint8_t value, uint8_t colour_value); void set_register(int address, uint8_t value); + uint8_t get_register(int address); private: std::unique_ptr _crt; @@ -47,6 +48,8 @@ class MOS6560 { uint8_t *pixel_pointer; + uint8_t _registers[16]; + void output_border(unsigned int number_of_cycles); }; diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index ed3b72ca6..249d16cd2 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -29,6 +29,10 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin if(isReadOperation(operation)) { *value = read_memory(address); + if((address&0xfff0) == 0x9000) + { + *value = _mos6560->get_register(address - 0x9000); + } } else { diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index b4af33e4b..460355d8d 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -46,12 +46,12 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { uint8_t _userBASICMemory[0x0400]; uint8_t _screenMemory[0x1000]; - uint8_t _colorMemory[0x0200]; + uint8_t _colorMemory[0x0400]; inline uint8_t *ram_pointer(uint16_t address) { if(address < sizeof(_userBASICMemory)) return &_userBASICMemory[address]; if(address >= 0x1000 && address < 0x2000) return &_screenMemory[address&0x0fff]; - if(address >= 0x9400 && address < 0x9600) return &_colorMemory[0x01ff]; + if(address >= 0x9400 && address < 0x9800) return &_colorMemory[0x03ff]; // TODO: make this 4-bit return nullptr; } From ca23e2e10a708a178a61585960019329fddf20dc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2016 20:33:06 -0400 Subject: [PATCH 23/66] This now proceeds to an ostensibly working basic prompt. Colours are wrong, 6560 is probably very wrong, 6522 is still absent. Hence no cursor. --- Components/6560/6560.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 9781f5657..db1a9adaa 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -133,7 +133,7 @@ uint16_t MOS6560::get_address() _row_counter++; if(_row_counter == _number_of_rows*8) _row_counter = -1; } - else if(_vertical_counter >= _first_row_location * 2) + else if(_vertical_counter == _first_row_location * 2) { _video_matrix_line_address_counter = _video_matrix_start_address; _row_counter = 0; From 6522530e1c66798c93a8f1589d8c6987b1943f66 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Jun 2016 21:56:02 -0400 Subject: [PATCH 24/66] Actually, I'm dithering over whether the 6522 should be an ordinary class or a curiously-recurring template. But it'll need a file, definitely. --- Components/6522/6522.cpp | 24 +++++++++++++++++ Components/6522/6522.hpp | 26 +++++++++++++++++++ Components/6560/6560.cpp | 18 ++++++++++--- .../Clock Signal.xcodeproj/project.pbxproj | 6 +++++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 Components/6522/6522.cpp create mode 100644 Components/6522/6522.hpp diff --git a/Components/6522/6522.cpp b/Components/6522/6522.cpp new file mode 100644 index 000000000..2e302b645 --- /dev/null +++ b/Components/6522/6522.cpp @@ -0,0 +1,24 @@ +// +// 6522.cpp +// Clock Signal +// +// Created by Thomas Harte on 06/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "6522.hpp" + +using namespace MOS; + +MOS6522::MOS6522() +{ +} + +void MOS6522::set_register(int address, uint8_t value) +{ +} + +uint8_t MOS6522::get_register(int address) +{ + return 0xff; +} diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp new file mode 100644 index 000000000..834c58e49 --- /dev/null +++ b/Components/6522/6522.hpp @@ -0,0 +1,26 @@ +// +// 6522.hpp +// Clock Signal +// +// Created by Thomas Harte on 06/06/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#ifndef _522_hpp +#define _522_hpp + +#include + +namespace MOS { + +class MOS6522 { + public: + MOS6522(); + + void set_register(int address, uint8_t value); + uint8_t get_register(int address); +}; + +} + +#endif /* _522_hpp */ diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index db1a9adaa..11c48b40f 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -30,8 +30,20 @@ using namespace MOS; 15 - 1111 Light yellow */ +/* + 0 -> green + 1 -> green + 2 -> browny yellow + 3 -> browny red + 4 -> purple + 5 -> purple + 6 -> cyan + 7 -> green + 8 -> green +*/ + MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YIQ, 65*4, 1, 1)), + _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YIQ, 65*4, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists _horizontal_counter(0), _vertical_counter(0) { @@ -41,8 +53,8 @@ MOS6560::MOS6560() : "uint c = texture(texID, coordinate).r;" "float y = 0.75 + (float(c & 8u) / 8.0) * 0.25 * step(1, c);" - "uint iPhase = c & 7u;" - "float phaseOffset = float(iPhase + 3u) / 7.0;" // TODO: appropriate phaseOffset + "uint iPhase = 8u;" + "float phaseOffset = 6.283185308 * (float(iPhase)) / 7.0;" // TODO: appropriate phaseOffset "return mix(step(1, c) * y, step(2, c) * step(mod(phase + phaseOffset, 6.283185308), 3.141592654), amplitude);" "}"); diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index b7b414066..963e8afcc 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -317,6 +317,7 @@ 4BC76E6B1C98F43700E6EF73 /* Accelerate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BC76E6A1C98F43700E6EF73 /* Accelerate.framework */; }; 4BC9DF451D044FCA00F44158 /* ROMImages in Resources */ = {isa = PBXBuildFile; fileRef = 4BC9DF441D044FCA00F44158 /* ROMImages */; }; 4BC9DF4F1D04691600F44158 /* 6560.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BC9DF4D1D04691600F44158 /* 6560.cpp */; }; + 4BCA98C31D065CA20062F44C /* 6522.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BCA98C11D065CA20062F44C /* 6522.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -689,6 +690,8 @@ 4BC9DF461D04565200F44158 /* CSKeyboardMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSKeyboardMachine.h; sourceTree = ""; }; 4BC9DF4D1D04691600F44158 /* 6560.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6560.cpp; sourceTree = ""; }; 4BC9DF4E1D04691600F44158 /* 6560.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6560.hpp; sourceTree = ""; }; + 4BCA98C11D065CA20062F44C /* 6522.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = 6522.cpp; sourceTree = ""; }; + 4BCA98C21D065CA20062F44C /* 6522.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = 6522.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1277,6 +1280,8 @@ 4BC9DF4B1D04691600F44158 /* 6522 */ = { isa = PBXGroup; children = ( + 4BCA98C11D065CA20062F44C /* 6522.cpp */, + 4BCA98C21D065CA20062F44C /* 6522.hpp */, ); path = 6522; sourceTree = ""; @@ -1720,6 +1725,7 @@ 4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */, 4BC76E691C98E31700E6EF73 /* FIRFilter.cpp in Sources */, 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, + 4BCA98C31D065CA20062F44C /* 6522.cpp in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, 4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */, 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */, From 26ab96868ab3abf29448ddc2647acff2420f310b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 7 Jun 2016 19:15:18 -0400 Subject: [PATCH 25/66] Decided to turn the 6522 into a template, since it's a per-cycle thing with variable behaviour. Added appropriate memory map callouts to hit the two in the Vic. Though they don't yet do anything. --- Components/6522/6522.cpp | 12 ------------ Components/6522/6522.hpp | 14 ++++++++++---- Components/6560/6560.cpp | 2 +- Machines/Vic-20/Vic20.cpp | 17 +++++++++++++++++ Machines/Vic-20/Vic20.hpp | 9 +++++++++ 5 files changed, 37 insertions(+), 17 deletions(-) diff --git a/Components/6522/6522.cpp b/Components/6522/6522.cpp index 2e302b645..412cf4791 100644 --- a/Components/6522/6522.cpp +++ b/Components/6522/6522.cpp @@ -10,15 +10,3 @@ using namespace MOS; -MOS6522::MOS6522() -{ -} - -void MOS6522::set_register(int address, uint8_t value) -{ -} - -uint8_t MOS6522::get_register(int address) -{ - return 0xff; -} diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 834c58e49..a519107a9 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -13,12 +13,18 @@ namespace MOS { -class MOS6522 { +template class MOS6522 { public: - MOS6522(); + MOS6522() : _data_direction{0, 0} {} - void set_register(int address, uint8_t value); - uint8_t get_register(int address); + void set_register(int address, uint8_t value) {} + uint8_t get_register(int address) {return 0xff;} + + private: + uint16_t _interval_timers[2]; + uint8_t _shift_register; + uint8_t _input_latches[2]; + uint8_t _data_direction[2]; }; } diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 11c48b40f..2581b7553 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -43,7 +43,7 @@ using namespace MOS; */ MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YIQ, 65*4, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists + _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YIQ, 228, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists _horizontal_counter(0), _vertical_counter(0) { diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 249d16cd2..1b9724487 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -33,6 +33,14 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { *value = _mos6560->get_register(address - 0x9000); } + else if((address&0xfff0) == 0x9110) + { + *value = _userPortVIA->get_register(address - 0x9110); + } + else if((address&0xfff0) == 0x9120) + { + *value = _keyboardVIA->get_register(address - 0x9120); + } } else { @@ -42,6 +50,15 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { _mos6560->set_register(address - 0x9000, *value); } + else if((address&0xfff0) == 0x9110) + { + _userPortVIA->set_register(address - 0x9110, *value); + } + else if((address&0xfff0) == 0x9120) + { + _keyboardVIA->set_register(address - 0x9120, *value); + } + // TODO: the 6522 } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 460355d8d..c82e6b60f 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -11,6 +11,7 @@ #include "../../Processors/6502/CPU6502.hpp" #include "../../Components/6560/6560.hpp" +#include "../../Components/6522/6522.hpp" #include "../CRTMachine.hpp" namespace Vic20 { @@ -21,6 +22,12 @@ enum ROMSlot { ROMSlotCharacters, }; +class UserPortVIA: public MOS::MOS6522 { +}; + +class KeyboardVIA: public MOS::MOS6522 { +}; + class Machine: public CPU6502::Processor, public CRTMachine::Machine { public: Machine(); @@ -65,6 +72,8 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { } std::unique_ptr _mos6560; + std::unique_ptr _userPortVIA; + std::unique_ptr _keyboardVIA; }; } From 581eace4785d4498095e11a35ff200cbb9a6a21d Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 7 Jun 2016 22:01:14 -0400 Subject: [PATCH 26/66] Increased logging slightly, ensured all of colour RAM can be read, slightly improved the 2600 pixel decoder. --- Components/6522/6522.hpp | 19 +++++++++++++++++-- Components/6560/6560.cpp | 10 +++++----- Machines/Atari2600/Atari2600.cpp | 4 ++-- Machines/Vic-20/Vic20.cpp | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index a519107a9..309eaeceb 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -10,6 +10,7 @@ #define _522_hpp #include +#include namespace MOS { @@ -17,14 +18,28 @@ template class MOS6522 { public: MOS6522() : _data_direction{0, 0} {} - void set_register(int address, uint8_t value) {} - uint8_t get_register(int address) {return 0xff;} + void set_register(int address, uint8_t value) + { + printf("6522: %d <- %02x\n", address, value); +// switch(address) +// { +// case 0x11: _auxiliary_control_register = value; break; +// } + } + uint8_t get_register(int address) + { + printf("6522: %d\n", address); + return 0xff; + } private: uint16_t _interval_timers[2]; uint8_t _shift_register; uint8_t _input_latches[2]; uint8_t _data_direction[2]; + + uint8_t _interrupt_flag_register, _interrupt_enable_register; + uint8_t _peripheral_control_register, _auxiliary_control_register; }; } diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 2581b7553..2ebba2aa7 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -31,8 +31,8 @@ using namespace MOS; */ /* - 0 -> green - 1 -> green + 0 -> purple + 1 -> purple 2 -> browny yellow 3 -> browny red 4 -> purple @@ -53,10 +53,10 @@ MOS6560::MOS6560() : "uint c = texture(texID, coordinate).r;" "float y = 0.75 + (float(c & 8u) / 8.0) * 0.25 * step(1, c);" - "uint iPhase = 8u;" - "float phaseOffset = 6.283185308 * (float(iPhase)) / 7.0;" // TODO: appropriate phaseOffset + "uint iPhase = c & 7u;" + "float phaseOffset = 6.283185308 * float(iPhase + 8u) / 8.0;" // TODO: appropriate phaseOffset - "return mix(step(1, c) * y, step(2, c) * step(mod(phase + phaseOffset, 6.283185308), 3.141592654), amplitude);" + "return mix(step(1, c) * y, step(2, c) * sin(phase + phaseOffset), amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) "}"); } diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index e479780f5..fdd12c10d 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -69,7 +69,7 @@ void Machine::setup_output(float aspect_ratio) "uint iPhase = (c >> 4);" "float phaseOffset = 6.283185308 * float(iPhase - 1u) / 13.0;" - "return (float(y) / 14.0) * (1.0 - amplitude) + step(1, iPhase) * amplitude * cos(phase + phaseOffset);" + "return mix(float(y) / 14.0, step(1, iPhase) * cos(phase + phaseOffset), amplitude);" "}"); _crt->set_output_device(Outputs::CRT::Television); @@ -89,7 +89,7 @@ void Machine::switch_region() "uint direction = iPhase & 1u;" "float phaseOffset = float(7u - direction) + (float(direction) - 0.5) * 2.0 * float(iPhase >> 1);" "phaseOffset *= 6.283185308 / 12.0;" - "return (float(y) / 14.0) * (1.0 - amplitude) + step(4, (iPhase + 2u) & 15u) * amplitude * cos(phase + phaseOffset);" + "return mix(float(y) / 14.0, step(4, (iPhase + 2u) & 15u) * cos(phase + phaseOffset), amplitude);" "}"); _crt->set_new_timing(228, 312, Outputs::CRT::ColourSpace::YUV, 228, 1); diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 1b9724487..389ae7580 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -23,7 +23,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // run the phase-1 part of this cycle, in which the VIC accesses memory uint16_t video_address = _mos6560->get_address(); - _mos6560->set_graphics_value(read_memory(video_address), _colorMemory[video_address & 0x01ff]); + _mos6560->set_graphics_value(read_memory(video_address), _colorMemory[video_address & 0x03ff]); // run the phase-2 part of the cycle, which is whatever the 6502 said it should be if(isReadOperation(operation)) From e99055bedb9b0943ca9866b2bc093843e584f2c8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Jun 2016 22:15:24 -0400 Subject: [PATCH 27/66] =?UTF-8?q?Attempted=20switching=20back=20to=20a=20s?= =?UTF-8?q?quare=20wave=20for=20the=20composite=20video=20and=20otherwise?= =?UTF-8?q?=20implementing=20what's=20necessary=20to=20get=20to=20that=20f?= =?UTF-8?q?lashing=20cursor=20=E2=80=94=20the=206560=20returns=20its=20sca?= =?UTF-8?q?n=20line=20and=20the=20timing=20bits=20of=20the=206522=20are=20?= =?UTF-8?q?appearing.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Components/6522/6522.hpp | 60 ++++++++++++++++++++++++++++++++++----- Components/6560/6560.cpp | 12 ++++++-- Machines/Vic-20/Vic20.cpp | 8 ++++-- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 309eaeceb..d9c250db3 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -16,28 +16,74 @@ namespace MOS { template class MOS6522 { public: - MOS6522() : _data_direction{0, 0} {} + MOS6522() : + _data_direction{0, 0}, + _timer_is_running{false, false} + {} void set_register(int address, uint8_t value) { printf("6522: %d <- %02x\n", address, value); -// switch(address) -// { -// case 0x11: _auxiliary_control_register = value; break; -// } + address &= 0xf; + switch(address) + { + // Timer 1 + case 0x06: case 0x04: _interval_timer_latch[0] = (_interval_timer_latch[0]&0xff00) | value; break; + case 0x05: case 0x07: + _interval_timer_latch[0] = (_interval_timer_latch[0]&0x00ff) | (uint16_t)(value << 8); + // TODO: clear interrupt flag + if(address == 0x05) + { + _interval_timer[0] = _interval_timer_latch[0]; + _timer_is_running[0] = true; + } + break; + + // Timer 2 + case 0x08: _interval_timer_latch[1] = value; break; + case 0x09: + // TODO: clear interrupt flag + _interval_timer[1] = _interval_timer_latch[1] | (uint16_t)(value << 8); + _timer_is_running[1] = true; + break; + + case 0x11: _auxiliary_control_register = value; break; + } } + uint8_t get_register(int address) { printf("6522: %d\n", address); + address &= 0xf; + switch(address) + { + // Timer 1 + case 0x04: + // TODO: clear interrupt flag + return _interval_timer[0] & 0x00ff; + case 0x05: return _interval_timer[0] >> 8; + case 0x06: return _interval_timer_latch[0] & 0x00ff; + case 0x07: return _interval_timer_latch[0] >> 8; + } + return 0xff; } + void run_for_cycles(unsigned int number_of_cycles) + { + _interval_timer[0] -= number_of_cycles; + _interval_timer[1] -= number_of_cycles; + // TODO: interrupts, potentially reload of the first timer, other status effects + } + private: - uint16_t _interval_timers[2]; + uint16_t _interval_timer[2], _interval_timer_latch[2]; uint8_t _shift_register; - uint8_t _input_latches[2]; + uint8_t _input_latch[2]; uint8_t _data_direction[2]; + bool _timer_is_running[2]; + uint8_t _interrupt_flag_register, _interrupt_enable_register; uint8_t _peripheral_control_register, _auxiliary_control_register; }; diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 2ebba2aa7..f0b09adc7 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -56,12 +56,14 @@ MOS6560::MOS6560() : "uint iPhase = c & 7u;" "float phaseOffset = 6.283185308 * float(iPhase + 8u) / 8.0;" // TODO: appropriate phaseOffset - "return mix(step(1, c) * y, step(2, c) * sin(phase + phaseOffset), amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) + // sin(phase + phaseOffset) + "return mix(step(1, c) * y, step(2, c) * step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0, amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) "}"); } void MOS6560::set_register(int address, uint8_t value) { + address &= 0xf; _registers[address] = value; switch(address) { @@ -114,7 +116,13 @@ void MOS6560::set_register(int address, uint8_t value) uint8_t MOS6560::get_register(int address) { - return _registers[address]; + address &= 0xf; + switch(address) + { + default: return _registers[address]; + case 0x03: return ((_vertical_counter >> 1) & 0x80) | (_registers[3] & 0x7f); + case 0x04: return _vertical_counter & 0xff; + } } diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 389ae7580..3f32b44b8 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -12,7 +12,9 @@ using namespace Vic20; -Machine::Machine() +Machine::Machine() : + _userPortVIA(new UserPortVIA()), + _keyboardVIA(new KeyboardVIA()) { set_reset_line(true); } @@ -58,10 +60,10 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { _keyboardVIA->set_register(address - 0x9120, *value); } - - // TODO: the 6522 } + _userPortVIA->run_for_cycles(1); + _keyboardVIA->run_for_cycles(1); return 1; } From 30b7db3979ccf5f1f60044531a5bc1737720d8a4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2016 22:05:17 -0400 Subject: [PATCH 28/66] Attempted a square wave, made the Vic itself responsible for address manipulation re:the 6560. --- Components/6560/6560.cpp | 5 ++--- Machines/Vic-20/Vic20.cpp | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index f0b09adc7..1fe5e3205 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -57,7 +57,7 @@ MOS6560::MOS6560() : "float phaseOffset = 6.283185308 * float(iPhase + 8u) / 8.0;" // TODO: appropriate phaseOffset // sin(phase + phaseOffset) - "return mix(step(1, c) * y, step(2, c) * step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0, amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) + "return mix(step(1, c) * y, step(2, c) * step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0 - 1.0, amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) "}"); } @@ -226,8 +226,7 @@ uint16_t MOS6560::get_address() */ if(_column_counter&1) { - // TODO: don't add 0x8000. That's a hack. - return 0x8000 + (_character_cell_start_address + (_character_code*8) + (_row_counter&7)); + return _character_cell_start_address + (_character_code*8) + (_row_counter&7); } else { diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 3f32b44b8..e35b0352c 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -25,6 +25,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // run the phase-1 part of this cycle, in which the VIC accesses memory uint16_t video_address = _mos6560->get_address(); + if(!(video_address&0x1000)) video_address += 0x8000; _mos6560->set_graphics_value(read_memory(video_address), _colorMemory[video_address & 0x03ff]); // run the phase-2 part of the cycle, which is whatever the 6502 said it should be From f3b1d7de82ce67dcd79dae3b91c319ef083c8231 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Thu, 9 Jun 2016 22:37:59 -0400 Subject: [PATCH 29/66] ... and that's a flashing cursor. Keyboard input next! --- Components/6522/6522.hpp | 80 ++++++++++++++++++++++++++++++++++++--- Components/6560/6560.cpp | 4 +- Machines/Vic-20/Vic20.cpp | 11 ++++++ Machines/Vic-20/Vic20.hpp | 5 ++- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index d9c250db3..21c2971ca 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -14,8 +14,29 @@ namespace MOS { -template class MOS6522 { +class MOS6522Delegate { public: + virtual void mos6522_did_change_interrupt_status(void *mos6522) = 0; +}; + +template class MOS6522 { + private: + enum InterruptFlag: uint8_t { + CA2ActiveEdge = 1 << 0, + CA1ActiveEdge = 1 << 1, + ShiftRegister = 1 << 2, + CB2ActiveEdge = 1 << 3, + CB1ActiveEdge = 1 << 4, + Timer2 = 1 << 5, + Timer1 = 1 << 6, + }; + + public: + void set_delegate(MOS6522Delegate *delegate) + { + _delegate = delegate; + } + MOS6522() : _data_direction{0, 0}, _timer_is_running{false, false} @@ -31,23 +52,31 @@ template class MOS6522 { case 0x06: case 0x04: _interval_timer_latch[0] = (_interval_timer_latch[0]&0xff00) | value; break; case 0x05: case 0x07: _interval_timer_latch[0] = (_interval_timer_latch[0]&0x00ff) | (uint16_t)(value << 8); - // TODO: clear interrupt flag + _interrupt_flags &= ~InterruptFlag::Timer1; if(address == 0x05) { _interval_timer[0] = _interval_timer_latch[0]; _timer_is_running[0] = true; } + reevaluate_interrupts(); break; // Timer 2 case 0x08: _interval_timer_latch[1] = value; break; case 0x09: - // TODO: clear interrupt flag + _interrupt_flags &= ~InterruptFlag::Timer2; _interval_timer[1] = _interval_timer_latch[1] | (uint16_t)(value << 8); _timer_is_running[1] = true; + reevaluate_interrupts(); break; - case 0x11: _auxiliary_control_register = value; break; + case 11: _auxiliary_control_register = value; break; + case 13: + if(!(value&0x80)) value = ~value; + _interrupt_mask = value; + break; + case 14: + break; } } @@ -59,11 +88,16 @@ template class MOS6522 { { // Timer 1 case 0x04: - // TODO: clear interrupt flag + _interrupt_flags &= ~InterruptFlag::Timer1; + reevaluate_interrupts(); return _interval_timer[0] & 0x00ff; case 0x05: return _interval_timer[0] >> 8; case 0x06: return _interval_timer_latch[0] & 0x00ff; case 0x07: return _interval_timer_latch[0] >> 8; + + case 11: return _auxiliary_control_register; + case 13: return _interrupt_flags; + case 14: return _interrupt_mask; } return 0xff; @@ -73,14 +107,48 @@ template class MOS6522 { { _interval_timer[0] -= number_of_cycles; _interval_timer[1] -= number_of_cycles; - // TODO: interrupts, potentially reload of the first timer, other status effects + + if(!_interval_timer[1] && _timer_is_running[1]) + { + _timer_is_running[1] = false; + _interrupt_flags |= InterruptFlag::Timer2; + reevaluate_interrupts(); + } + + if(!_interval_timer[0] && _timer_is_running[0]) + { + _interrupt_flags |= InterruptFlag::Timer1; + reevaluate_interrupts(); + + // TODO: reload shouldn't occur for a further 1.5 cycles + if(_auxiliary_control_register&0x40) + { + _interval_timer[0] = _interval_timer_latch[0]; + } + else + _timer_is_running[0] = false; + } + // TODO: lots of other status effects + } + + bool get_interrupt_line() + { + uint8_t interrupt_status = _interrupt_flags & (~_interrupt_mask) & 0x7f; + return !!interrupt_status; } private: + inline void reevaluate_interrupts() + { + if(_delegate) _delegate->mos6522_did_change_interrupt_status(this); + } + + MOS6522Delegate *_delegate; uint16_t _interval_timer[2], _interval_timer_latch[2]; uint8_t _shift_register; uint8_t _input_latch[2]; uint8_t _data_direction[2]; + uint8_t _interrupt_flags, _interrupt_mask; bool _timer_is_running[2]; diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 1fe5e3205..c20391932 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -120,8 +120,8 @@ uint8_t MOS6560::get_register(int address) switch(address) { default: return _registers[address]; - case 0x03: return ((_vertical_counter >> 1) & 0x80) | (_registers[3] & 0x7f); - case 0x04: return _vertical_counter & 0xff; + case 0x03: return (uint8_t)(_vertical_counter << 7) | (_registers[3] & 0x7f); + case 0x04: return (_vertical_counter >> 1) & 0xff; } } diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index e35b0352c..3bf55f007 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -16,6 +16,8 @@ Machine::Machine() : _userPortVIA(new UserPortVIA()), _keyboardVIA(new KeyboardVIA()) { + _userPortVIA->set_delegate(this); + _keyboardVIA->set_delegate(this); set_reset_line(true); } @@ -68,6 +70,15 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin return 1; } +#pragma mark - 6522 delegate + +void Machine::mos6522_did_change_interrupt_status(void *mos6522) +{ + bool irq = _userPortVIA->get_interrupt_line() || _keyboardVIA->get_interrupt_line(); + printf("IRQ: %s\n", irq ? "e" : "-"); + set_irq_line(irq); +} + #pragma mark - Setup void Machine::setup_output(float aspect_ratio) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index c82e6b60f..05092f96c 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -28,7 +28,7 @@ class UserPortVIA: public MOS::MOS6522 { class KeyboardVIA: public MOS::MOS6522 { }; -class Machine: public CPU6502::Processor, public CRTMachine::Machine { +class Machine: public CPU6502::Processor, public CRTMachine::Machine, public MOS::MOS6522Delegate { public: Machine(); @@ -46,6 +46,9 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine { virtual Outputs::Speaker *get_speaker() { return nullptr; } // TODO virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor::run_for_cycles(number_of_cycles); } + // to satisfy MOS::MOS6522::Delegate + virtual void mos6522_did_change_interrupt_status(void *mos6522); + private: uint8_t _characterROM[0x1000]; uint8_t _basicROM[0x2000]; From 1ed04fae1e07d1eeecd8b360ebaae96b45bc829a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 10 Jun 2016 18:12:21 -0400 Subject: [PATCH 30/66] Resolved 6560 addressing. --- Components/6560/6560.cpp | 2 +- Machines/Vic-20/Vic20.cpp | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index c20391932..29054d0d6 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -88,7 +88,7 @@ void MOS6560::set_register(int address, uint8_t value) case 0x5: _character_cell_start_address = (uint16_t)((value & 0x0f) << 10); - _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0400) | ((value & 0xf0) << 5)); + _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0200) | ((value & 0xf0) << 6)); break; case 0xe: diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 3bf55f007..ec3ab80c6 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -27,8 +27,18 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin // run the phase-1 part of this cycle, in which the VIC accesses memory uint16_t video_address = _mos6560->get_address(); - if(!(video_address&0x1000)) video_address += 0x8000; - _mos6560->set_graphics_value(read_memory(video_address), _colorMemory[video_address & 0x03ff]); + uint8_t video_value = 0xff; // TODO + if(!(video_address&0x2000)) + { + video_value = _characterROM[video_address & 0x0fff]; + } + else + { + video_address &= 0x1fff; + if(video_address < sizeof(_userBASICMemory)) video_value = _userBASICMemory[video_address]; + else if(video_address >= 0x1000 && video_address < 0x2000) video_value = _screenMemory[video_address&0x0fff]; + } + _mos6560->set_graphics_value(video_value, _colorMemory[video_address & 0x03ff]); // run the phase-2 part of the cycle, which is whatever the 6502 said it should be if(isReadOperation(operation)) From a71259dec393918f92460779f8120c4eac199925 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 07:12:55 -0400 Subject: [PATCH 31/66] Gave the 6522 a full and grouped register set. --- Components/6522/6522.hpp | 122 ++++++++++++++++++++++++++------------- 1 file changed, 82 insertions(+), 40 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 21c2971ca..879837050 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -38,66 +38,106 @@ template class MOS6522 { } MOS6522() : - _data_direction{0, 0}, _timer_is_running{false, false} {} void set_register(int address, uint8_t value) { - printf("6522: %d <- %02x\n", address, value); address &= 0xf; switch(address) { + case 0x00: + _registers.output[1] = value; + break; + case 0x01: + _registers.output[0] = value; + break; + case 0xf: + _registers.output[0] = value; + break; + case 0x02: + _registers.data_direction[1] = value; + break; + case 0x03: + _registers.data_direction[0] = value; + break; + // Timer 1 - case 0x06: case 0x04: _interval_timer_latch[0] = (_interval_timer_latch[0]&0xff00) | value; break; + case 0x06: case 0x04: _registers.timer_latch[0] = (_registers.timer_latch[0]&0xff00) | value; break; case 0x05: case 0x07: - _interval_timer_latch[0] = (_interval_timer_latch[0]&0x00ff) | (uint16_t)(value << 8); - _interrupt_flags &= ~InterruptFlag::Timer1; + _registers.timer_latch[0] = (_registers.timer_latch[0]&0x00ff) | (uint16_t)(value << 8); + _registers.interrupt_flags &= ~InterruptFlag::Timer1; if(address == 0x05) { - _interval_timer[0] = _interval_timer_latch[0]; + _registers.timer[0] = _registers.timer_latch[0]; _timer_is_running[0] = true; } reevaluate_interrupts(); break; // Timer 2 - case 0x08: _interval_timer_latch[1] = value; break; + case 0x08: _registers.timer_latch[1] = value; break; case 0x09: - _interrupt_flags &= ~InterruptFlag::Timer2; - _interval_timer[1] = _interval_timer_latch[1] | (uint16_t)(value << 8); + _registers.interrupt_flags &= ~InterruptFlag::Timer2; + _registers.timer[1] = _registers.timer_latch[1] | (uint16_t)(value << 8); _timer_is_running[1] = true; reevaluate_interrupts(); break; - case 11: _auxiliary_control_register = value; break; - case 13: - if(!(value&0x80)) value = ~value; - _interrupt_mask = value; + // Shift + case 0xa: _registers.shift = value; break; + + // Control + case 0xb: _registers.auxiliary_control = value; break; + case 0xc: _registers.peripheral_control = value; break; + + // Interrupt control + case 0xd: + _registers.interrupt_flags = value; // TODO: really? + reevaluate_interrupts(); break; - case 14: + case 0xe: + if(!(value&0x80)) value = ~value; + _registers.interrupt_enable = value; + reevaluate_interrupts(); break; } } uint8_t get_register(int address) { - printf("6522: %d\n", address); address &= 0xf; switch(address) { + case 0x00: return _registers.input[1]; + case 0x01: return _registers.input[0]; + case 0x02: return _registers.data_direction[1]; + case 0x03: return _registers.data_direction[0]; + case 0x0f: return _registers.input[1]; + // Timer 1 case 0x04: - _interrupt_flags &= ~InterruptFlag::Timer1; + _registers.interrupt_flags &= ~InterruptFlag::Timer1; reevaluate_interrupts(); - return _interval_timer[0] & 0x00ff; - case 0x05: return _interval_timer[0] >> 8; - case 0x06: return _interval_timer_latch[0] & 0x00ff; - case 0x07: return _interval_timer_latch[0] >> 8; + return _registers.timer[0] & 0x00ff; + case 0x05: return _registers.timer[0] >> 8; + case 0x06: return _registers.timer_latch[0] & 0x00ff; + case 0x07: return _registers.timer_latch[0] >> 8; - case 11: return _auxiliary_control_register; - case 13: return _interrupt_flags; - case 14: return _interrupt_mask; + // Timer 2 + case 0x08: + _registers.interrupt_flags &= ~InterruptFlag::Timer2; + reevaluate_interrupts(); + return _registers.timer[1] & 0x00ff; + case 0x09: return _registers.timer[1] >> 8; + + case 0x0a: return _registers.shift; + + case 0x0b: return _registers.auxiliary_control; + case 0x0c: return _registers.peripheral_control; + + case 0x0d: return _registers.interrupt_flags; + case 0x0e: return _registers.interrupt_enable; } return 0xff; @@ -105,25 +145,25 @@ template class MOS6522 { void run_for_cycles(unsigned int number_of_cycles) { - _interval_timer[0] -= number_of_cycles; - _interval_timer[1] -= number_of_cycles; + _registers.timer[0] -= number_of_cycles; + _registers.timer[1] -= number_of_cycles; - if(!_interval_timer[1] && _timer_is_running[1]) + if(!_registers.timer[1] && _timer_is_running[1]) { _timer_is_running[1] = false; - _interrupt_flags |= InterruptFlag::Timer2; + _registers.interrupt_flags |= InterruptFlag::Timer2; reevaluate_interrupts(); } - if(!_interval_timer[0] && _timer_is_running[0]) + if(!_registers.timer[0] && _timer_is_running[0]) { - _interrupt_flags |= InterruptFlag::Timer1; + _registers.interrupt_flags |= InterruptFlag::Timer1; reevaluate_interrupts(); // TODO: reload shouldn't occur for a further 1.5 cycles - if(_auxiliary_control_register&0x40) + if(_registers.auxiliary_control&0x40) { - _interval_timer[0] = _interval_timer_latch[0]; + _registers.timer[0] = _registers.timer_latch[0]; } else _timer_is_running[0] = false; @@ -133,7 +173,7 @@ template class MOS6522 { bool get_interrupt_line() { - uint8_t interrupt_status = _interrupt_flags & (~_interrupt_mask) & 0x7f; + uint8_t interrupt_status = _registers.interrupt_flags & (~_registers.interrupt_enable) & 0x7f; return !!interrupt_status; } @@ -144,16 +184,18 @@ template class MOS6522 { } MOS6522Delegate *_delegate; - uint16_t _interval_timer[2], _interval_timer_latch[2]; - uint8_t _shift_register; - uint8_t _input_latch[2]; - uint8_t _data_direction[2]; - uint8_t _interrupt_flags, _interrupt_mask; + + struct Registers { + uint8_t output[2], input[2], data_direction[2]; + uint16_t timer[2], timer_latch[2]; + uint8_t shift; + uint8_t auxiliary_control, peripheral_control; + uint8_t interrupt_flags, interrupt_enable; + + Registers() : data_direction{0, 0} {} + } _registers; bool _timer_is_running[2]; - - uint8_t _interrupt_flag_register, _interrupt_enable_register; - uint8_t _peripheral_control_register, _auxiliary_control_register; }; } From 82a3c4964b05e6dcd48a6f57584bdce0d992416a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 07:49:07 -0400 Subject: [PATCH 32/66] Decided to keep the internal copy of the interrupt enable the other way around. Reduced delegate noise. --- Components/6522/6522.hpp | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 879837050..e4fdd087e 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -32,15 +32,6 @@ template class MOS6522 { }; public: - void set_delegate(MOS6522Delegate *delegate) - { - _delegate = delegate; - } - - MOS6522() : - _timer_is_running{false, false} - {} - void set_register(int address, uint8_t value) { address &= 0xf; @@ -97,7 +88,7 @@ template class MOS6522 { reevaluate_interrupts(); break; case 0xe: - if(!(value&0x80)) value = ~value; + if(value&0x80) value = ~value; _registers.interrupt_enable = value; reevaluate_interrupts(); break; @@ -136,8 +127,8 @@ template class MOS6522 { case 0x0b: return _registers.auxiliary_control; case 0x0c: return _registers.peripheral_control; - case 0x0d: return _registers.interrupt_flags; - case 0x0e: return _registers.interrupt_enable; + case 0x0d: return _registers.interrupt_flags | (get_interrupt_line() ? 0x80 : 0x00); + case 0x0e: return ~_registers.interrupt_enable; } return 0xff; @@ -173,14 +164,30 @@ template class MOS6522 { bool get_interrupt_line() { - uint8_t interrupt_status = _registers.interrupt_flags & (~_registers.interrupt_enable) & 0x7f; + uint8_t interrupt_status = _registers.interrupt_flags & _registers.interrupt_enable & 0x7f; return !!interrupt_status; } + void set_delegate(MOS6522Delegate *delegate) + { + _delegate = delegate; + } + + MOS6522() : + _timer_is_running{false, false}, + _last_posted_interrupt_status(false) + {} + private: + bool _last_posted_interrupt_status; inline void reevaluate_interrupts() { - if(_delegate) _delegate->mos6522_did_change_interrupt_status(this); + bool new_interrupt_status = get_interrupt_line(); + if(new_interrupt_status != _last_posted_interrupt_status) + { + _last_posted_interrupt_status = new_interrupt_status; + if(_delegate) _delegate->mos6522_did_change_interrupt_status(this); + } } MOS6522Delegate *_delegate; From 1054793fd7b5574d9e87dcfe5d8a60ee54e47970 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 07:57:04 -0400 Subject: [PATCH 33/66] Fixed interrupt enable register. This makes a lot more sense! --- Components/6522/6522.hpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index e4fdd087e..78c1508cc 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -35,6 +35,7 @@ template class MOS6522 { void set_register(int address, uint8_t value) { address &= 0xf; +// printf("6522 %p: %d <- %02x\n", this, address, value); switch(address) { case 0x00: @@ -88,8 +89,10 @@ template class MOS6522 { reevaluate_interrupts(); break; case 0xe: - if(value&0x80) value = ~value; - _registers.interrupt_enable = value; + if(value&0x80) + _registers.interrupt_enable |= value; + else + _registers.interrupt_enable &= ~value; reevaluate_interrupts(); break; } @@ -98,6 +101,7 @@ template class MOS6522 { uint8_t get_register(int address) { address &= 0xf; +// printf("6522 %p: %d\n", this, address); switch(address) { case 0x00: return _registers.input[1]; @@ -128,7 +132,7 @@ template class MOS6522 { case 0x0c: return _registers.peripheral_control; case 0x0d: return _registers.interrupt_flags | (get_interrupt_line() ? 0x80 : 0x00); - case 0x0e: return ~_registers.interrupt_enable; + case 0x0e: return _registers.interrupt_enable | 0x80; } return 0xff; @@ -199,7 +203,9 @@ template class MOS6522 { uint8_t auxiliary_control, peripheral_control; uint8_t interrupt_flags, interrupt_enable; - Registers() : data_direction{0, 0} {} + Registers() : + data_direction{0, 0}, + interrupt_enable(0) {} } _registers; bool _timer_is_running[2]; From de847588624cb2216a8a377b2213b1d355ff7aed Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 07:58:32 -0400 Subject: [PATCH 34/66] This is how flags writes are supposed to work, it seems. --- Components/6522/6522.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 78c1508cc..4a42f4c10 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -85,7 +85,7 @@ template class MOS6522 { // Interrupt control case 0xd: - _registers.interrupt_flags = value; // TODO: really? + _registers.interrupt_flags &= ~value; reevaluate_interrupts(); break; case 0xe: From 7a241b5ef54d539c3dfd44cb3b76711bef06b008 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 11:34:39 -0400 Subject: [PATCH 35/66] Added just enough hopefully to allow implementation of the keyboard-input VIA. --- Components/6522/6522.hpp | 34 +++++++++++++++++++++++++--------- Machines/Vic-20/Vic20.cpp | 1 - 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index 4a42f4c10..deb196903 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -40,13 +40,18 @@ template class MOS6522 { { case 0x00: _registers.output[1] = value; + static_cast(this)->set_port_output(1, value); // TODO: handshake break; case 0x01: _registers.output[0] = value; + static_cast(this)->set_port_output(0, value); // TODO: handshake break; case 0xf: + // No handshake, so write directly _registers.output[0] = value; + static_cast(this)->set_port_output(0, value); break; + case 0x02: _registers.data_direction[1] = value; break; @@ -104,11 +109,12 @@ template class MOS6522 { // printf("6522 %p: %d\n", this, address); switch(address) { - case 0x00: return _registers.input[1]; - case 0x01: return _registers.input[0]; + case 0x00: return (_registers.auxiliary_control & 0x40) ? _registers.input[1] : static_cast(this)->get_port_input(1); + case 0x0f: // TODO: no handshake + case 0x01: return (_registers.auxiliary_control & 0x80) ? _registers.input[0] : static_cast(this)->get_port_input(0); + case 0x02: return _registers.data_direction[1]; case 0x03: return _registers.data_direction[0]; - case 0x0f: return _registers.input[1]; // Timer 1 case 0x04: @@ -138,6 +144,10 @@ template class MOS6522 { return 0xff; } + void set_control_line_input(int port, int line, bool value) + { + } + void run_for_cycles(unsigned int number_of_cycles) { _registers.timer[0] -= number_of_cycles; @@ -157,9 +167,7 @@ template class MOS6522 { // TODO: reload shouldn't occur for a further 1.5 cycles if(_registers.auxiliary_control&0x40) - { _registers.timer[0] = _registers.timer_latch[0]; - } else _timer_is_running[0] = false; } @@ -183,6 +191,12 @@ template class MOS6522 { {} private: + // Intended to be overwritten + uint8_t get_port_input(int port) { return 0xff; } + void set_port_output(int port, uint8_t value) {} + + // Delegate and communications + MOS6522Delegate *_delegate; bool _last_posted_interrupt_status; inline void reevaluate_interrupts() { @@ -194,8 +208,7 @@ template class MOS6522 { } } - MOS6522Delegate *_delegate; - + // The registers struct Registers { uint8_t output[2], input[2], data_direction[2]; uint16_t timer[2], timer_latch[2]; @@ -203,11 +216,14 @@ template class MOS6522 { uint8_t auxiliary_control, peripheral_control; uint8_t interrupt_flags, interrupt_enable; + // "A low reset (RES) input clears all R6522 internal registers to logic 0" Registers() : - data_direction{0, 0}, - interrupt_enable(0) {} + output{0, 0}, input{0, 0}, data_direction{0, 0}, + auxiliary_control(0), peripheral_control(0), + interrupt_flags(0), interrupt_enable(0) {} } _registers; + // Internal state other than the registers bool _timer_is_running[2]; }; diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index ec3ab80c6..313330df2 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -85,7 +85,6 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin void Machine::mos6522_did_change_interrupt_status(void *mos6522) { bool irq = _userPortVIA->get_interrupt_line() || _keyboardVIA->get_interrupt_line(); - printf("IRQ: %s\n", irq ? "e" : "-"); set_irq_line(irq); } From d7c1f5b18a5e2b968885c5233d98cbd1f6a84255 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 11:50:37 -0400 Subject: [PATCH 36/66] Made an attempt at hooking up the '2' and '4' keys. A mostly unsuccessful attempt. 2 does nothing, 4 clears the screen. --- Machines/Vic-20/Vic20.hpp | 38 +++++++++++++++++++ .../Mac/Clock Signal/Wrappers/CSElectron.h | 3 +- .../Clock Signal/Wrappers/CSKeyboardMachine.h | 2 + .../Mac/Clock Signal/Wrappers/CSVic20.mm | 7 ++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 05092f96c..7fa8dbdc6 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -22,10 +22,47 @@ enum ROMSlot { ROMSlotCharacters, }; + +#define key(line, mask) (((mask) << 3) | (line)) + +enum Key: uint16_t { + Key2 = key(7, 0x80), Key4 = key(7, 0x40) +}; + class UserPortVIA: public MOS::MOS6522 { }; class KeyboardVIA: public MOS::MOS6522 { + public: + void set_key_state(Key key, bool isPressed) { + if(isPressed) + _columns[key & 0x07] &= ~(key >> 3); + else + _columns[key & 0x07] |= (key >> 3); + } + + // to satisfy MOS::MOS6522 + uint8_t get_port_input(int port) { + if(!port) { + uint8_t result = 0xff; + for(int c = 0; c < 8; c++) + { + if(!(_activation_mask&(1 << c))) result &= _columns[c]; + } + return result; + } + + return 0xff; + } + + void set_port_output(int port, uint8_t value) { + if(port) _activation_mask = value; + } + + KeyboardVIA() : _columns{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} {} + private: + uint8_t _columns[8]; + uint8_t _activation_mask; }; class Machine: public CPU6502::Processor, public CRTMachine::Machine, public MOS::MOS6522Delegate { @@ -34,6 +71,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p void set_rom(ROMSlot slot, size_t length, const uint8_t *data); void add_prg(size_t length, const uint8_t *data); + void set_key_state(Key key, bool isPressed) { _keyboardVIA->set_key_state(key, isPressed); } // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h index 7f546434f..1de8ac9e0 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h @@ -6,8 +6,7 @@ // Copyright © 2016 Thomas Harte. All rights reserved. // -#include "CSMachine.h" -#import "KeyCodes.h" +#import "CSMachine.h" #import "CSKeyboardMachine.h" @interface CSElectron : CSMachine diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h b/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h index bba3b77b7..34f3dea0f 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSKeyboardMachine.h @@ -6,6 +6,8 @@ // Copyright © 2016 Thomas Harte. All rights reserved. // +#import "KeyCodes.h" + @protocol CSKeyboardMachine - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index cee3469d3..cd9209d60 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -39,6 +39,13 @@ } - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { + @synchronized(self) { + switch(key) + { + case VK_ANSI_2: _vic20.set_key_state(Vic20::Key::Key2, isPressed); break; + case VK_ANSI_4: _vic20.set_key_state(Vic20::Key::Key4, isPressed); break; + } + } } - (void)clearAllKeys { From 271de23ee6e8cb79a9b5872c55a0a3b890955a48 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 12:26:19 -0400 Subject: [PATCH 37/66] Ran on in and introduced a bunch more keys, hopefully to help to diagnose. --- Machines/Vic-20/Vic20.hpp | 30 ++++++++++++--- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 37 +++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 7fa8dbdc6..816a10392 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -26,7 +26,22 @@ enum ROMSlot { #define key(line, mask) (((mask) << 3) | (line)) enum Key: uint16_t { - Key2 = key(7, 0x80), Key4 = key(7, 0x40) + Key2 = key(7, 0x01), Key4 = key(7, 0x02), Key6 = key(7, 0x04), Key8 = key(7, 0x08), + Key0 = key(7, 0x10), KeyDash = key(7, 0x20), KeyHome = key(7, 0x40), KeyF7 = key(7, 0x80), + KeyQ = key(6, 0x01), KeyE = key(6, 0x02), KeyT = key(6, 0x04), KeyU = key(6, 0x08), + KeyO = key(6, 0x10), KeyAt = key(6, 0x20), KeyUp = key(6, 0x40), KeyF5 = key(6, 0x80), + KeyCBM = key(5, 0x01), KeyS = key(5, 0x02), KeyF = key(5, 0x04), KeyH = key(5, 0x08), + KeyK = key(5, 0x10), KeyColon = key(5, 0x20), KeyEquals = key(5, 0x40), KeyF3 = key(5, 0x80), + KeySpace = key(4, 0x01), KeyZ = key(4, 0x02), KeyC = key(4, 0x04), KeyB = key(4, 0x08), + KeyM = key(4, 0x10), KeyFullStop = key(4, 0x20), KeyRShift = key(4, 0x40), KeyF1 = key(4, 0x80), + KeyRunStop = key(3, 0x01), KeyLShift = key(3, 0x02), KeyX = key(3, 0x04), KeyV = key(3, 0x08), + KeyN = key(3, 0x10), KeyComma = key(3, 0x20), KeySlash = key(3, 0x40), KeyDown = key(3, 0x80), + KeyControl = key(2, 0x01), KeyA = key(2, 0x02), KeyD = key(2, 0x04), KeyG = key(2, 0x08), + KeyJ = key(2, 0x10), KeyL = key(2, 0x20), KeySemicolon = key(2, 0x40), KeyRight = key(2, 0x80), + KeyLeft = key(1, 0x01), KeyW = key(1, 0x02), KeyR = key(1, 0x04), KeyY = key(1, 0x08), + KeyI = key(1, 0x10), KeyP = key(1, 0x20), KeyAsterisk = key(1, 0x40), KeyReturn = key(1, 0x80), + Key1 = key(0, 0x01), Key3 = key(0, 0x02), Key5 = key(0, 0x04), Key7 = key(0, 0x08), + Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDel = key(0, 0x80), }; class UserPortVIA: public MOS::MOS6522 { @@ -36,9 +51,9 @@ class KeyboardVIA: public MOS::MOS6522 { public: void set_key_state(Key key, bool isPressed) { if(isPressed) - _columns[key & 0x07] &= ~(key >> 3); + _columns[key & 7] &= ~(key >> 3); else - _columns[key & 0x07] |= (key >> 3); + _columns[key & 7] |= (key >> 3); } // to satisfy MOS::MOS6522 @@ -47,8 +62,11 @@ class KeyboardVIA: public MOS::MOS6522 { uint8_t result = 0xff; for(int c = 0; c < 8; c++) { - if(!(_activation_mask&(1 << c))) result &= _columns[c]; + if(!(_activation_mask&(1 << c))) + result &= _columns[c]; } +// if(_activation_mask) +// printf("%02x => %02x\n", _activation_mask, result); return result; } @@ -56,7 +74,9 @@ class KeyboardVIA: public MOS::MOS6522 { } void set_port_output(int port, uint8_t value) { - if(port) _activation_mask = value; + if(port) + _activation_mask = value; +// printf("%d <= %02x\n", port, value); } KeyboardVIA() : _columns{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} {} diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index cd9209d60..250145a7e 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -42,8 +42,45 @@ @synchronized(self) { switch(key) { + case VK_ANSI_1: _vic20.set_key_state(Vic20::Key::Key1, isPressed); break; case VK_ANSI_2: _vic20.set_key_state(Vic20::Key::Key2, isPressed); break; + case VK_ANSI_3: _vic20.set_key_state(Vic20::Key::Key3, isPressed); break; case VK_ANSI_4: _vic20.set_key_state(Vic20::Key::Key4, isPressed); break; + case VK_ANSI_5: _vic20.set_key_state(Vic20::Key::Key5, isPressed); break; + case VK_ANSI_6: _vic20.set_key_state(Vic20::Key::Key6, isPressed); break; + case VK_ANSI_7: _vic20.set_key_state(Vic20::Key::Key7, isPressed); break; + case VK_ANSI_8: _vic20.set_key_state(Vic20::Key::Key8, isPressed); break; + case VK_ANSI_9: _vic20.set_key_state(Vic20::Key::Key9, isPressed); break; + case VK_ANSI_0: _vic20.set_key_state(Vic20::Key::Key0, isPressed); break; + + case VK_ANSI_Q: _vic20.set_key_state(Vic20::Key::KeyQ, isPressed); break; + case VK_ANSI_W: _vic20.set_key_state(Vic20::Key::KeyW, isPressed); break; + case VK_ANSI_E: _vic20.set_key_state(Vic20::Key::KeyE, isPressed); break; + case VK_ANSI_R: _vic20.set_key_state(Vic20::Key::KeyR, isPressed); break; + case VK_ANSI_T: _vic20.set_key_state(Vic20::Key::KeyT, isPressed); break; + case VK_ANSI_Y: _vic20.set_key_state(Vic20::Key::KeyY, isPressed); break; + case VK_ANSI_U: _vic20.set_key_state(Vic20::Key::KeyU, isPressed); break; + case VK_ANSI_I: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; + case VK_ANSI_O: _vic20.set_key_state(Vic20::Key::KeyO, isPressed); break; + case VK_ANSI_P: _vic20.set_key_state(Vic20::Key::KeyP, isPressed); break; + + case VK_ANSI_A: _vic20.set_key_state(Vic20::Key::KeyA, isPressed); break; + case VK_ANSI_S: _vic20.set_key_state(Vic20::Key::KeyS, isPressed); break; + case VK_ANSI_D: _vic20.set_key_state(Vic20::Key::KeyD, isPressed); break; + case VK_ANSI_F: _vic20.set_key_state(Vic20::Key::KeyF, isPressed); break; + case VK_ANSI_G: _vic20.set_key_state(Vic20::Key::KeyG, isPressed); break; + case VK_ANSI_H: _vic20.set_key_state(Vic20::Key::KeyH, isPressed); break; + case VK_ANSI_J: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; + case VK_ANSI_K: _vic20.set_key_state(Vic20::Key::KeyO, isPressed); break; + case VK_ANSI_L: _vic20.set_key_state(Vic20::Key::KeyP, isPressed); break; + + case VK_ANSI_Z: _vic20.set_key_state(Vic20::Key::KeyZ, isPressed); break; + case VK_ANSI_X: _vic20.set_key_state(Vic20::Key::KeyX, isPressed); break; + case VK_ANSI_C: _vic20.set_key_state(Vic20::Key::KeyC, isPressed); break; + case VK_ANSI_V: _vic20.set_key_state(Vic20::Key::KeyV, isPressed); break; + case VK_ANSI_B: _vic20.set_key_state(Vic20::Key::KeyB, isPressed); break; + case VK_ANSI_N: _vic20.set_key_state(Vic20::Key::KeyN, isPressed); break; + case VK_ANSI_M: _vic20.set_key_state(Vic20::Key::KeyM, isPressed); break; } } } From d1731b1d26f9c8c2ab1f90aec1621cfa755a48c3 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 13:06:01 -0400 Subject: [PATCH 38/66] =?UTF-8?q?Hacked=20my=206522=20to=20work.=20Mistake?= =?UTF-8?q?=20is=20in=20not=20returning=20output=20as=20input=20when=20app?= =?UTF-8?q?ropriate=20=E2=80=94=20i.e.=20that=20I'm=20ignoring=20data=20di?= =?UTF-8?q?rection.=20Also=20fixed=20K=20and=20L=20keys.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Components/6522/6522.hpp | 49 ++++++++++--------- Machines/Vic-20/Vic20.hpp | 8 ++- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 4 +- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Components/6522/6522.hpp b/Components/6522/6522.hpp index deb196903..15458d465 100644 --- a/Components/6522/6522.hpp +++ b/Components/6522/6522.hpp @@ -38,11 +38,11 @@ template class MOS6522 { // printf("6522 %p: %d <- %02x\n", this, address, value); switch(address) { - case 0x00: + case 0x0: _registers.output[1] = value; static_cast(this)->set_port_output(1, value); // TODO: handshake break; - case 0x01: + case 0x1: _registers.output[0] = value; static_cast(this)->set_port_output(0, value); // TODO: handshake break; @@ -52,16 +52,16 @@ template class MOS6522 { static_cast(this)->set_port_output(0, value); break; - case 0x02: + case 0x2: _registers.data_direction[1] = value; break; - case 0x03: + case 0x3: _registers.data_direction[0] = value; break; // Timer 1 - case 0x06: case 0x04: _registers.timer_latch[0] = (_registers.timer_latch[0]&0xff00) | value; break; - case 0x05: case 0x07: + case 0x6: case 0x4: _registers.timer_latch[0] = (_registers.timer_latch[0]&0xff00) | value; break; + case 0x5: case 0x7: _registers.timer_latch[0] = (_registers.timer_latch[0]&0x00ff) | (uint16_t)(value << 8); _registers.interrupt_flags &= ~InterruptFlag::Timer1; if(address == 0x05) @@ -73,8 +73,8 @@ template class MOS6522 { break; // Timer 2 - case 0x08: _registers.timer_latch[1] = value; break; - case 0x09: + case 0x8: _registers.timer_latch[1] = value; break; + case 0x9: _registers.interrupt_flags &= ~InterruptFlag::Timer2; _registers.timer[1] = _registers.timer_latch[1] | (uint16_t)(value << 8); _timer_is_running[1] = true; @@ -109,36 +109,37 @@ template class MOS6522 { // printf("6522 %p: %d\n", this, address); switch(address) { - case 0x00: return (_registers.auxiliary_control & 0x40) ? _registers.input[1] : static_cast(this)->get_port_input(1); - case 0x0f: // TODO: no handshake - case 0x01: return (_registers.auxiliary_control & 0x80) ? _registers.input[0] : static_cast(this)->get_port_input(0); +// case 0x0: return (_registers.auxiliary_control & 0x40) ? _registers.input[1] : static_cast(this)->get_port_input(1); + case 0x0: return _registers.output[1];//static_cast(this)->get_port_input(1); + case 0xf: // TODO: handshake, latching + case 0x1: return static_cast(this)->get_port_input(0); - case 0x02: return _registers.data_direction[1]; - case 0x03: return _registers.data_direction[0]; + case 0x2: return _registers.data_direction[1]; + case 0x3: return _registers.data_direction[0]; // Timer 1 - case 0x04: + case 0x4: _registers.interrupt_flags &= ~InterruptFlag::Timer1; reevaluate_interrupts(); return _registers.timer[0] & 0x00ff; - case 0x05: return _registers.timer[0] >> 8; - case 0x06: return _registers.timer_latch[0] & 0x00ff; - case 0x07: return _registers.timer_latch[0] >> 8; + case 0x5: return _registers.timer[0] >> 8; + case 0x6: return _registers.timer_latch[0] & 0x00ff; + case 0x7: return _registers.timer_latch[0] >> 8; // Timer 2 - case 0x08: + case 0x8: _registers.interrupt_flags &= ~InterruptFlag::Timer2; reevaluate_interrupts(); return _registers.timer[1] & 0x00ff; - case 0x09: return _registers.timer[1] >> 8; + case 0x9: return _registers.timer[1] >> 8; - case 0x0a: return _registers.shift; + case 0xa: return _registers.shift; - case 0x0b: return _registers.auxiliary_control; - case 0x0c: return _registers.peripheral_control; + case 0xb: return _registers.auxiliary_control; + case 0xc: return _registers.peripheral_control; - case 0x0d: return _registers.interrupt_flags | (get_interrupt_line() ? 0x80 : 0x00); - case 0x0e: return _registers.interrupt_enable | 0x80; + case 0xd: return _registers.interrupt_flags | (get_interrupt_line() ? 0x80 : 0x00); + case 0xe: return _registers.interrupt_enable | 0x80; } return 0xff; diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 816a10392..c40dffdfb 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -51,9 +51,15 @@ class KeyboardVIA: public MOS::MOS6522 { public: void set_key_state(Key key, bool isPressed) { if(isPressed) + { _columns[key & 7] &= ~(key >> 3); +// printf("!!!\n"); + } else + { _columns[key & 7] |= (key >> 3); +// printf("???\n"); + } } // to satisfy MOS::MOS6522 @@ -76,7 +82,7 @@ class KeyboardVIA: public MOS::MOS6522 { void set_port_output(int port, uint8_t value) { if(port) _activation_mask = value; -// printf("%d <= %02x\n", port, value); +// printf("<- %02x\n", port, value); } KeyboardVIA() : _columns{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} {} diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index 250145a7e..abfa85603 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -71,8 +71,8 @@ case VK_ANSI_G: _vic20.set_key_state(Vic20::Key::KeyG, isPressed); break; case VK_ANSI_H: _vic20.set_key_state(Vic20::Key::KeyH, isPressed); break; case VK_ANSI_J: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; - case VK_ANSI_K: _vic20.set_key_state(Vic20::Key::KeyO, isPressed); break; - case VK_ANSI_L: _vic20.set_key_state(Vic20::Key::KeyP, isPressed); break; + case VK_ANSI_K: _vic20.set_key_state(Vic20::Key::KeyK, isPressed); break; + case VK_ANSI_L: _vic20.set_key_state(Vic20::Key::KeyL, isPressed); break; case VK_ANSI_Z: _vic20.set_key_state(Vic20::Key::KeyZ, isPressed); break; case VK_ANSI_X: _vic20.set_key_state(Vic20::Key::KeyX, isPressed); break; From 3e8d383615e720fc06c58463a208cef0727fac94 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 13:19:59 -0400 Subject: [PATCH 39/66] Improved key map. Possibly enough to type some basic BASIC? --- Machines/Vic-20/Vic20.hpp | 2 +- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 49 ++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index c40dffdfb..715ac228e 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -41,7 +41,7 @@ enum Key: uint16_t { KeyLeft = key(1, 0x01), KeyW = key(1, 0x02), KeyR = key(1, 0x04), KeyY = key(1, 0x08), KeyI = key(1, 0x10), KeyP = key(1, 0x20), KeyAsterisk = key(1, 0x40), KeyReturn = key(1, 0x80), Key1 = key(0, 0x01), Key3 = key(0, 0x02), Key5 = key(0, 0x04), Key7 = key(0, 0x08), - Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDel = key(0, 0x80), + Key9 = key(0, 0x10), KeyPlus = key(0, 0x20), KeyGBP = key(0, 0x40), KeyDelete = key(0, 0x80), }; class UserPortVIA: public MOS::MOS6522 { diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index abfa85603..ccc4d6b6a 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -63,7 +63,6 @@ case VK_ANSI_I: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; case VK_ANSI_O: _vic20.set_key_state(Vic20::Key::KeyO, isPressed); break; case VK_ANSI_P: _vic20.set_key_state(Vic20::Key::KeyP, isPressed); break; - case VK_ANSI_A: _vic20.set_key_state(Vic20::Key::KeyA, isPressed); break; case VK_ANSI_S: _vic20.set_key_state(Vic20::Key::KeyS, isPressed); break; case VK_ANSI_D: _vic20.set_key_state(Vic20::Key::KeyD, isPressed); break; @@ -73,7 +72,6 @@ case VK_ANSI_J: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; case VK_ANSI_K: _vic20.set_key_state(Vic20::Key::KeyK, isPressed); break; case VK_ANSI_L: _vic20.set_key_state(Vic20::Key::KeyL, isPressed); break; - case VK_ANSI_Z: _vic20.set_key_state(Vic20::Key::KeyZ, isPressed); break; case VK_ANSI_X: _vic20.set_key_state(Vic20::Key::KeyX, isPressed); break; case VK_ANSI_C: _vic20.set_key_state(Vic20::Key::KeyC, isPressed); break; @@ -81,10 +79,57 @@ case VK_ANSI_B: _vic20.set_key_state(Vic20::Key::KeyB, isPressed); break; case VK_ANSI_N: _vic20.set_key_state(Vic20::Key::KeyN, isPressed); break; case VK_ANSI_M: _vic20.set_key_state(Vic20::Key::KeyM, isPressed); break; + + case VK_Space: _vic20.set_key_state(Vic20::Key::KeySpace, isPressed); break; + case VK_Return: _vic20.set_key_state(Vic20::Key::KeyReturn, isPressed); break; + case VK_Delete: _vic20.set_key_state(Vic20::Key::KeyDelete, isPressed); break; + + case VK_ANSI_Comma: _vic20.set_key_state(Vic20::Key::KeyComma, isPressed); break; + case VK_ANSI_Period: _vic20.set_key_state(Vic20::Key::KeyFullStop, isPressed); break; + + case VK_ANSI_Minus: _vic20.set_key_state(Vic20::Key::KeyDash, isPressed); break; + case VK_ANSI_Equal: _vic20.set_key_state(Vic20::Key::KeyEquals, isPressed); break; + + case VK_ANSI_Semicolon: _vic20.set_key_state(Vic20::Key::KeyColon, isPressed); break; + case VK_ANSI_Quote: _vic20.set_key_state(Vic20::Key::KeySemicolon, isPressed); break; + + case VK_ANSI_Slash: _vic20.set_key_state(Vic20::Key::KeySlash, isPressed); break; + + case VK_Shift: + // Yuck + _vic20.set_key_state(Vic20::Key::KeyLShift, isPressed); + _vic20.set_key_state(Vic20::Key::KeyRShift, isPressed); + break; + + case VK_Option: + _vic20.set_key_state(Vic20::Key::KeyCBM, isPressed); + break; + + case VK_Control: + _vic20.set_key_state(Vic20::Key::KeyControl, isPressed); + break; + +// default: printf("%02x\n", key); break; } } } +// Not yet mapped: +// KeyHome +// KeyF7 +// KeyAt +// KeyUp +// KeyF5 +// KeyF3 +// KeyF1 +// KeyRunStop +// KeyDown +// KeyRight +// KeyLeft +// KeyAsterisk +// KeyPlus +// KeyGBP + - (void)clearAllKeys { } From d9b001d3fc58236d5e88446c6e461a5f9b2d7878 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 13:51:04 -0400 Subject: [PATCH 40/66] Minor clean-ups. --- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 104 +++++++----------- 1 file changed, 42 insertions(+), 62 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index ccc4d6b6a..d5227614e 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -39,77 +39,57 @@ } - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { + static NSDictionary *vicKeysByKeys = @{ + @(VK_ANSI_1): @(Vic20::Key::Key1), @(VK_ANSI_2): @(Vic20::Key::Key2), + @(VK_ANSI_3): @(Vic20::Key::Key3), @(VK_ANSI_4): @(Vic20::Key::Key4), + @(VK_ANSI_5): @(Vic20::Key::Key5), @(VK_ANSI_6): @(Vic20::Key::Key6), + @(VK_ANSI_7): @(Vic20::Key::Key7), @(VK_ANSI_8): @(Vic20::Key::Key8), + @(VK_ANSI_9): @(Vic20::Key::Key9), @(VK_ANSI_0): @(Vic20::Key::Key0), + + @(VK_ANSI_Q): @(Vic20::Key::KeyQ), @(VK_ANSI_W): @(Vic20::Key::KeyW), + @(VK_ANSI_E): @(Vic20::Key::KeyE), @(VK_ANSI_R): @(Vic20::Key::KeyR), + @(VK_ANSI_T): @(Vic20::Key::KeyT), @(VK_ANSI_Y): @(Vic20::Key::KeyY), + @(VK_ANSI_U): @(Vic20::Key::KeyU), @(VK_ANSI_I): @(Vic20::Key::KeyI), + @(VK_ANSI_O): @(Vic20::Key::KeyO), @(VK_ANSI_P): @(Vic20::Key::KeyP), + @(VK_ANSI_A): @(Vic20::Key::KeyA), @(VK_ANSI_S): @(Vic20::Key::KeyS), + @(VK_ANSI_D): @(Vic20::Key::KeyD), @(VK_ANSI_F): @(Vic20::Key::KeyF), + @(VK_ANSI_G): @(Vic20::Key::KeyG), @(VK_ANSI_H): @(Vic20::Key::KeyH), + @(VK_ANSI_J): @(Vic20::Key::KeyJ), @(VK_ANSI_K): @(Vic20::Key::KeyK), + @(VK_ANSI_L): @(Vic20::Key::KeyL), @(VK_ANSI_Z): @(Vic20::Key::KeyZ), + @(VK_ANSI_X): @(Vic20::Key::KeyX), @(VK_ANSI_C): @(Vic20::Key::KeyC), + @(VK_ANSI_V): @(Vic20::Key::KeyV), @(VK_ANSI_B): @(Vic20::Key::KeyB), + @(VK_ANSI_N): @(Vic20::Key::KeyN), @(VK_ANSI_M): @(Vic20::Key::KeyM), + + @(VK_Space): @(Vic20::Key::KeySpace), + @(VK_Return): @(Vic20::Key::KeyReturn), + @(VK_Delete): @(Vic20::Key::KeyDelete), + @(VK_ANSI_Comma): @(Vic20::Key::KeyComma), + @(VK_ANSI_Period): @(Vic20::Key::KeyFullStop), + @(VK_ANSI_Minus): @(Vic20::Key::KeyDash), + @(VK_ANSI_Equal): @(Vic20::Key::KeyEquals), + @(VK_ANSI_Semicolon): @(Vic20::Key::KeyColon), + @(VK_ANSI_Quote): @(Vic20::Key::KeySemicolon), + @(VK_ANSI_Slash): @(Vic20::Key::KeySlash), + @(VK_Option): @(Vic20::Key::KeyCBM), + @(VK_Control): @(Vic20::Key::KeyControl), + }; + @synchronized(self) { switch(key) { - case VK_ANSI_1: _vic20.set_key_state(Vic20::Key::Key1, isPressed); break; - case VK_ANSI_2: _vic20.set_key_state(Vic20::Key::Key2, isPressed); break; - case VK_ANSI_3: _vic20.set_key_state(Vic20::Key::Key3, isPressed); break; - case VK_ANSI_4: _vic20.set_key_state(Vic20::Key::Key4, isPressed); break; - case VK_ANSI_5: _vic20.set_key_state(Vic20::Key::Key5, isPressed); break; - case VK_ANSI_6: _vic20.set_key_state(Vic20::Key::Key6, isPressed); break; - case VK_ANSI_7: _vic20.set_key_state(Vic20::Key::Key7, isPressed); break; - case VK_ANSI_8: _vic20.set_key_state(Vic20::Key::Key8, isPressed); break; - case VK_ANSI_9: _vic20.set_key_state(Vic20::Key::Key9, isPressed); break; - case VK_ANSI_0: _vic20.set_key_state(Vic20::Key::Key0, isPressed); break; - - case VK_ANSI_Q: _vic20.set_key_state(Vic20::Key::KeyQ, isPressed); break; - case VK_ANSI_W: _vic20.set_key_state(Vic20::Key::KeyW, isPressed); break; - case VK_ANSI_E: _vic20.set_key_state(Vic20::Key::KeyE, isPressed); break; - case VK_ANSI_R: _vic20.set_key_state(Vic20::Key::KeyR, isPressed); break; - case VK_ANSI_T: _vic20.set_key_state(Vic20::Key::KeyT, isPressed); break; - case VK_ANSI_Y: _vic20.set_key_state(Vic20::Key::KeyY, isPressed); break; - case VK_ANSI_U: _vic20.set_key_state(Vic20::Key::KeyU, isPressed); break; - case VK_ANSI_I: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; - case VK_ANSI_O: _vic20.set_key_state(Vic20::Key::KeyO, isPressed); break; - case VK_ANSI_P: _vic20.set_key_state(Vic20::Key::KeyP, isPressed); break; - case VK_ANSI_A: _vic20.set_key_state(Vic20::Key::KeyA, isPressed); break; - case VK_ANSI_S: _vic20.set_key_state(Vic20::Key::KeyS, isPressed); break; - case VK_ANSI_D: _vic20.set_key_state(Vic20::Key::KeyD, isPressed); break; - case VK_ANSI_F: _vic20.set_key_state(Vic20::Key::KeyF, isPressed); break; - case VK_ANSI_G: _vic20.set_key_state(Vic20::Key::KeyG, isPressed); break; - case VK_ANSI_H: _vic20.set_key_state(Vic20::Key::KeyH, isPressed); break; - case VK_ANSI_J: _vic20.set_key_state(Vic20::Key::KeyI, isPressed); break; - case VK_ANSI_K: _vic20.set_key_state(Vic20::Key::KeyK, isPressed); break; - case VK_ANSI_L: _vic20.set_key_state(Vic20::Key::KeyL, isPressed); break; - case VK_ANSI_Z: _vic20.set_key_state(Vic20::Key::KeyZ, isPressed); break; - case VK_ANSI_X: _vic20.set_key_state(Vic20::Key::KeyX, isPressed); break; - case VK_ANSI_C: _vic20.set_key_state(Vic20::Key::KeyC, isPressed); break; - case VK_ANSI_V: _vic20.set_key_state(Vic20::Key::KeyV, isPressed); break; - case VK_ANSI_B: _vic20.set_key_state(Vic20::Key::KeyB, isPressed); break; - case VK_ANSI_N: _vic20.set_key_state(Vic20::Key::KeyN, isPressed); break; - case VK_ANSI_M: _vic20.set_key_state(Vic20::Key::KeyM, isPressed); break; - - case VK_Space: _vic20.set_key_state(Vic20::Key::KeySpace, isPressed); break; - case VK_Return: _vic20.set_key_state(Vic20::Key::KeyReturn, isPressed); break; - case VK_Delete: _vic20.set_key_state(Vic20::Key::KeyDelete, isPressed); break; - - case VK_ANSI_Comma: _vic20.set_key_state(Vic20::Key::KeyComma, isPressed); break; - case VK_ANSI_Period: _vic20.set_key_state(Vic20::Key::KeyFullStop, isPressed); break; - - case VK_ANSI_Minus: _vic20.set_key_state(Vic20::Key::KeyDash, isPressed); break; - case VK_ANSI_Equal: _vic20.set_key_state(Vic20::Key::KeyEquals, isPressed); break; - - case VK_ANSI_Semicolon: _vic20.set_key_state(Vic20::Key::KeyColon, isPressed); break; - case VK_ANSI_Quote: _vic20.set_key_state(Vic20::Key::KeySemicolon, isPressed); break; - - case VK_ANSI_Slash: _vic20.set_key_state(Vic20::Key::KeySlash, isPressed); break; + default: { + NSNumber *targetKey = vicKeysByKeys[@(key)]; + if(targetKey) + { + _vic20.set_key_state((Vic20::Key)targetKey.integerValue, isPressed); + } + } break; case VK_Shift: // Yuck _vic20.set_key_state(Vic20::Key::KeyLShift, isPressed); _vic20.set_key_state(Vic20::Key::KeyRShift, isPressed); break; - - case VK_Option: - _vic20.set_key_state(Vic20::Key::KeyCBM, isPressed); - break; - - case VK_Control: - _vic20.set_key_state(Vic20::Key::KeyControl, isPressed); - break; - -// default: printf("%02x\n", key); break; } } } From 167ed9b8bbd1e82c7851b8417fae7a1a04b95d8b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 11 Jun 2016 14:00:12 -0400 Subject: [PATCH 41/66] Added enough to load a PRG as a ROM. --- Machines/Vic-20/Vic20.cpp | 15 ++++++++++++++- Machines/Vic-20/Vic20.hpp | 5 +++++ OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 313330df2..a9088de17 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -14,13 +14,19 @@ using namespace Vic20; Machine::Machine() : _userPortVIA(new UserPortVIA()), - _keyboardVIA(new KeyboardVIA()) + _keyboardVIA(new KeyboardVIA()), + _rom(nullptr) { _userPortVIA->set_delegate(this); _keyboardVIA->set_delegate(this); set_reset_line(true); } +Machine::~Machine() +{ + delete[] _rom; +} + unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value) { set_reset_line(false); @@ -115,4 +121,11 @@ void Machine::set_rom(ROMSlot slot, size_t length, const uint8_t *data) void Machine::add_prg(size_t length, const uint8_t *data) { + if(length > 2) + { + _rom_address = (uint16_t)(data[0] | (data[1] << 8)); + _rom_length = (uint16_t)(length - 2); + _rom = new uint8_t[length - 2]; + memcpy(_rom, &data[2], length - 2); + } } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 715ac228e..3d62adc20 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -94,6 +94,7 @@ class KeyboardVIA: public MOS::MOS6522 { class Machine: public CPU6502::Processor, public CRTMachine::Machine, public MOS::MOS6522Delegate { public: Machine(); + ~Machine(); void set_rom(ROMSlot slot, size_t length, const uint8_t *data); void add_prg(size_t length, const uint8_t *data); @@ -118,6 +119,9 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p uint8_t _basicROM[0x2000]; uint8_t _kernelROM[0x2000]; + uint8_t *_rom; + uint16_t _rom_address, _rom_length; + uint8_t _userBASICMemory[0x0400]; uint8_t _screenMemory[0x1000]; uint8_t _colorMemory[0x0400]; @@ -135,6 +139,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p else if(address >= 0x8000 && address < 0x9000) return _characterROM[address&0x0fff]; else if(address >= 0xc000 && address < 0xe000) return _basicROM[address&0x1fff]; else if(address >= 0xe000) return _kernelROM[address&0x1fff]; + else if(address >= _rom_address && address < _rom_address+_rom_length) return _rom[address - _rom_address]; return 0xff; } diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index d5227614e..6354cfd16 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -83,6 +83,8 @@ { _vic20.set_key_state((Vic20::Key)targetKey.integerValue, isPressed); } + else + NSLog(@"Unmapped: %02x", key); } break; case VK_Shift: From ec604f1414394d8f94f5021f00cd5a46e7f48aaa Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 10:35:47 -0400 Subject: [PATCH 42/66] Expanded mapped keys just a tiny bit further. --- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index 6354cfd16..ebcdfbfeb 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -72,6 +72,18 @@ @(VK_ANSI_Slash): @(Vic20::Key::KeySlash), @(VK_Option): @(Vic20::Key::KeyCBM), @(VK_Control): @(Vic20::Key::KeyControl), + + @(VK_F1): @(Vic20::Key::KeyF1), @(VK_F3): @(Vic20::Key::KeyF3), + @(VK_F5): @(Vic20::Key::KeyF5), @(VK_F7): @(Vic20::Key::KeyF7), + + @(VK_ANSI_Grave): @(Vic20::Key::KeyLeft), + @(VK_Tab): @(Vic20::Key::KeyRunStop), + @(VK_ANSI_LeftBracket): @(Vic20::Key::KeyAt), + @(VK_ANSI_RightBracket): @(Vic20::Key::KeyAsterisk), + @(VK_ANSI_Backslash): @(Vic20::Key::KeyUp), + + @(VK_RightArrow): @(Vic20::Key::KeyRight), + @(VK_DownArrow): @(Vic20::Key::KeyDown), }; @synchronized(self) { @@ -98,17 +110,6 @@ // Not yet mapped: // KeyHome -// KeyF7 -// KeyAt -// KeyUp -// KeyF5 -// KeyF3 -// KeyF1 -// KeyRunStop -// KeyDown -// KeyRight -// KeyLeft -// KeyAsterisk // KeyPlus // KeyGBP From 4fec625b1904942a00dec2059b572d297f15ad51 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 10:38:21 -0400 Subject: [PATCH 43/66] Minor cleaning, implemented `clearAllKeys`. --- Machines/Vic-20/Vic20.hpp | 18 ++++++++---------- .../Mac/Clock Signal/Wrappers/CSVic20.mm | 13 ++++++++----- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 3d62adc20..47dcb71df 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -51,15 +51,13 @@ class KeyboardVIA: public MOS::MOS6522 { public: void set_key_state(Key key, bool isPressed) { if(isPressed) - { _columns[key & 7] &= ~(key >> 3); -// printf("!!!\n"); - } else - { _columns[key & 7] |= (key >> 3); -// printf("???\n"); - } + } + + void clear_all_keys() { + memset(_columns, 0xff, sizeof(_columns)); } // to satisfy MOS::MOS6522 @@ -71,8 +69,6 @@ class KeyboardVIA: public MOS::MOS6522 { if(!(_activation_mask&(1 << c))) result &= _columns[c]; } -// if(_activation_mask) -// printf("%02x => %02x\n", _activation_mask, result); return result; } @@ -82,10 +78,11 @@ class KeyboardVIA: public MOS::MOS6522 { void set_port_output(int port, uint8_t value) { if(port) _activation_mask = value; -// printf("<- %02x\n", port, value); } - KeyboardVIA() : _columns{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} {} + KeyboardVIA() { + clear_all_keys(); + } private: uint8_t _columns[8]; uint8_t _activation_mask; @@ -99,6 +96,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p void set_rom(ROMSlot slot, size_t length, const uint8_t *data); void add_prg(size_t length, const uint8_t *data); void set_key_state(Key key, bool isPressed) { _keyboardVIA->set_key_state(key, isPressed); } + void clear_all_keys() { _keyboardVIA->clear_all_keys(); } // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm index ebcdfbfeb..cd5a0c18f 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSVic20.mm @@ -86,6 +86,11 @@ @(VK_DownArrow): @(Vic20::Key::KeyDown), }; + // Not yet mapped: + // KeyHome + // KeyPlus + // KeyGBP + @synchronized(self) { switch(key) { @@ -108,12 +113,10 @@ } } -// Not yet mapped: -// KeyHome -// KeyPlus -// KeyGBP - - (void)clearAllKeys { + @synchronized(self) { + _vic20.clear_all_keys(); + } } @end From 19b2f4648851adc9e7dc31e3e0a6c9f417e5a2a2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 11:06:19 -0400 Subject: [PATCH 44/66] Fixed accesses to colour memory. --- Machines/Vic-20/Vic20.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 47dcb71df..865229b38 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -127,7 +127,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p inline uint8_t *ram_pointer(uint16_t address) { if(address < sizeof(_userBASICMemory)) return &_userBASICMemory[address]; if(address >= 0x1000 && address < 0x2000) return &_screenMemory[address&0x0fff]; - if(address >= 0x9400 && address < 0x9800) return &_colorMemory[0x03ff]; // TODO: make this 4-bit + if(address >= 0x9400 && address < 0x9800) return &_colorMemory[address&0x03ff]; // TODO: make this 4-bit return nullptr; } From ed76e36b187dd32a543a6985ad7e94ca248db7b8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 11:23:57 -0400 Subject: [PATCH 45/66] Made basic attempt at 16-line character mode. --- Components/6560/6560.cpp | 8 ++++---- Components/6560/6560.hpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 29054d0d6..2e2ed8917 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -83,7 +83,7 @@ void MOS6560::set_register(int address, uint8_t value) case 0x3: _number_of_rows = (value >> 1)&0x3f; - _wide_characters = !!(value&0x01); + _tall_characters = !!(value&0x01); break; case 0x5: @@ -151,7 +151,7 @@ uint16_t MOS6560::get_address() if(_row_counter >= 0) { _row_counter++; - if(_row_counter == _number_of_rows*8) _row_counter = -1; + if(_row_counter == _number_of_rows*(_tall_characters ? 16 : 8)) _row_counter = -1; } else if(_vertical_counter == _first_row_location * 2) { @@ -166,7 +166,7 @@ uint16_t MOS6560::get_address() if(_column_counter == _number_of_columns*2) { _column_counter = -1; - if((_row_counter&7) == 7) + if((_row_counter&(_tall_characters ? 15 : 7)) == (_tall_characters ? 15 : 7)) { _video_matrix_line_address_counter = _video_matrix_address_counter; } @@ -226,7 +226,7 @@ uint16_t MOS6560::get_address() */ if(_column_counter&1) { - return _character_cell_start_address + (_character_code*8) + (_row_counter&7); + return _character_cell_start_address + (_character_code*(_tall_characters ? 16 : 8)) + (_row_counter&(_tall_characters ? 15 : 7)); } else { diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 21a7da4f3..be8f856df 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -27,7 +27,7 @@ class MOS6560 { private: std::unique_ptr _crt; - bool _interlaced, _wide_characters; + bool _interlaced, _tall_characters; uint8_t _first_column_location, _first_row_location; uint8_t _number_of_columns, _number_of_rows; uint16_t _character_cell_start_address, _video_matrix_start_address; From 2992183aaeb950ae9c5a4786d1dec2de562663dd Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 14:39:17 -0400 Subject: [PATCH 46/66] Switched to a lookup table for phase, temporarily in YUV colour space, probably. Working on it. --- Components/6560/6560.cpp | 14 ++++++++++++-- Outputs/CRT/Internals/CRTOpenGL.cpp | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 2e2ed8917..7d4063a6d 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -43,18 +43,28 @@ using namespace MOS; */ MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YIQ, 228, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists + _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YUV, 228, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists _horizontal_counter(0), _vertical_counter(0) { _crt->set_composite_sampling_function( + "float angles[8] = float[](" + "2.356194490192345," // orange + "2.748893571891069," // light yellow + "1.963495408493621," // red + "5.105088062083414," // cyan + "0.785398163397448," // purple + "3.926990816987241," // green + "0.0," // blue + "3.141592653589793" // yellow + ");" "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "{" "uint c = texture(texID, coordinate).r;" "float y = 0.75 + (float(c & 8u) / 8.0) * 0.25 * step(1, c);" "uint iPhase = c & 7u;" - "float phaseOffset = 6.283185308 * float(iPhase + 8u) / 8.0;" // TODO: appropriate phaseOffset + "float phaseOffset = angles[iPhase];" // sin(phase + phaseOffset) "return mix(step(1, c) * y, step(2, c) * step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0 - 1.0, amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index e01ea78a5..1d888974f 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -334,6 +334,7 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out glActiveTexture(pixel_accumulation_texture_unit); framebuffer->bind_texture(); +// compositeTexture->bind_texture(); framebuffer->draw((float)output_width / (float)output_height); _fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); From 8abf39520268b6afc207a2ddf67776657f3a133c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 14:57:24 -0400 Subject: [PATCH 47/66] Experimented with table-based GLSL lookups, and a sine curve. Now _exceedingly_ slow, but colours are correct if I pretend I'm in the YUV colour space. --- Components/6560/6560.cpp | 47 +++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 7d4063a6d..e63bf47e2 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -48,26 +48,53 @@ MOS6560::MOS6560() : _vertical_counter(0) { _crt->set_composite_sampling_function( - "float angles[8] = float[](" - "2.356194490192345," // orange - "2.748893571891069," // light yellow + "float angles[16] = float[](" + "0.0," // black + "0.0," // white "1.963495408493621," // red "5.105088062083414," // cyan "0.785398163397448," // purple "3.926990816987241," // green "0.0," // blue - "3.141592653589793" // yellow + "3.141592653589793," // yellow + + "2.356194490192345," // orange + "2.748893571891069," // light yellow + "1.963495408493621," // light red + "5.105088062083414," // light cyan + "0.785398163397448," // light purple + "3.926990816987241," // light green + "0.0," // light blue + "3.141592653589793" // light yellow + ");" + "float brightnesses[16] = float[](" + "0.0 / 255.0," + "255.0 / 255.0," + "79.6875 / 255.0," + "159.375 / 255.0," + "95.625 / 255.0," + "127.5 / 255.0," + "63.75 / 255.0," + "191.25 / 255.0," + + "95.625 / 255.0," + "63.75 / 255.0," + "127.5 / 255.0," + "189.375 / 255.0," + "135.625 / 255.0," + "191.25 / 255.0," + "119.53125 / 255.0," + "159.375 / 255.0" ");" "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "{" "uint c = texture(texID, coordinate).r;" - "float y = 0.75 + (float(c & 8u) / 8.0) * 0.25 * step(1, c);" + "float y = brightnesses[c];" + "float phaseOffset = angles[c];" - "uint iPhase = c & 7u;" - "float phaseOffset = angles[iPhase];" - - // sin(phase + phaseOffset) - "return mix(step(1, c) * y, step(2, c) * step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0 - 1.0, amplitude);" // TODO: square wave (step(3.141592654, mod(phase + phaseOffset, 6.283185308))?) +// "float chroma = step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0 - 1.0;" + "float chroma = cos(phase + phaseOffset);" + "return mix(y, chroma, amplitude);" "}"); } From 1a2b18f93b569ebf1abbc83d14b7d4dfea97c9e2 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 17:27:57 -0400 Subject: [PATCH 48/66] Steps towards CPU mapping; diagnostic. --- Components/6560/6560.cpp | 50 +++++----------------------------------- Components/6560/6560.hpp | 1 + 2 files changed, 7 insertions(+), 44 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index e63bf47e2..b454e8227 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -48,49 +48,11 @@ MOS6560::MOS6560() : _vertical_counter(0) { _crt->set_composite_sampling_function( - "float angles[16] = float[](" - "0.0," // black - "0.0," // white - "1.963495408493621," // red - "5.105088062083414," // cyan - "0.785398163397448," // purple - "3.926990816987241," // green - "0.0," // blue - "3.141592653589793," // yellow - - "2.356194490192345," // orange - "2.748893571891069," // light yellow - "1.963495408493621," // light red - "5.105088062083414," // light cyan - "0.785398163397448," // light purple - "3.926990816987241," // light green - "0.0," // light blue - "3.141592653589793" // light yellow - ");" - "float brightnesses[16] = float[](" - "0.0 / 255.0," - "255.0 / 255.0," - "79.6875 / 255.0," - "159.375 / 255.0," - "95.625 / 255.0," - "127.5 / 255.0," - "63.75 / 255.0," - "191.25 / 255.0," - - "95.625 / 255.0," - "63.75 / 255.0," - "127.5 / 255.0," - "189.375 / 255.0," - "135.625 / 255.0," - "191.25 / 255.0," - "119.53125 / 255.0," - "159.375 / 255.0" - ");" "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" "{" "uint c = texture(texID, coordinate).r;" - "float y = brightnesses[c];" - "float phaseOffset = angles[c];" + "float y = float(c >> 4) / 4.0;" + "float phaseOffset = float(c & 15u) / 16.0;" // "float chroma = step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0 - 1.0;" "float chroma = cos(phase + phaseOffset);" @@ -129,7 +91,7 @@ void MOS6560::set_register(int address, uint8_t value) break; case 0xe: - _auxiliary_colour = value >> 4; + _auxiliary_colour = _colours[value >> 4]; // TODO: sound amplitude break; @@ -140,8 +102,8 @@ void MOS6560::set_register(int address, uint8_t value) _cycles_in_state = 0; } _invertedCells = !!((value >> 3)&1); - _borderColour = value & 0x07; - _backgroundColour = value >> 4; + _borderColour = _colours[value & 0x07]; + _backgroundColour = _colours[value >> 4]; break; // TODO: audio, primarily @@ -290,7 +252,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) if(pixel_pointer) { - uint8_t cell_colour = _character_colour & 0x7; + uint8_t cell_colour = _colours[_character_colour & 0x7]; if(!(_character_colour&0x8)) { pixel_pointer[0] = ((_character_value >> 7)&1) ? cell_colour : _backgroundColour; diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index be8f856df..9b5134bd9 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -49,6 +49,7 @@ class MOS6560 { uint8_t *pixel_pointer; uint8_t _registers[16]; + uint8_t _colours[16]; void output_border(unsigned int number_of_cycles); }; From 580c8bdcbdebc87c646edab8072314e271672d73 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 17:29:44 -0400 Subject: [PATCH 49/66] Ported rest. --- Components/6560/6560.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index b454e8227..8cf4dca9b 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -58,6 +58,27 @@ MOS6560::MOS6560() : "float chroma = cos(phase + phaseOffset);" "return mix(y, chroma, amplitude);" "}"); + + // set up colours table + // 0 + // 2, 6, 9, B, + // 4, 5, 8, A, C, E + // 3, 7, D, F + // 1 + uint8_t luminances[16] = { // range is 0–4 + 0, 4, 1, 3, + 2, 2, 1, 3, + 2, 1, 2, 1, + 2, 3, 2, 3 + }; + uint8_t chrominances[16] = { // range is 0–15 + 0, 0, 5, 13, 2, 10, 0, 8, + 6, 7, 5, 13, 2, 10, 0, 8, + }; + for(int c = 0; c < 16; c++) + { + _colours[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]); + } } void MOS6560::set_register(int address, uint8_t value) From 6b5a3229186e4f664c05e6ce3f23d4c4ee9d5878 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 17:41:52 -0400 Subject: [PATCH 50/66] Fixed all colours, plus special case no-chroma for black and white. --- Components/6560/6560.cpp | 43 ++++++---------------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 8cf4dca9b..ff64c9c7e 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -10,38 +10,6 @@ using namespace MOS; -/* - 0 - 0000 Black - 1 - 0001 White - 2 - 0010 Red - 3 - 0011 Cyan - 4 - 0100 Purple - 5 - 0101 Green - 6 - 0110 Blue - 7 - 0111 Yellow - - 8 - 1000 Orange - 9 - 1001 Light orange - 10 - 1010 Pink - 11 - 1011 Light cyan - 12 - 1100 Light purple - 13 - 1101 Light green - 14 - 1110 Light blue - 15 - 1111 Light yellow -*/ - -/* - 0 -> purple - 1 -> purple - 2 -> browny yellow - 3 -> browny red - 4 -> purple - 5 -> purple - 6 -> cyan - 7 -> green - 8 -> green -*/ - MOS6560::MOS6560() : _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YUV, 228, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists _horizontal_counter(0), @@ -52,10 +20,11 @@ MOS6560::MOS6560() : "{" "uint c = texture(texID, coordinate).r;" "float y = float(c >> 4) / 4.0;" - "float phaseOffset = float(c & 15u) / 16.0;" + "uint yC = c & 15u;" + "float phaseOffset = 6.283185308 * float(yC) / 16.0;" -// "float chroma = step(3.141592654, mod(phase + phaseOffset, 6.283185308)) * 2.0 - 1.0;" - "float chroma = cos(phase + phaseOffset);" +// "float chroma = 2.0*step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654) - 1.0;" + "float chroma = step(yC, 15) * cos(phase + phaseOffset);" "return mix(y, chroma, amplitude);" "}"); @@ -71,8 +40,8 @@ MOS6560::MOS6560() : 2, 1, 2, 1, 2, 3, 2, 3 }; - uint8_t chrominances[16] = { // range is 0–15 - 0, 0, 5, 13, 2, 10, 0, 8, + uint8_t chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" + 15, 15, 5, 13, 2, 10, 0, 8, 6, 7, 5, 13, 2, 10, 0, 8, }; for(int c = 0; c < 16; c++) From 4c2b964cd40c1be5fb7ff5b388569e8823edef9b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 17:45:25 -0400 Subject: [PATCH 51/66] Added NTSC-VIC's switching of phase every field. --- Components/6560/6560.cpp | 3 ++- Components/6560/6560.hpp | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index ff64c9c7e..8db86e8d8 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -133,6 +133,7 @@ uint16_t MOS6560::get_address() if(_vertical_counter == 261) { + _frame_colour_burst_phase ^= 128; _vertical_counter = 0; _row_counter = -1; } @@ -181,7 +182,7 @@ uint16_t MOS6560::get_address() switch(_output_state) { case State::Sync: _crt->output_sync(_cycles_in_state * 4); break; - case State::ColourBurst: _crt->output_colour_burst(_cycles_in_state * 4, 0, 0); break; + case State::ColourBurst: _crt->output_colour_burst(_cycles_in_state * 4, _frame_colour_burst_phase, 0); break; case State::Border: output_border(_cycles_in_state * 4); break; case State::Pixels: _crt->output_data(_cycles_in_state * 4, 1); break; } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 9b5134bd9..04b894d0c 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -51,6 +51,8 @@ class MOS6560 { uint8_t _registers[16]; uint8_t _colours[16]; + uint8_t _frame_colour_burst_phase; + void output_border(unsigned int number_of_cycles); }; From a5efa7543a81b5951ebde65360d4964d4fab8d97 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 17:57:52 -0400 Subject: [PATCH 52/66] Added vertical sync, switching fully to the normal NTSC colour space. --- Components/6560/6560.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 8db86e8d8..162c65964 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -11,7 +11,7 @@ using namespace MOS; MOS6560::MOS6560() : - _crt(new Outputs::CRT::CRT(65*4, 4, 261, Outputs::CRT::ColourSpace::YUV, 228, 1, 1)), // TODO: turn 261 back into 263 once vertical sync exists + _crt(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)), _horizontal_counter(0), _vertical_counter(0) { @@ -24,8 +24,8 @@ MOS6560::MOS6560() : "float phaseOffset = 6.283185308 * float(yC) / 16.0;" // "float chroma = 2.0*step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654) - 1.0;" - "float chroma = step(yC, 15) * cos(phase + phaseOffset);" - "return mix(y, chroma, amplitude);" + "float chroma = cos(phase + phaseOffset);" + "return mix(y, step(yC, 14) * chroma, amplitude);" "}"); // set up colours table @@ -40,13 +40,17 @@ MOS6560::MOS6560() : 2, 1, 2, 1, 2, 3, 2, 3 }; - uint8_t chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" - 15, 15, 5, 13, 2, 10, 0, 8, - 6, 7, 5, 13, 2, 10, 0, 8, +// uint8_t pal_chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" +// 15, 15, 5, 13, 2, 10, 0, 8, +// 6, 7, 5, 13, 2, 10, 0, 8, +// }; + uint8_t ntsc_chrominances[16] = { + 15, 15, 2, 10, 4, 12, 6, 14, + 0, 8, 2, 10, 4, 12, 6, 14, }; for(int c = 0; c < 16; c++) { - _colours[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]); + _colours[c] = (uint8_t)((luminances[c] << 4) | ntsc_chrominances[c]); } } @@ -176,6 +180,9 @@ uint16_t MOS6560::get_address() _this_state = (_column_counter >= 0 && _row_counter >= 0) ? State::Pixels : State::Border; } + // apply vertical sync + if(_vertical_counter < 3) _this_state = State::Sync; + // update the CRT if(_this_state != _output_state) { From 4ad55a7f5e6c2faf871b12614d127fb5e16d36ef Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 18:01:38 -0400 Subject: [PATCH 53/66] Trimmed the visible area. --- Components/6560/6560.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 162c65964..8387fd7a3 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -52,6 +52,9 @@ MOS6560::MOS6560() : { _colours[c] = (uint8_t)((luminances[c] << 4) | ntsc_chrominances[c]); } + + // show the middle 90% + _crt->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); } void MOS6560::set_register(int address, uint8_t value) From e10535181d8ef54192ba55f80f18052e6fe06149 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 12 Jun 2016 22:27:58 -0400 Subject: [PATCH 54/66] Made an attempt to implement interlaced video. --- Components/6560/6560.cpp | 24 +++++++++++++++++------- Components/6560/6560.hpp | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 8387fd7a3..219af4325 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -13,7 +13,8 @@ using namespace MOS; MOS6560::MOS6560() : _crt(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)), _horizontal_counter(0), - _vertical_counter(0) + _vertical_counter(0), + _is_odd_frame(false) { _crt->set_composite_sampling_function( "float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)" @@ -140,7 +141,7 @@ uint16_t MOS6560::get_address() if(_vertical_counter == 261) { - _frame_colour_burst_phase ^= 128; + _is_odd_frame ^= true; _vertical_counter = 0; _row_counter = -1; } @@ -184,17 +185,26 @@ uint16_t MOS6560::get_address() } // apply vertical sync - if(_vertical_counter < 3) _this_state = State::Sync; + if( + (_vertical_counter < 3 && (_is_odd_frame || !_interlaced)) || + (_interlaced && + ( + (_vertical_counter == 0 && _horizontal_counter > 32) || + (_vertical_counter == 1) || (_vertical_counter == 2) || + (_vertical_counter == 3 && _horizontal_counter <= 32) + ) + )) + _this_state = State::Sync; // update the CRT if(_this_state != _output_state) { switch(_output_state) { - case State::Sync: _crt->output_sync(_cycles_in_state * 4); break; - case State::ColourBurst: _crt->output_colour_burst(_cycles_in_state * 4, _frame_colour_burst_phase, 0); break; - case State::Border: output_border(_cycles_in_state * 4); break; - case State::Pixels: _crt->output_data(_cycles_in_state * 4, 1); break; + case State::Sync: _crt->output_sync(_cycles_in_state * 4); break; + case State::ColourBurst: _crt->output_colour_burst(_cycles_in_state * 4, _is_odd_frame ? 128 : 0, 0); break; + case State::Border: output_border(_cycles_in_state * 4); break; + case State::Pixels: _crt->output_data(_cycles_in_state * 4, 1); break; } _output_state = _this_state; _cycles_in_state = 0; diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 04b894d0c..6e9fb6d0b 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -51,7 +51,7 @@ class MOS6560 { uint8_t _registers[16]; uint8_t _colours[16]; - uint8_t _frame_colour_burst_phase; + bool _is_odd_frame; void output_border(unsigned int number_of_cycles); }; From 2e946e785f4315d05ad139a3cc38633e8987ef89 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 18:20:21 -0400 Subject: [PATCH 55/66] Settled on half-intensity colour for now, appears likely not to be too incorrect(?) --- Components/6560/6560.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 219af4325..fe6202721 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -24,8 +24,8 @@ MOS6560::MOS6560() : "uint yC = c & 15u;" "float phaseOffset = 6.283185308 * float(yC) / 16.0;" -// "float chroma = 2.0*step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654) - 1.0;" - "float chroma = cos(phase + phaseOffset);" + "float chroma = step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654);" +// "float chroma = cos(phase + phaseOffset);" "return mix(y, step(yC, 14) * chroma, amplitude);" "}"); From 91c406e0658e89255e4a393d0312832ae312c0f9 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 18:21:21 -0400 Subject: [PATCH 56/66] Made an attempt to honour interlaced-frame line counts. --- Components/6560/6560.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index fe6202721..bc478d5fa 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -139,7 +139,7 @@ uint16_t MOS6560::get_address() _vertical_counter++; _column_counter = -1; - if(_vertical_counter == 261) + if(_vertical_counter == _interlaced ? 261 : (_is_odd_frame ? 262 : 263)) { _is_odd_frame ^= true; _vertical_counter = 0; From 4190b42bbb9b517932258dc423b7281789a4aa0c Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 18:27:18 -0400 Subject: [PATCH 57/66] No need for these to live separately, I think. --- Machines/Vic-20/Vic20.cpp | 20 +++++++++----------- Machines/Vic-20/Vic20.hpp | 8 ++++---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index a9088de17..1212c589f 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -13,12 +13,10 @@ using namespace Vic20; Machine::Machine() : - _userPortVIA(new UserPortVIA()), - _keyboardVIA(new KeyboardVIA()), _rom(nullptr) { - _userPortVIA->set_delegate(this); - _keyboardVIA->set_delegate(this); + _userPortVIA.set_delegate(this); + _keyboardVIA.set_delegate(this); set_reset_line(true); } @@ -56,11 +54,11 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } else if((address&0xfff0) == 0x9110) { - *value = _userPortVIA->get_register(address - 0x9110); + *value = _userPortVIA.get_register(address - 0x9110); } else if((address&0xfff0) == 0x9120) { - *value = _keyboardVIA->get_register(address - 0x9120); + *value = _keyboardVIA.get_register(address - 0x9120); } } else @@ -73,16 +71,16 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin } else if((address&0xfff0) == 0x9110) { - _userPortVIA->set_register(address - 0x9110, *value); + _userPortVIA.set_register(address - 0x9110, *value); } else if((address&0xfff0) == 0x9120) { - _keyboardVIA->set_register(address - 0x9120, *value); + _keyboardVIA.set_register(address - 0x9120, *value); } } - _userPortVIA->run_for_cycles(1); - _keyboardVIA->run_for_cycles(1); + _userPortVIA.run_for_cycles(1); + _keyboardVIA.run_for_cycles(1); return 1; } @@ -90,7 +88,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin void Machine::mos6522_did_change_interrupt_status(void *mos6522) { - bool irq = _userPortVIA->get_interrupt_line() || _keyboardVIA->get_interrupt_line(); + bool irq = _userPortVIA.get_interrupt_line() || _keyboardVIA.get_interrupt_line(); set_irq_line(irq); } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 865229b38..06f46f0be 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -95,8 +95,8 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p void set_rom(ROMSlot slot, size_t length, const uint8_t *data); void add_prg(size_t length, const uint8_t *data); - void set_key_state(Key key, bool isPressed) { _keyboardVIA->set_key_state(key, isPressed); } - void clear_all_keys() { _keyboardVIA->clear_all_keys(); } + void set_key_state(Key key, bool isPressed) { _keyboardVIA.set_key_state(key, isPressed); } + void clear_all_keys() { _keyboardVIA.clear_all_keys(); } // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); @@ -142,8 +142,8 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p } std::unique_ptr _mos6560; - std::unique_ptr _userPortVIA; - std::unique_ptr _keyboardVIA; + UserPortVIA _userPortVIA; + KeyboardVIA _keyboardVIA; }; } From fcf4b14344978eddad3a3d9a8ca48dd173881b89 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 19:30:41 -0400 Subject: [PATCH 58/66] Extended to allow floating-point sampling rates. Which makes sense. --- OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h | 4 ++-- OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm | 8 ++++---- Outputs/Speaker.hpp | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h index c91487b7f..332328f1c 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.h @@ -14,8 +14,8 @@ - (void)runForNumberOfCycles:(int)numberOfCycles; -- (int)idealSamplingRateFromRange:(NSRange)range; -- (void)setAudioSamplingRate:(int)samplingRate; +- (float)idealSamplingRateFromRange:(NSRange)range; +- (void)setAudioSamplingRate:(float)samplingRate; - (void)setView:(CSOpenGLView *)view aspectRatio:(float)aspectRatio; - (void)drawViewForPixelSize:(CGSize)pixelSize onlyIfDirty:(BOOL)onlyIfDirty; diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm index e3ba9ada8..188abe561 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm @@ -36,25 +36,25 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate { }]; } -- (int)idealSamplingRateFromRange:(NSRange)range { +- (float)idealSamplingRateFromRange:(NSRange)range { @synchronized(self) { Outputs::Speaker *speaker = self.machine->get_speaker(); if(speaker) { - return speaker->get_ideal_clock_rate_in_range((int)range.location, (int)(range.location + range.length)); + return speaker->get_ideal_clock_rate_in_range((float)range.location, (float)(range.location + range.length)); } return 0; } } -- (void)setAudioSamplingRate:(int)samplingRate { +- (void)setAudioSamplingRate:(float)samplingRate { @synchronized(self) { _speakerDelegate.machine = self; [self setSpeakerDelegate:&_speakerDelegate sampleRate:samplingRate]; } } -- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(int)sampleRate { +- (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(float)sampleRate { @synchronized(self) { Outputs::Speaker *speaker = self.machine->get_speaker(); if(speaker) diff --git a/Outputs/Speaker.hpp b/Outputs/Speaker.hpp index 9742e86df..6cfd434a2 100644 --- a/Outputs/Speaker.hpp +++ b/Outputs/Speaker.hpp @@ -24,7 +24,7 @@ class Speaker { virtual void speaker_did_complete_samples(Speaker *speaker, const int16_t *buffer, int buffer_size) = 0; }; - int get_ideal_clock_rate_in_range(int minimum, int maximum) + float get_ideal_clock_rate_in_range(float minimum, float maximum) { // return exactly the input rate if possible if(_input_cycles_per_second >= minimum && _input_cycles_per_second <= maximum) return _input_cycles_per_second; @@ -36,7 +36,7 @@ class Speaker { return maximum; } - void set_output_rate(int cycles_per_second, int buffer_size) + void set_output_rate(float cycles_per_second, int buffer_size) { _output_cycles_per_second = cycles_per_second; if(_buffer_size != buffer_size) @@ -58,7 +58,7 @@ class Speaker { _delegate = delegate; } - void set_input_rate(int cycles_per_second) + void set_input_rate(float cycles_per_second) { _input_cycles_per_second = cycles_per_second; set_needs_updated_filter_coefficients(); @@ -74,7 +74,7 @@ class Speaker { bool _coefficients_are_dirty; Delegate *_delegate; - int _input_cycles_per_second, _output_cycles_per_second; + float _input_cycles_per_second, _output_cycles_per_second; void set_needs_updated_filter_coefficients() { @@ -181,7 +181,7 @@ template class Filter: public Speaker { } else { - _number_of_taps = (_input_cycles_per_second + _output_cycles_per_second) / _output_cycles_per_second; + _number_of_taps = (int)ceilf((_input_cycles_per_second + _output_cycles_per_second) / _output_cycles_per_second); _number_of_taps *= 2; _number_of_taps |= 1; } @@ -190,7 +190,7 @@ template class Filter: public Speaker { _buffer_in_progress_pointer = 0; _stepper = std::unique_ptr(new SignalProcessing::Stepper((uint64_t)_input_cycles_per_second, (uint64_t)_output_cycles_per_second)); - _filter = std::unique_ptr(new SignalProcessing::FIRFilter((unsigned int)_number_of_taps, (unsigned int)_input_cycles_per_second, 0.0, (float)_output_cycles_per_second / 2.0f, SignalProcessing::FIRFilter::DefaultAttenuation)); + _filter = std::unique_ptr(new SignalProcessing::FIRFilter((unsigned int)_number_of_taps, (float)_input_cycles_per_second, 0.0, (float)_output_cycles_per_second / 2.0f, SignalProcessing::FIRFilter::DefaultAttenuation)); _input_buffer = std::unique_ptr(new int16_t[_number_of_taps]); _input_buffer_depth = 0; From 5fc36b956c92e16d54a66d58628204fdcd6189fe Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 19:30:52 -0400 Subject: [PATCH 59/66] Attempted most basic sketching of a container for Vic audio. --- Components/6560/6560.cpp | 50 +++++++++++++++++++++++++++++++++++++-- Components/6560/6560.hpp | 17 +++++++++++++ Machines/Vic-20/Vic20.hpp | 2 +- 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index bc478d5fa..1c1d96dba 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -14,6 +14,7 @@ MOS6560::MOS6560() : _crt(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)), _horizontal_counter(0), _vertical_counter(0), + _cycles_since_speaker_update(0), _is_odd_frame(false) { _crt->set_composite_sampling_function( @@ -56,6 +57,7 @@ MOS6560::MOS6560() : // show the middle 90% _crt->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); + _speaker.set_input_rate(63920.4375); // assuming NTSC; clock rate / 16 } void MOS6560::set_register(int address, uint8_t value) @@ -88,9 +90,18 @@ void MOS6560::set_register(int address, uint8_t value) _video_matrix_start_address = (uint16_t)((_video_matrix_start_address & 0x0200) | ((value & 0xf0) << 6)); break; + case 0xa: + case 0xb: + case 0xc: + case 0xd: + update_audio(); + _speaker.set_control(address - 0xa, value); + break; + case 0xe: + update_audio(); _auxiliary_colour = _colours[value >> 4]; - // TODO: sound amplitude + _speaker.set_volume(value & 0xf); break; case 0xf: @@ -122,7 +133,6 @@ uint8_t MOS6560::get_register(int address) } } - void MOS6560::output_border(unsigned int number_of_cycles) { uint8_t *colour_pointer = _crt->allocate_write_area(1); @@ -132,6 +142,8 @@ void MOS6560::output_border(unsigned int number_of_cycles) uint16_t MOS6560::get_address() { + _cycles_since_speaker_update++; + _horizontal_counter++; if(_horizontal_counter == 65) { @@ -297,3 +309,37 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) } } } + +void MOS6560::update_audio() +{ +// _speaker.run_for_cycles(_cycles_since_speaker_update >> 4); + _cycles_since_speaker_update &= 15; +} + +#pragma mark - Audio + +MOS6560Speaker::MOS6560Speaker() +{ +} + +void MOS6560Speaker::set_volume(uint8_t volume) +{ +// printf("Volume is %d\n", volume); +} + +void MOS6560Speaker::set_control(int channel, uint8_t volume) +{ + // NTSC: 1022727 +//N: bass switch, R: freq f=Phi2/256/(255-$900a) NTSC: Phi2=14318181/14 Hz +//O: alto switch, S: freq f=Phi2/128/(255-$900b) PAL: Phi2=4433618/4 Hz +//P: soprano switch, T: freq f=Phi2/64/(255-$900c) +//Q: noise switch, U: freq f=Phi2/32/(255-$900d) +} + +void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target) +{ +} + +void MOS6560Speaker::skip_samples(unsigned int number_of_samples) +{ +} diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 6e9fb6d0b..3c10abca2 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -10,13 +10,26 @@ #define _560_hpp #include "../../Outputs/CRT/CRT.hpp" +#include "../../Outputs/Speaker.hpp" namespace MOS { +class MOS6560Speaker: public ::Outputs::Filter { + public: + MOS6560Speaker(); + + void set_volume(uint8_t volume); + void set_control(int channel, uint8_t volume); + + void get_samples(unsigned int number_of_samples, int16_t *target); + void skip_samples(unsigned int number_of_samples); +}; + class MOS6560 { public: MOS6560(); Outputs::CRT::CRT *get_crt() { return _crt.get(); } + Outputs::Speaker *get_speaker() { return &_speaker; } uint16_t get_address(); void set_graphics_value(uint8_t value, uint8_t colour_value); @@ -26,6 +39,7 @@ class MOS6560 { private: std::unique_ptr _crt; + MOS6560Speaker _speaker; bool _interlaced, _tall_characters; uint8_t _first_column_location, _first_row_location; @@ -54,6 +68,9 @@ class MOS6560 { bool _is_odd_frame; void output_border(unsigned int number_of_cycles); + + unsigned int _cycles_since_speaker_update; + void update_audio(); }; } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 06f46f0be..3843d392a 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -106,7 +106,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p virtual void setup_output(float aspect_ratio); virtual void close_output() {} virtual Outputs::CRT::CRT *get_crt() { return _mos6560->get_crt(); } - virtual Outputs::Speaker *get_speaker() { return nullptr; } // TODO + virtual Outputs::Speaker *get_speaker() { return _mos6560->get_speaker(); } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor::run_for_cycles(number_of_cycles); } // to satisfy MOS::MOS6522::Delegate From 2d23bc46f23b0acfce4f7a80e7973c85bcff6759 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 19:34:01 -0400 Subject: [PATCH 60/66] Whoops; fixed line count target test. --- Components/6560/6560.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index bc478d5fa..31fcbe3f8 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -139,7 +139,7 @@ uint16_t MOS6560::get_address() _vertical_counter++; _column_counter = -1; - if(_vertical_counter == _interlaced ? 261 : (_is_odd_frame ? 262 : 263)) + if(_vertical_counter == (_interlaced ? (_is_odd_frame ? 262 : 263) : 261)) { _is_odd_frame ^= true; _vertical_counter = 0; From efcb196ef7016397b1c2177fad52ca8dc822fdfb Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 20:59:01 -0400 Subject: [PATCH 61/66] Made a complete attempt at the tone channels. --- Components/6560/6560.cpp | 35 ++++++++++++++++++++++++++--------- Components/6560/6560.hpp | 8 +++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index a223df035..182cf8cd3 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -57,7 +57,7 @@ MOS6560::MOS6560() : // show the middle 90% _crt->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); - _speaker.set_input_rate(63920.4375); // assuming NTSC; clock rate / 16 + _speaker.set_input_rate(255681.75); // assuming NTSC; clock rate / 4 } void MOS6560::set_register(int address, uint8_t value) @@ -312,7 +312,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) void MOS6560::update_audio() { -// _speaker.run_for_cycles(_cycles_since_speaker_update >> 4); + _speaker.run_for_cycles(_cycles_since_speaker_update >> 4); _cycles_since_speaker_update &= 15; } @@ -324,22 +324,39 @@ MOS6560Speaker::MOS6560Speaker() void MOS6560Speaker::set_volume(uint8_t volume) { -// printf("Volume is %d\n", volume); + _volume = volume; + printf("Volume: %d\n", volume); } -void MOS6560Speaker::set_control(int channel, uint8_t volume) +void MOS6560Speaker::set_control(int channel, uint8_t value) { - // NTSC: 1022727 -//N: bass switch, R: freq f=Phi2/256/(255-$900a) NTSC: Phi2=14318181/14 Hz -//O: alto switch, S: freq f=Phi2/128/(255-$900b) PAL: Phi2=4433618/4 Hz -//P: soprano switch, T: freq f=Phi2/64/(255-$900c) -//Q: noise switch, U: freq f=Phi2/32/(255-$900d) + _control_registers[channel] = value; + printf("Control %02x: %d\n", channel, value); } +#define shift(r) _shift_registers[r] = (uint8_t)((_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7)); +#define update(r, m) _counters[r]++; if((_counters[r] >> m) == 0xff) { shift(r); _counters[r] = _control_registers[r]&0x7f; } + void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target) { +// - $900d: cpuclock/32 (?) + + for(unsigned int c = 0; c < number_of_samples; c++) + { + update(0, 2); + update(1, 1); + update(2, 0); + + target[c] = ((_shift_registers[0]&1) + (_shift_registers[1]&1) + (_shift_registers[2]&1)) * _volume * 700; + } } void MOS6560Speaker::skip_samples(unsigned int number_of_samples) { + for(unsigned int c = 0; c < number_of_samples; c++) + { + update(0, 2); + update(1, 1); + update(2, 0); + } } diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index 3c10abca2..b8b66fc85 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -19,10 +19,16 @@ class MOS6560Speaker: public ::Outputs::Filter { MOS6560Speaker(); void set_volume(uint8_t volume); - void set_control(int channel, uint8_t volume); + void set_control(int channel, uint8_t value); void get_samples(unsigned int number_of_samples, int16_t *target); void skip_samples(unsigned int number_of_samples); + + private: + unsigned int _counters[4]; + uint8_t _shift_registers[4]; + uint8_t _control_registers[4]; + uint8_t _volume; }; class MOS6560 { From fdc854c0c2aee18ae7b098a7e4523e7a738b9347 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 13 Jun 2016 21:49:59 -0400 Subject: [PATCH 62/66] Fixed tone channels; made an attempt at loading PRGs that are supposed to go into RAM. --- Components/6560/6560.cpp | 17 +++++++++++------ Components/6560/6560.hpp | 2 ++ Machines/Vic-20/Vic20.cpp | 11 +++++++++-- Machines/Vic-20/Vic20.hpp | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 182cf8cd3..4d1abce6a 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -312,30 +312,32 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) void MOS6560::update_audio() { - _speaker.run_for_cycles(_cycles_since_speaker_update >> 4); - _cycles_since_speaker_update &= 15; + _speaker.run_for_cycles(_cycles_since_speaker_update >> 2); + _cycles_since_speaker_update &= 3; } #pragma mark - Audio -MOS6560Speaker::MOS6560Speaker() +MOS6560Speaker::MOS6560Speaker() : + _volume(0), + _control_registers{0, 0, 0, 0}, + _shift_registers{0, 0, 0, 0}, + _counters{0, 1, 2, 0} { } void MOS6560Speaker::set_volume(uint8_t volume) { _volume = volume; - printf("Volume: %d\n", volume); } void MOS6560Speaker::set_control(int channel, uint8_t value) { _control_registers[channel] = value; - printf("Control %02x: %d\n", channel, value); } #define shift(r) _shift_registers[r] = (uint8_t)((_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7)); -#define update(r, m) _counters[r]++; if((_counters[r] >> m) == 0xff) { shift(r); _counters[r] = _control_registers[r]&0x7f; } +#define update(r, m) _counters[r]++; if((_counters[r] >> m) == 0x7f) { shift(r); _counters[r] = _control_registers[r]&0x7f; } void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target) { @@ -360,3 +362,6 @@ void MOS6560Speaker::skip_samples(unsigned int number_of_samples) update(2, 0); } } + +#undef shift +#undef update diff --git a/Components/6560/6560.hpp b/Components/6560/6560.hpp index b8b66fc85..59a73d8f4 100644 --- a/Components/6560/6560.hpp +++ b/Components/6560/6560.hpp @@ -40,6 +40,8 @@ class MOS6560 { uint16_t get_address(); void set_graphics_value(uint8_t value, uint8_t colour_value); + void synchronise() { update_audio(); } + void set_register(int address, uint8_t value); uint8_t get_register(int address); diff --git a/Machines/Vic-20/Vic20.cpp b/Machines/Vic-20/Vic20.cpp index 1212c589f..5a60dcc1d 100644 --- a/Machines/Vic-20/Vic20.cpp +++ b/Machines/Vic-20/Vic20.cpp @@ -123,7 +123,14 @@ void Machine::add_prg(size_t length, const uint8_t *data) { _rom_address = (uint16_t)(data[0] | (data[1] << 8)); _rom_length = (uint16_t)(length - 2); - _rom = new uint8_t[length - 2]; - memcpy(_rom, &data[2], length - 2); + if(_rom_address >= 0x1000 && _rom_address+_rom_length < 0x2000) + { + memcpy(&_screenMemory[_rom_address - 0x1000], &data[2], length - 2); + } + else + { + _rom = new uint8_t[length - 2]; + memcpy(_rom, &data[2], length - 2); + } } } diff --git a/Machines/Vic-20/Vic20.hpp b/Machines/Vic-20/Vic20.hpp index 3843d392a..6e9e09a85 100644 --- a/Machines/Vic-20/Vic20.hpp +++ b/Machines/Vic-20/Vic20.hpp @@ -100,7 +100,7 @@ class Machine: public CPU6502::Processor, public CRTMachine::Machine, p // to satisfy CPU6502::Processor unsigned int perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value); - void synchronise() {} + void synchronise() { _mos6560->synchronise(); } // to satisfy CRTMachine::Machine virtual void setup_output(float aspect_ratio); From c18cc4c8f576941ca57408d1667bc261d2d3cafc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jun 2016 07:29:35 -0400 Subject: [PATCH 63/66] It appears the Vic's output is sine-ish, after all. Also adjusted centre of display, simultaneously adding some validation on that. --- Components/6560/6560.cpp | 14 ++++++-------- Outputs/CRT/CRT.cpp | 11 +++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 4d1abce6a..3d0e0a50a 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -25,8 +25,8 @@ MOS6560::MOS6560() : "uint yC = c & 15u;" "float phaseOffset = 6.283185308 * float(yC) / 16.0;" - "float chroma = step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654);" -// "float chroma = cos(phase + phaseOffset);" +// "float chroma = step(mod(phase + phaseOffset + 0.785398163397448, 6.283185308), 3.141592654);" + "float chroma = cos(phase + phaseOffset);" "return mix(y, step(yC, 14) * chroma, amplitude);" "}"); @@ -37,10 +37,8 @@ MOS6560::MOS6560() : // 3, 7, D, F // 1 uint8_t luminances[16] = { // range is 0–4 - 0, 4, 1, 3, - 2, 2, 1, 3, - 2, 1, 2, 1, - 2, 3, 2, 3 + 0, 4, 1, 3, 2, 2, 1, 3, + 2, 1, 2, 1, 2, 3, 2, 3 }; // uint8_t pal_chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance" // 15, 15, 5, 13, 2, 10, 0, 8, @@ -55,8 +53,8 @@ MOS6560::MOS6560() : _colours[c] = (uint8_t)((luminances[c] << 4) | ntsc_chrominances[c]); } - // show the middle 90% - _crt->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f)); + // show only the centre + _crt->set_visible_area(_crt->get_rect_for_area(16, 237, 11*4, 55*4, 4.0f / 3.0f)); _speaker.set_input_rate(255681.75); // assuming NTSC; clock rate / 4 } diff --git a/Outputs/CRT/CRT.cpp b/Outputs/CRT/CRT.cpp index 3f68c7684..f91f9c301 100644 --- a/Outputs/CRT/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -377,6 +377,10 @@ Outputs::CRT::Rect CRT::get_rect_for_area(int first_line_after_sync, int number_ unsigned int horizontal_scan_period = _horizontal_flywheel->get_scan_period(); unsigned int horizontal_retrace_period = horizontal_period - horizontal_scan_period; + // make sure that the requested range is visible + if(first_cycle_after_sync < horizontal_retrace_period) first_cycle_after_sync = (int)horizontal_retrace_period; + if(first_cycle_after_sync + number_of_cycles > horizontal_scan_period) number_of_cycles = (int)(horizontal_scan_period - (unsigned)first_cycle_after_sync); + float start_x = (float)((unsigned)first_cycle_after_sync - horizontal_retrace_period) / (float)horizontal_scan_period; float width = (float)number_of_cycles / (float)horizontal_scan_period; @@ -384,6 +388,13 @@ Outputs::CRT::Rect CRT::get_rect_for_area(int first_line_after_sync, int number_ unsigned int vertical_period = _vertical_flywheel->get_standard_period(); unsigned int vertical_scan_period = _vertical_flywheel->get_scan_period(); unsigned int vertical_retrace_period = vertical_period - vertical_scan_period; + + // make sure that the requested range is visible +// if((unsigned)first_line_after_sync * horizontal_period < vertical_retrace_period) +// first_line_after_sync = (vertical_retrace_period + horizontal_period - 1) / horizontal_period; +// if((first_line_after_sync + number_of_lines) * horizontal_period > vertical_scan_period) +// number_of_lines = (int)(horizontal_scan_period - (unsigned)first_cycle_after_sync); + float start_y = (float)(((unsigned)first_line_after_sync * horizontal_period) - vertical_retrace_period) / (float)vertical_scan_period; float height = (float)((unsigned)number_of_lines * horizontal_period) / vertical_scan_period; From a9036e7aa4e504c7c8d04fc9aa22d5a78fa377ae Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jun 2016 07:31:47 -0400 Subject: [PATCH 64/66] Increased buffering range of audio as a quick fix for now. Basically means: increased latency as a short-term fix. --- OSBindings/Mac/Clock Signal/Wrappers/AudioQueue.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OSBindings/Mac/Clock Signal/Wrappers/AudioQueue.m b/OSBindings/Mac/Clock Signal/Wrappers/AudioQueue.m index 9a409ea60..5f1e65ea4 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/AudioQueue.m +++ b/OSBindings/Mac/Clock Signal/Wrappers/AudioQueue.m @@ -10,7 +10,7 @@ @import AudioToolbox; #define AudioQueueNumAudioBuffers 4 -#define AudioQueueStreamLength 1024 +#define AudioQueueStreamLength 4096 #define AudioQueueBufferLength 512 enum { From f4884a34811d8010cd363393bd8cf41f229b63da Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jun 2016 17:50:32 -0400 Subject: [PATCH 65/66] Added the noise channel, albeit not very creatively. --- Components/6560/6560.cpp | 97 +++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 11 deletions(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index 3d0e0a50a..b31cb9039 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -263,7 +263,7 @@ void MOS6560::set_graphics_value(uint8_t value, uint8_t colour_value) { // TODO: this isn't correct, as _character_value will be // accessed second, then output will roll over. Probably it's - // correct (given the delays upstream) to output all 8 on an &1 + // correct (given the delays upstream) to output all 8 on an &1 // and to adjust the signalling to the CRT above? if(_this_state == State::Pixels) { @@ -334,20 +334,93 @@ void MOS6560Speaker::set_control(int channel, uint8_t value) _control_registers[channel] = value; } +// Source: VICE. Not original. +static uint8_t noise_pattern[] = { + 0x07, 0x1e, 0x1e, 0x1c, 0x1c, 0x3e, 0x3c, 0x38, 0x78, 0xf8, 0x7c, 0x1e, 0x1f, 0x8f, 0x07, 0x07, + 0xc1, 0xc0, 0xe0, 0xf1, 0xe0, 0xf0, 0xe3, 0xe1, 0xc0, 0xe0, 0x78, 0x7e, 0x3c, 0x38, 0xe0, 0xe1, + 0xc3, 0xc3, 0x87, 0xc7, 0x07, 0x1e, 0x1c, 0x1f, 0x0e, 0x0e, 0x1e, 0x0e, 0x0f, 0x0f, 0xc3, 0xc3, + 0xf1, 0xe1, 0xe3, 0xc1, 0xe3, 0xc3, 0xc3, 0xfc, 0x3c, 0x1e, 0x0f, 0x83, 0xc3, 0xc1, 0xc1, 0xc3, + 0xc3, 0xc7, 0x87, 0x87, 0xc7, 0x0f, 0x0e, 0x3c, 0x7c, 0x78, 0x3c, 0x3c, 0x3c, 0x38, 0x3e, 0x1c, + 0x7c, 0x1e, 0x3c, 0x0f, 0x0e, 0x3e, 0x78, 0xf0, 0xf0, 0xe0, 0xe1, 0xf1, 0xc1, 0xc3, 0xc7, 0xc3, + 0xe1, 0xf1, 0xe0, 0xe1, 0xf0, 0xf1, 0xe3, 0xc0, 0xf0, 0xe0, 0xf8, 0x70, 0xe3, 0x87, 0x87, 0xc0, + 0xf0, 0xe0, 0xf1, 0xe1, 0xe1, 0xc7, 0x83, 0x87, 0x83, 0x8f, 0x87, 0x87, 0xc7, 0x83, 0xc3, 0x83, + 0xc3, 0xf1, 0xe1, 0xc3, 0xc7, 0x81, 0xcf, 0x87, 0x03, 0x87, 0xc7, 0xc7, 0x87, 0x83, 0xe1, 0xc3, + 0x07, 0xc3, 0x87, 0x87, 0x07, 0x87, 0xc3, 0x87, 0x83, 0xe1, 0xc3, 0xc7, 0xc3, 0x87, 0x87, 0x8f, + 0x0f, 0x87, 0x87, 0x0f, 0xcf, 0x1f, 0x87, 0x8e, 0x0e, 0x07, 0x81, 0xc3, 0xe3, 0xc1, 0xe0, 0xf0, + 0xe0, 0xe3, 0x83, 0x87, 0x07, 0x87, 0x8e, 0x1e, 0x0f, 0x07, 0x87, 0x8f, 0x1f, 0x07, 0x87, 0xc1, + 0xf0, 0xe1, 0xe1, 0xe3, 0xc7, 0x0f, 0x03, 0x8f, 0x87, 0x0e, 0x1e, 0x1e, 0x0f, 0x87, 0x87, 0x0f, + 0x87, 0x1f, 0x0f, 0xc3, 0xc3, 0xf0, 0xf8, 0xf0, 0x70, 0xf1, 0xf0, 0xf0, 0xe1, 0xf0, 0xe0, 0x78, + 0x7c, 0x78, 0x7c, 0x70, 0x71, 0xe1, 0xe1, 0xc3, 0xc3, 0xc7, 0x87, 0x1c, 0x3c, 0x3c, 0x1c, 0x3c, + 0x7c, 0x1e, 0x1e, 0x1e, 0x1c, 0x3c, 0x78, 0xf8, 0xf8, 0xe1, 0xc3, 0x87, 0x1e, 0x1e, 0x3c, 0x3e, + 0x0f, 0x0f, 0x87, 0x1f, 0x8e, 0x0f, 0x0f, 0x8e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, 0x8f, 0x87, + 0x87, 0xc3, 0x83, 0xc1, 0xe1, 0xc3, 0xc1, 0xc3, 0xc7, 0x8f, 0x0f, 0x0f, 0x0f, 0x0f, 0x83, 0xc7, + 0xc3, 0xc1, 0xe1, 0xe0, 0xf8, 0x3e, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x78, 0x3e, 0x1e, 0x1e, 0x1e, + 0x0f, 0x0f, 0x0f, 0x1e, 0x0e, 0x1e, 0x1e, 0x0f, 0x0f, 0x87, 0x1f, 0x87, 0x87, 0x1c, 0x3e, 0x1f, + 0x0f, 0x0f, 0x8e, 0x3e, 0x0e, 0x3e, 0x1e, 0x1c, 0x3c, 0x7c, 0xfc, 0x38, 0x78, 0x78, 0x38, 0x78, + 0x70, 0xf8, 0x7c, 0x1e, 0x3c, 0x3c, 0x30, 0xf1, 0xf0, 0x70, 0x70, 0xe0, 0xf8, 0xf0, 0xf8, 0x78, + 0x78, 0x71, 0xe1, 0xf0, 0xe3, 0xc1, 0xf0, 0x71, 0xe3, 0xc7, 0x87, 0x8e, 0x3e, 0x0e, 0x1e, 0x3e, + 0x0f, 0x07, 0x87, 0x0c, 0x3e, 0x0f, 0x87, 0x0f, 0x1e, 0x3c, 0x3c, 0x38, 0x78, 0xf1, 0xe7, 0xc3, + 0xc3, 0xc7, 0x8e, 0x3c, 0x38, 0xf0, 0xe0, 0x7e, 0x1e, 0x3e, 0x0e, 0x0f, 0x0f, 0x0f, 0x03, 0xc3, + 0xc3, 0xc7, 0x87, 0x1f, 0x0e, 0x1e, 0x1c, 0x3c, 0x3c, 0x0f, 0x07, 0x07, 0xc7, 0xc7, 0x87, 0x87, + 0x8f, 0x0f, 0xc0, 0xf0, 0xf8, 0x60, 0xf0, 0xf0, 0xe1, 0xe3, 0xe3, 0xc3, 0xc3, 0xc3, 0x87, 0x0f, + 0x87, 0x8e, 0x1e, 0x1e, 0x3f, 0x1e, 0x0e, 0x1c, 0x3c, 0x7e, 0x1e, 0x3c, 0x38, 0x78, 0x78, 0x78, + 0x38, 0x78, 0x3c, 0xe1, 0xe3, 0x8f, 0x1f, 0x1c, 0x78, 0x70, 0x7e, 0x0f, 0x87, 0x07, 0xc3, 0xc7, + 0x0f, 0x1e, 0x3c, 0x0e, 0x0f, 0x0e, 0x1e, 0x03, 0xf0, 0xf0, 0xf1, 0xe3, 0xc1, 0xc7, 0xc0, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe0, 0x70, 0xe1, 0xf0, 0x78, 0x70, 0xe3, 0xc7, 0x0f, 0xc1, 0xe1, 0xe3, 0xc3, + 0xc0, 0xf0, 0xfc, 0x1c, 0x3c, 0x70, 0xf8, 0x70, 0xf8, 0x78, 0x3c, 0x70, 0xf0, 0x78, 0x70, 0x7c, + 0x7c, 0x3c, 0x38, 0x1e, 0x3e, 0x3c, 0x7e, 0x07, 0x83, 0xc7, 0xc1, 0xc1, 0xe1, 0xc3, 0xc3, 0xc3, + 0xe1, 0xe1, 0xf0, 0x78, 0x7c, 0x3e, 0x0f, 0x1f, 0x07, 0x8f, 0x0f, 0x83, 0x87, 0xc1, 0xe3, 0xe3, + 0xc3, 0xc3, 0xe1, 0xf0, 0xf8, 0xf0, 0x3c, 0x7c, 0x3c, 0x0f, 0x8e, 0x0e, 0x1f, 0x1f, 0x0e, 0x3c, + 0x38, 0x78, 0x70, 0x70, 0xf0, 0xf0, 0xf8, 0x70, 0x70, 0x78, 0x38, 0x3c, 0x70, 0xe0, 0xf0, 0x78, + 0xf1, 0xf0, 0x78, 0x3e, 0x3c, 0x0f, 0x07, 0x0e, 0x3e, 0x1e, 0x3f, 0x1e, 0x0e, 0x0f, 0x87, 0x87, + 0x07, 0x0f, 0x07, 0xc7, 0x8f, 0x0f, 0x87, 0x1e, 0x1e, 0x1f, 0x1e, 0x1e, 0x3c, 0x1e, 0x1c, 0x3e, + 0x0f, 0x03, 0xc3, 0x81, 0xe0, 0xf0, 0xfc, 0x38, 0x3c, 0x3e, 0x0e, 0x1e, 0x1c, 0x7c, 0x1e, 0x1f, + 0x0e, 0x3e, 0x1c, 0x78, 0x78, 0x7c, 0x1e, 0x3e, 0x1e, 0x3c, 0x1f, 0x0f, 0x1f, 0x0f, 0x0f, 0x8f, + 0x1c, 0x3c, 0x78, 0xf8, 0xf0, 0xf8, 0x70, 0xf0, 0x78, 0x78, 0x3c, 0x3c, 0x78, 0x3c, 0x1f, 0x0f, + 0x07, 0x86, 0x1c, 0x1e, 0x1c, 0x1e, 0x1e, 0x1f, 0x03, 0xc3, 0xc7, 0x8e, 0x3c, 0x3c, 0x1c, 0x18, + 0xf0, 0xe1, 0xc3, 0xe1, 0xc1, 0xe1, 0xe3, 0xc3, 0xc3, 0xe3, 0xc3, 0x83, 0x87, 0x83, 0x87, 0x0f, + 0x07, 0x07, 0xe1, 0xe1, 0xe0, 0x7c, 0x78, 0x38, 0x78, 0x78, 0x3c, 0x1f, 0x0f, 0x8f, 0x0e, 0x07, + 0x0f, 0x07, 0x83, 0xc3, 0xc3, 0x81, 0xf0, 0xf8, 0xf1, 0xe0, 0xe3, 0xc7, 0x1c, 0x3e, 0x1e, 0x0f, + 0x0f, 0xc3, 0xf0, 0xf0, 0xe3, 0x83, 0xc3, 0xc7, 0x07, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x07, 0x87, + 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x1e, 0x0f, 0x0f, 0x87, 0x87, 0x87, 0x8f, 0xc7, 0xc7, 0x83, 0x83, + 0xc3, 0xc7, 0x8f, 0x87, 0x07, 0xc3, 0x8e, 0x1e, 0x38, 0x3e, 0x3c, 0x38, 0x7c, 0x1f, 0x1c, 0x38, + 0x3c, 0x78, 0x7c, 0x1e, 0x1c, 0x3c, 0x3f, 0x1e, 0x0e, 0x3e, 0x1c, 0x3c, 0x1f, 0x0f, 0x07, 0xc3, + 0xe3, 0x83, 0x87, 0x81, 0xc1, 0xe3, 0xcf, 0x0e, 0x0f, 0x1e, 0x3e, 0x1e, 0x1f, 0x0f, 0x8f, 0xc3, + 0x87, 0x0e, 0x03, 0xf0, 0xf0, 0x70, 0xe0, 0xe1, 0xe1, 0xc7, 0x8e, 0x0f, 0x0f, 0x1e, 0x0e, 0x1e, + 0x1f, 0x1c, 0x78, 0xf0, 0xf1, 0xf1, 0xe0, 0xf1, 0xe1, 0xe1, 0xe0, 0xe0, 0xf1, 0xc1, 0xf0, 0x71, + 0xe1, 0xc3, 0x83, 0xc7, 0x83, 0xe1, 0xe1, 0xf8, 0x70, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0x70, 0xf8, + 0x70, 0x70, 0x61, 0xe0, 0xf0, 0xe1, 0xe0, 0x78, 0x71, 0xe0, 0xf0, 0xf8, 0x38, 0x1e, 0x1c, 0x38, + 0x70, 0xf8, 0x60, 0x78, 0x38, 0x3c, 0x3f, 0x1f, 0x0f, 0x1f, 0x0f, 0x1f, 0x87, 0x87, 0x83, 0x87, + 0x83, 0xe1, 0xe1, 0xf0, 0x78, 0xf1, 0xf0, 0x70, 0x38, 0x38, 0x70, 0xe0, 0xe3, 0xc0, 0xe0, 0xf8, + 0x78, 0x78, 0xf8, 0x38, 0xf1, 0xe1, 0xe1, 0xc3, 0x87, 0x87, 0x0e, 0x1e, 0x1f, 0x0e, 0x0e, 0x0f, + 0x0f, 0x87, 0xc3, 0x87, 0x07, 0x83, 0xc0, 0xf0, 0x38, 0x3c, 0x3c, 0x38, 0xf0, 0xfc, 0x3e, 0x1e, + 0x1c, 0x1c, 0x38, 0x70, 0xf0, 0xf1, 0xe0, 0xf0, 0xe0, 0xe0, 0xf1, 0xe3, 0xe0, 0xe1, 0xf0, 0xf0, + 0x78, 0x7c, 0x78, 0x3c, 0x78, 0x78, 0x38, 0x78, 0x78, 0x78, 0x78, 0x70, 0xe3, 0x83, 0x83, 0xe0, + 0xc3, 0xc1, 0xe1, 0xc1, 0xc1, 0xc1, 0xe3, 0xc3, 0xc7, 0x1e, 0x0e, 0x1f, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0e, 0x0e, 0x0e, 0x07, 0x83, 0x87, 0x87, 0x0e, 0x07, 0x8f, 0x0f, 0x0f, 0x0f, 0x0e, 0x1c, 0x70, + 0xe1, 0xe0, 0x71, 0xc1, 0x83, 0x83, 0x87, 0x0f, 0x1e, 0x18, 0x78, 0x78, 0x7c, 0x3e, 0x1c, 0x38, + 0xf0, 0xe1, 0xe0, 0x78, 0x70, 0x38, 0x3c, 0x3e, 0x1e, 0x3c, 0x1e, 0x1c, 0x70, 0x3c, 0x38, 0x3f, +}; + #define shift(r) _shift_registers[r] = (uint8_t)((_shift_registers[r] << 1) | (((_shift_registers[r]^0x80)&_control_registers[r]) >> 7)); -#define update(r, m) _counters[r]++; if((_counters[r] >> m) == 0x7f) { shift(r); _counters[r] = _control_registers[r]&0x7f; } +#define increment(r) _shift_registers[r] = (_shift_registers[r]+1)%8191; +#define update(r, m, up) _counters[r]++; if((_counters[r] >> m) == 0x7f) { up(r); _counters[r] = _control_registers[r]&0x7f; } void MOS6560Speaker::get_samples(unsigned int number_of_samples, int16_t *target) { -// - $900d: cpuclock/32 (?) - for(unsigned int c = 0; c < number_of_samples; c++) { - update(0, 2); - update(1, 1); - update(2, 0); + update(0, 2, shift); + update(1, 1, shift); + update(2, 0, shift); + update(3, 1, increment); - target[c] = ((_shift_registers[0]&1) + (_shift_registers[1]&1) + (_shift_registers[2]&1)) * _volume * 700; + target[c] = ( + (_shift_registers[0]&1) + + (_shift_registers[1]&1) + + (_shift_registers[2]&1) + + ((noise_pattern[_shift_registers[3] >> 3] >> (_shift_registers[3]&7))&(_control_registers[3] >> 7)&1) + ) * _volume * 700; } } @@ -355,11 +428,13 @@ void MOS6560Speaker::skip_samples(unsigned int number_of_samples) { for(unsigned int c = 0; c < number_of_samples; c++) { - update(0, 2); - update(1, 1); - update(2, 0); + update(0, 2, shift); + update(1, 1, shift); + update(2, 0, shift); + update(3, 1, increment); } } #undef shift +#undef increment #undef update From a2a6e3c818e134eb89cc917c4bacf57d2407c445 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Tue, 14 Jun 2016 18:19:06 -0400 Subject: [PATCH 66/66] Fixed phase offsets. --- Components/6560/6560.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/6560/6560.cpp b/Components/6560/6560.cpp index b31cb9039..f22b69204 100644 --- a/Components/6560/6560.cpp +++ b/Components/6560/6560.cpp @@ -320,7 +320,7 @@ MOS6560Speaker::MOS6560Speaker() : _volume(0), _control_registers{0, 0, 0, 0}, _shift_registers{0, 0, 0, 0}, - _counters{0, 1, 2, 0} + _counters{2, 1, 0, 0} // create a slight phase offset for the three channels { }