1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-07 08:28:57 +00:00

Merge pull request #45 from TomHarte/MemoryModels

Vic: Adds support for expanded memory and PAL region machines.
This commit is contained in:
Thomas Harte 2016-08-14 20:01:19 -04:00 committed by GitHub
commit e59301b416
13 changed files with 266 additions and 43 deletions

View File

@ -13,6 +13,8 @@
using namespace Atari2600; using namespace Atari2600;
namespace { namespace {
static const unsigned int horizontalTimerPeriod = 228; static const unsigned int horizontalTimerPeriod = 228;
static const double NTSC_clock_rate = 1194720;
static const double PAL_clock_rate = 1182298;
} }
Machine::Machine() : Machine::Machine() :
@ -52,6 +54,7 @@ Machine::Machine() :
_stateByExtendTime[vbextend][c] = state; _stateByExtendTime[vbextend][c] = state;
} }
} }
set_clock_rate(NTSC_clock_rate);
} }
void Machine::setup_output(float aspect_ratio) void Machine::setup_output(float aspect_ratio)
@ -94,8 +97,7 @@ void Machine::switch_region()
_is_pal_region = true; _is_pal_region = true;
_speaker->set_input_rate((float)(get_clock_rate() / 38.0)); _speaker->set_input_rate((float)(get_clock_rate() / 38.0));
set_clock_rate(PAL_clock_rate);
if(delegate) delegate->machine_did_change_clock_rate(this);
} }
void Machine::close_output() void Machine::close_output()
@ -109,11 +111,6 @@ Machine::~Machine()
close_output(); close_output();
} }
double Machine::get_clock_rate()
{
return _is_pal_region ? 1182298 : 1194720;
}
void Machine::update_timers(int mask) void Machine::update_timers(int mask)
{ {
unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events; unsigned int upcomingPointerPlus4 = (_upcomingEventsPointer + 4)%number_of_upcoming_events;

View File

@ -94,7 +94,6 @@ class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine {
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; } virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; }
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _speaker; } virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _speaker; }
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
virtual double get_clock_rate();
// TODO: different rate for PAL // TODO: different rate for PAL
private: private:

View File

@ -30,15 +30,26 @@ class Machine {
virtual void run_for_cycles(int number_of_cycles) = 0; virtual void run_for_cycles(int number_of_cycles) = 0;
// TODO: sever the clock-rate stuff. // TODO: sever the clock-rate stuff.
virtual double get_clock_rate() = 0; double get_clock_rate() {
return clock_rate_;
}
class Delegate { class Delegate {
public: public:
virtual void machine_did_change_clock_rate(Machine *machine) = 0; virtual void machine_did_change_clock_rate(Machine *machine) = 0;
}; };
void set_delegate(Delegate *delegate) { this->delegate = delegate; } void set_delegate(Delegate *delegate) { this->delegate_ = delegate; }
protected: protected:
Delegate *delegate; double clock_rate_;
void set_clock_rate(double clock_rate) {
if(clock_rate_ != clock_rate) {
clock_rate_ = clock_rate;
if(delegate_) delegate_->machine_did_change_clock_rate(this);
}
}
private:
Delegate *delegate_;
}; };
} }

View File

@ -35,9 +35,34 @@ Machine::Machine() :
_tape.set_delegate(this); _tape.set_delegate(this);
// establish the memory maps // establish the memory maps
set_memory_size(MemorySize::Default);
// set the NTSC clock rate
set_region(NTSC);
// _debugPort.reset(new ::Commodore::Serial::DebugPort);
// _debugPort->set_serial_bus(_serialBus);
// _serialBus->add_port(_debugPort);
}
void Machine::set_memory_size(MemorySize size)
{
memset(_processorReadMemoryMap, 0, sizeof(_processorReadMemoryMap)); memset(_processorReadMemoryMap, 0, sizeof(_processorReadMemoryMap));
memset(_processorWriteMemoryMap, 0, sizeof(_processorWriteMemoryMap)); memset(_processorWriteMemoryMap, 0, sizeof(_processorWriteMemoryMap));
switch(size)
{
default: break;
case ThreeKB:
write_to_map(_processorReadMemoryMap, _expansionRAM, 0x0000, 0x1000);
write_to_map(_processorWriteMemoryMap, _expansionRAM, 0x0000, 0x1000);
break;
case ThirtyTwoKB:
write_to_map(_processorReadMemoryMap, _expansionRAM, 0x0000, 0x8000);
write_to_map(_processorWriteMemoryMap, _expansionRAM, 0x0000, 0x8000);
break;
}
// install the ROMs and VIC-visible memory
write_to_map(_processorReadMemoryMap, _userBASICMemory, 0x0000, sizeof(_userBASICMemory)); write_to_map(_processorReadMemoryMap, _userBASICMemory, 0x0000, sizeof(_userBASICMemory));
write_to_map(_processorReadMemoryMap, _screenMemory, 0x1000, sizeof(_screenMemory)); write_to_map(_processorReadMemoryMap, _screenMemory, 0x1000, sizeof(_screenMemory));
write_to_map(_processorReadMemoryMap, _colorMemory, 0x9400, sizeof(_colorMemory)); write_to_map(_processorReadMemoryMap, _colorMemory, 0x9400, sizeof(_colorMemory));
@ -48,10 +73,6 @@ Machine::Machine() :
write_to_map(_processorWriteMemoryMap, _userBASICMemory, 0x0000, sizeof(_userBASICMemory)); write_to_map(_processorWriteMemoryMap, _userBASICMemory, 0x0000, sizeof(_userBASICMemory));
write_to_map(_processorWriteMemoryMap, _screenMemory, 0x1000, sizeof(_screenMemory)); write_to_map(_processorWriteMemoryMap, _screenMemory, 0x1000, sizeof(_screenMemory));
write_to_map(_processorWriteMemoryMap, _colorMemory, 0x9400, sizeof(_colorMemory)); write_to_map(_processorWriteMemoryMap, _colorMemory, 0x9400, sizeof(_colorMemory));
// _debugPort.reset(new ::Commodore::Serial::DebugPort);
// _debugPort->set_serial_bus(_serialBus);
// _serialBus->add_port(_debugPort);
} }
void Machine::write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length) void Machine::write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length)
@ -141,9 +162,26 @@ void Machine::mos6522_did_change_interrupt_status(void *mos6522)
#pragma mark - Setup #pragma mark - Setup
void Machine::set_region(Commodore::Vic20::Region region)
{
_region = region;
switch(region)
{
case PAL:
set_clock_rate(1108404);
if(_mos6560) _mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::PAL);
break;
case NTSC:
set_clock_rate(1022727);
if(_mos6560) _mos6560->set_output_mode(MOS::MOS6560<Commodore::Vic20::Vic6560>::OutputMode::NTSC);
break;
}
}
void Machine::setup_output(float aspect_ratio) void Machine::setup_output(float aspect_ratio)
{ {
_mos6560.reset(new Vic6560()); _mos6560.reset(new Vic6560());
set_region(_region);
memset(_mos6560->_videoMemoryMap, 0, sizeof(_mos6560->_videoMemoryMap)); memset(_mos6560->_videoMemoryMap, 0, sizeof(_mos6560->_videoMemoryMap));
write_to_map(_mos6560->_videoMemoryMap, _characterROM, 0x0000, sizeof(_characterROM)); write_to_map(_mos6560->_videoMemoryMap, _characterROM, 0x0000, sizeof(_characterROM));
@ -191,9 +229,25 @@ void Machine::add_prg(size_t length, const uint8_t *data)
set_typer_for_string("RUN\n"); set_typer_for_string("RUN\n");
} }
_rom = new uint8_t[length - 2]; if(_rom_address == 0xa000)
memcpy(_rom, &data[2], length - 2); {
write_to_map(_processorReadMemoryMap, _rom, _rom_address, _rom_length); _rom = new uint8_t[length - 2];
memcpy(_rom, &data[2], length - 2);
write_to_map(_processorReadMemoryMap, _rom, _rom_address, _rom_length);
}
else
{
// TODO: write to virtual media (tape, probably?), load normally.
data += 2;
while(_rom_length)
{
uint8_t *ram = _processorWriteMemoryMap[_rom_address >> 10];
if(ram) ram[_rom_address & 0x3ff] = *data;
data++;
_rom_length--;
_rom_address++;
}
}
} }
} }

View File

@ -32,6 +32,17 @@ enum ROMSlot {
Drive Drive
}; };
enum MemorySize {
Default,
ThreeKB,
ThirtyTwoKB
};
enum Region {
NTSC,
PAL
};
#define key(line, mask) (((mask) << 3) | (line)) #define key(line, mask) (((mask) << 3) | (line))
enum Key: uint16_t { enum Key: uint16_t {
@ -260,6 +271,9 @@ class Machine:
_keyboardVIA->set_joystick_state(input, isPressed); _keyboardVIA->set_joystick_state(input, isPressed);
} }
void set_memory_size(MemorySize size);
void set_region(Region region);
inline void set_use_fast_tape_hack(bool activate) { _use_fast_tape_hack = activate; } inline void set_use_fast_tape_hack(bool activate) { _use_fast_tape_hack = activate; }
inline void set_should_automatically_load_media(bool activate) { _should_automatically_load_media = activate; } inline void set_should_automatically_load_media(bool activate) { _should_automatically_load_media = activate; }
@ -273,7 +287,6 @@ class Machine:
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _mos6560->get_crt(); } virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _mos6560->get_crt(); }
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _mos6560->get_speaker(); } virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _mos6560->get_speaker(); }
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
virtual double get_clock_rate() { return 1022727; }
// TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt // TODO: or 1108405 for PAL; see http://www.antimon.org/dl/c64/code/stable.txt
// to satisfy MOS::MOS6522::Delegate // to satisfy MOS::MOS6522::Delegate
@ -291,6 +304,7 @@ class Machine:
uint8_t _characterROM[0x1000]; uint8_t _characterROM[0x1000];
uint8_t _basicROM[0x2000]; uint8_t _basicROM[0x2000];
uint8_t _kernelROM[0x2000]; uint8_t _kernelROM[0x2000];
uint8_t _expansionRAM[0x8000];
uint8_t *_rom; uint8_t *_rom;
uint16_t _rom_address, _rom_length; uint16_t _rom_address, _rom_length;
@ -305,6 +319,8 @@ class Machine:
uint8_t *_processorWriteMemoryMap[64]; uint8_t *_processorWriteMemoryMap[64];
void write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length); void write_to_map(uint8_t **map, uint8_t *area, uint16_t address, uint16_t length);
Region _region;
std::unique_ptr<Vic6560> _mos6560; std::unique_ptr<Vic6560> _mos6560;
std::shared_ptr<UserPortVIA> _userPortVIA; std::shared_ptr<UserPortVIA> _userPortVIA;
std::shared_ptr<KeyboardVIA> _keyboardVIA; std::shared_ptr<KeyboardVIA> _keyboardVIA;

View File

@ -55,6 +55,7 @@ Machine::Machine() :
memset(_roms[c], 0xff, 16384); memset(_roms[c], 0xff, 16384);
_tape.set_delegate(this); _tape.set_delegate(this);
set_clock_rate(2000000);
} }
void Machine::setup_output(float aspect_ratio) void Machine::setup_output(float aspect_ratio)

View File

@ -162,7 +162,6 @@ class Machine:
virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; } virtual std::shared_ptr<Outputs::CRT::CRT> get_crt() { return _crt; }
virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _speaker; } virtual std::shared_ptr<Outputs::Speaker> get_speaker() { return _speaker; }
virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); } virtual void run_for_cycles(int number_of_cycles) { CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles); }
virtual double get_clock_rate() { return 2000000; }
// to satisfy Tape::Delegate // to satisfy Tape::Delegate
virtual void tape_did_change_interrupt_status(Tape *tape); virtual void tape_did_change_interrupt_status(Tape *tape);

View File

@ -174,9 +174,8 @@ static void audioOutputCallback(
- (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(size_t)lengthInSamples - (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(size_t)lengthInSamples
{ {
while(1) if([_writeLock tryLockWhenCondition:AudioQueueCanProceed])
{ {
[_writeLock lockWhenCondition:AudioQueueCanProceed];
if((_audioStreamReadPosition + _streamLength) - _audioStreamWritePosition >= lengthInSamples) if((_audioStreamReadPosition + _streamLength) - _audioStreamWritePosition >= lengthInSamples)
{ {
size_t samplesBeforeOverflow = _streamLength - (_audioStreamWritePosition % _streamLength); size_t samplesBeforeOverflow = _streamLength - (_audioStreamWritePosition % _streamLength);
@ -193,7 +192,6 @@ static void audioOutputCallback(
_audioStreamWritePosition += lengthInSamples; _audioStreamWritePosition += lengthInSamples;
[_writeLock unlockWithCondition:[self writeLockCondition]]; [_writeLock unlockWithCondition:[self writeLockCondition]];
break;
} }
else else
{ {

View File

@ -6,8 +6,10 @@
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="Vic20Document" customModule="Clock_Signal" customModuleProvider="target"> <customObject id="-2" userLabel="File's Owner" customClass="Vic20Document" customModule="Clock_Signal" customModuleProvider="target">
<connections> <connections>
<outlet property="countryButton" destination="MlB-rE-TXV" id="BCU-M7-TC5"/>
<outlet property="fastLoadingButton" destination="sBT-cU-h7s" id="gWf-9E-D7l"/> <outlet property="fastLoadingButton" destination="sBT-cU-h7s" id="gWf-9E-D7l"/>
<outlet property="loadAutomaticallyButton" destination="lbt-Wo-6fc" id="Xsc-dz-1a6"/> <outlet property="loadAutomaticallyButton" destination="lbt-Wo-6fc" id="Xsc-dz-1a6"/>
<outlet property="memorySizeButton" destination="0NP-x1-qH2" id="Zxg-RB-IUl"/>
<outlet property="openGLView" destination="DEG-fq-cjd" id="Gxs-2u-n7B"/> <outlet property="openGLView" destination="DEG-fq-cjd" id="Gxs-2u-n7B"/>
<outlet property="optionsPanel" destination="ota-g7-hOL" id="zeO-di-9i3"/> <outlet property="optionsPanel" destination="ota-g7-hOL" id="zeO-di-9i3"/>
<outlet property="window" destination="xOd-HO-29H" id="JIz-fz-R2o"/> <outlet property="window" destination="xOd-HO-29H" id="JIz-fz-R2o"/>
@ -44,16 +46,16 @@
<window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="ota-g7-hOL" customClass="NSPanel"> <window title="Options" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="ota-g7-hOL" customClass="NSPanel">
<windowStyleMask key="styleMask" titled="YES" closable="YES" utility="YES" HUD="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" utility="YES" HUD="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="83" y="102" width="200" height="103"/> <rect key="contentRect" x="83" y="102" width="200" height="134"/>
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/> <rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/>
<value key="minSize" type="size" width="200" height="103"/> <value key="minSize" type="size" width="200" height="103"/>
<value key="maxSize" type="size" width="200" height="103"/> <value key="maxSize" type="size" width="200" height="103"/>
<view key="contentView" id="7Pv-WL-2Rq"> <view key="contentView" id="7Pv-WL-2Rq">
<rect key="frame" x="0.0" y="0.0" width="200" height="103"/> <rect key="frame" x="0.0" y="0.0" width="200" height="134"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<button translatesAutoresizingMaskIntoConstraints="NO" id="sBT-cU-h7s"> <button translatesAutoresizingMaskIntoConstraints="NO" id="sBT-cU-h7s">
<rect key="frame" x="18" y="67" width="164" height="18"/> <rect key="frame" x="18" y="98" width="164" height="18"/>
<buttonCell key="cell" type="check" title="Load Tapes Quickly" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="w0l-ha-esm"> <buttonCell key="cell" type="check" title="Load Tapes Quickly" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="w0l-ha-esm">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -63,7 +65,7 @@
</connections> </connections>
</button> </button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="lbt-Wo-6fc"> <button translatesAutoresizingMaskIntoConstraints="NO" id="lbt-Wo-6fc">
<rect key="frame" x="18" y="47" width="164" height="18"/> <rect key="frame" x="18" y="78" width="164" height="18"/>
<buttonCell key="cell" type="check" title="Load Automatically" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="jTj-uV-at1"> <buttonCell key="cell" type="check" title="Load Automatically" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="jTj-uV-at1">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/> <font key="font" metaFont="system"/>
@ -72,8 +74,25 @@
<action selector="setShouldLoadAutomatically:" target="-2" id="Ixe-HN-4XK"/> <action selector="setShouldLoadAutomatically:" target="-2" id="Ixe-HN-4XK"/>
</connections> </connections>
</button> </button>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MlB-rE-TXV"> <popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="0NP-x1-qH2">
<rect key="frame" x="18" y="17" width="165" height="26"/> <rect key="frame" x="18" y="17" width="165" height="26"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="K81-0X-C4f">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="diI-80-lCf">
<items>
<menuItem title="5 kb" id="ze7-6B-ois"/>
<menuItem title="8 kb" id="6C7-Iv-Wvl"/>
<menuItem title="32 kb" id="DOo-f6-OeZ"/>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="setMemorySize:" target="-2" id="LSs-M5-2YZ"/>
</connections>
</popUpButton>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MlB-rE-TXV" userLabel="Country Selector">
<rect key="frame" x="18" y="48" width="165" height="26"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="UIu-uz-pTu"> <popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="UIu-uz-pTu">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="menu"/>
@ -87,21 +106,28 @@
</items> </items>
</menu> </menu>
</popUpButtonCell> </popUpButtonCell>
<connections>
<action selector="setCountry:" target="-2" id="hi5-76-cdO"/>
</connections>
</popUpButton> </popUpButton>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstAttribute="trailing" secondItem="sBT-cU-h7s" secondAttribute="trailing" constant="20" id="79b-2A-2c7"/> <constraint firstAttribute="trailing" secondItem="sBT-cU-h7s" secondAttribute="trailing" constant="20" id="79b-2A-2c7"/>
<constraint firstItem="0NP-x1-qH2" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="7EF-L9-lIu"/>
<constraint firstItem="MlB-rE-TXV" firstAttribute="top" secondItem="lbt-Wo-6fc" secondAttribute="bottom" constant="8" id="DIc-Sm-VlA"/> <constraint firstItem="MlB-rE-TXV" firstAttribute="top" secondItem="lbt-Wo-6fc" secondAttribute="bottom" constant="8" id="DIc-Sm-VlA"/>
<constraint firstAttribute="bottom" secondItem="0NP-x1-qH2" secondAttribute="bottom" constant="20" id="Dtd-kf-4oU"/>
<constraint firstItem="sBT-cU-h7s" firstAttribute="top" secondItem="7Pv-WL-2Rq" secondAttribute="top" constant="20" id="E5m-wo-X92"/> <constraint firstItem="sBT-cU-h7s" firstAttribute="top" secondItem="7Pv-WL-2Rq" secondAttribute="top" constant="20" id="E5m-wo-X92"/>
<constraint firstItem="0NP-x1-qH2" firstAttribute="top" secondItem="MlB-rE-TXV" secondAttribute="bottom" constant="10" id="NbW-5e-wGB"/>
<constraint firstItem="lbt-Wo-6fc" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="cID-bi-rVP"/> <constraint firstItem="lbt-Wo-6fc" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="cID-bi-rVP"/>
<constraint firstItem="lbt-Wo-6fc" firstAttribute="top" secondItem="sBT-cU-h7s" secondAttribute="bottom" constant="6" id="ciY-E8-07P"/> <constraint firstItem="lbt-Wo-6fc" firstAttribute="top" secondItem="sBT-cU-h7s" secondAttribute="bottom" constant="6" id="ciY-E8-07P"/>
<constraint firstAttribute="trailing" secondItem="0NP-x1-qH2" secondAttribute="trailing" constant="20" id="ero-D6-tJj"/>
<constraint firstAttribute="trailing" secondItem="lbt-Wo-6fc" secondAttribute="trailing" constant="20" id="gMU-gX-3Sg"/> <constraint firstAttribute="trailing" secondItem="lbt-Wo-6fc" secondAttribute="trailing" constant="20" id="gMU-gX-3Sg"/>
<constraint firstItem="sBT-cU-h7s" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="nDy-Xc-Ug9"/> <constraint firstItem="sBT-cU-h7s" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="nDy-Xc-Ug9"/>
<constraint firstItem="MlB-rE-TXV" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="qb4-Lp-ZMc"/> <constraint firstItem="MlB-rE-TXV" firstAttribute="leading" secondItem="7Pv-WL-2Rq" secondAttribute="leading" constant="20" id="qb4-Lp-ZMc"/>
<constraint firstAttribute="trailing" secondItem="MlB-rE-TXV" secondAttribute="trailing" constant="20" id="v18-62-uee"/> <constraint firstAttribute="trailing" secondItem="MlB-rE-TXV" secondAttribute="trailing" constant="20" id="v18-62-uee"/>
</constraints> </constraints>
</view> </view>
<point key="canvasLocation" x="-2" y="16.5"/> <point key="canvasLocation" x="-2" y="32"/>
</window> </window>
</objects> </objects>
</document> </document>

View File

@ -26,12 +26,6 @@ class Vic20Document: MachineDocument {
override init() { override init() {
super.init() super.init()
if let kernel = rom("kernel-ntsc"), basic = rom("basic"), characters = rom("characters-english") {
vic20.setKernelROM(kernel)
vic20.setBASICROM(basic)
vic20.setCharactersROM(characters)
}
if let drive = dataForResource("1540", ofType: "bin", inDirectory: "ROMImages/Commodore1540") { if let drive = dataForResource("1540", ofType: "bin", inDirectory: "ROMImages/Commodore1540") {
vic20.setDriveROM(drive) vic20.setDriveROM(drive)
} }
@ -69,25 +63,121 @@ class Vic20Document: MachineDocument {
vic20.setPRG(data) vic20.setPRG(data)
} }
// MARK: automatic loading tick box
@IBOutlet var loadAutomaticallyButton: NSButton? @IBOutlet var loadAutomaticallyButton: NSButton?
var autoloadingUserDefaultsKey: String { var autoloadingUserDefaultsKey: String {
get { return prefixedUserDefaultsKey("autoload") } get { return prefixedUserDefaultsKey("autoload") }
} }
@IBAction func setShouldLoadAutomatically(sender: NSButton!) { @IBAction func setShouldLoadAutomatically(sender: NSButton!) {
let loadAutomatically = sender.state == NSOnState let loadAutomatically = sender.state == NSOnState
vic20.shouldLoadAutomatically = loadAutomatically vic20.shouldLoadAutomatically = loadAutomatically
NSUserDefaults.standardUserDefaults().setBool(loadAutomatically, forKey: self.autoloadingUserDefaultsKey) NSUserDefaults.standardUserDefaults().setBool(loadAutomatically, forKey: self.autoloadingUserDefaultsKey)
} }
// MARK: country selector
@IBOutlet var countryButton: NSPopUpButton?
var countryUserDefaultsKey: String {
get { return prefixedUserDefaultsKey("country") }
}
@IBAction func setCountry(sender: NSPopUpButton!) {
NSUserDefaults.standardUserDefaults().setInteger(sender.indexOfSelectedItem, forKey: self.countryUserDefaultsKey)
setCountry(sender.indexOfSelectedItem)
}
private func setCountry(countryID: Int) {
var charactersROM: String?
var kernelROM: String?
switch countryID {
case 0: // Danish
charactersROM = "characters-danish"
kernelROM = "kernel-danish"
vic20.region = .PAL
case 1: // European
charactersROM = "characters-english"
kernelROM = "kernel-pal"
vic20.region = .PAL
case 2: // Japanese
charactersROM = "characters-japanese"
kernelROM = "kernel-japanese"
vic20.region = .NTSC
case 3: // Swedish
charactersROM = "characters-swedish"
kernelROM = "kernel-swedish"
vic20.region = .PAL
case 4: // US
charactersROM = "characters-english"
kernelROM = "kernel-ntsc"
vic20.region = .NTSC
default: break
}
if let charactersROM = charactersROM, kernelROM = kernelROM {
if let kernel = rom(kernelROM), basic = rom("basic"), characters = rom(charactersROM) {
vic20.setKernelROM(kernel)
vic20.setBASICROM(basic)
vic20.setCharactersROM(characters)
}
}
}
// MARK: memory model selector
@IBOutlet var memorySizeButton: NSPopUpButton?
var memorySizeUserDefaultsKey: String {
get { return prefixedUserDefaultsKey("memorySize") }
}
@IBAction func setMemorySize(sender: NSPopUpButton!) {
var selectedSize: Int?
switch sender.indexOfSelectedItem {
case 0: selectedSize = 5
case 1: selectedSize = 8
case 2: selectedSize = 32
default: break
}
if let selectedSize = selectedSize {
NSUserDefaults.standardUserDefaults().setInteger(selectedSize, forKey: self.memorySizeUserDefaultsKey)
setMemorySize(sender.indexOfSelectedItem)
}
}
private func setMemorySize(sizeIndex: Int) {
switch sizeIndex {
case 2: vic20.memorySize = .Size32Kb
case 1: vic20.memorySize = .Size8Kb
default: vic20.memorySize = .Size5Kb
}
}
// MARK: option restoration
override func establishStoredOptions() { override func establishStoredOptions() {
super.establishStoredOptions() super.establishStoredOptions()
let standardUserDefaults = NSUserDefaults.standardUserDefaults() let standardUserDefaults = NSUserDefaults.standardUserDefaults()
standardUserDefaults.registerDefaults([ standardUserDefaults.registerDefaults([
autoloadingUserDefaultsKey: true self.autoloadingUserDefaultsKey: true,
self.memorySizeUserDefaultsKey: 5,
self.countryUserDefaultsKey: 1
]) ])
let loadAutomatically = standardUserDefaults.boolForKey(self.autoloadingUserDefaultsKey) let loadAutomatically = standardUserDefaults.boolForKey(self.autoloadingUserDefaultsKey)
vic20.shouldLoadAutomatically = loadAutomatically vic20.shouldLoadAutomatically = loadAutomatically
self.loadAutomaticallyButton?.state = loadAutomatically ? NSOnState : NSOffState self.loadAutomaticallyButton?.state = loadAutomatically ? NSOnState : NSOffState
let memorySize = standardUserDefaults.integerForKey(self.memorySizeUserDefaultsKey)
var indexToSelect: Int?
switch memorySize {
case 32: indexToSelect = 2
case 8: indexToSelect = 1
default: indexToSelect = 0
}
if let indexToSelect = indexToSelect {
self.memorySizeButton?.selectItemAtIndex(indexToSelect)
setMemorySize(indexToSelect)
}
let country = standardUserDefaults.integerForKey(self.countryUserDefaultsKey)
setCountry(country)
self.countryButton?.selectItemAtIndex(country)
} }
} }

View File

@ -10,6 +10,19 @@
#import "CSKeyboardMachine.h" #import "CSKeyboardMachine.h"
#import "CSFastLoading.h" #import "CSFastLoading.h"
typedef NS_ENUM(NSInteger, CSVic20Region)
{
CSVic20RegionPAL,
CSVic20RegionNTSC
};
typedef NS_ENUM(NSInteger, CSVic20MemorySize)
{
CSVic20MemorySize5Kb,
CSVic20MemorySize8Kb,
CSVic20MemorySize32Kb,
};
@interface CSVic20 : CSMachine <CSKeyboardMachine, CSFastLoading> @interface CSVic20 : CSMachine <CSKeyboardMachine, CSFastLoading>
- (void)setKernelROM:(nonnull NSData *)rom; - (void)setKernelROM:(nonnull NSData *)rom;
@ -24,5 +37,7 @@
@property (nonatomic, assign) BOOL useFastLoadingHack; @property (nonatomic, assign) BOOL useFastLoadingHack;
@property (nonatomic, assign) BOOL shouldLoadAutomatically; @property (nonatomic, assign) BOOL shouldLoadAutomatically;
@property (nonatomic, assign) CSVic20Region region;
@property (nonatomic, assign) CSVic20MemorySize memorySize;
@end @end

View File

@ -190,18 +190,38 @@ using namespace Commodore::Vic20;
} }
} }
#pragma mark - Public configuration options
- (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack { - (void)setUseFastLoadingHack:(BOOL)useFastLoadingHack {
_useFastLoadingHack = useFastLoadingHack;
@synchronized(self) { @synchronized(self) {
_useFastLoadingHack = useFastLoadingHack;
_vic20.set_use_fast_tape_hack(useFastLoadingHack ? true : false); _vic20.set_use_fast_tape_hack(useFastLoadingHack ? true : false);
} }
} }
- (void)setShouldLoadAutomatically:(BOOL)shouldLoadAutomatically { - (void)setShouldLoadAutomatically:(BOOL)shouldLoadAutomatically {
_shouldLoadAutomatically = shouldLoadAutomatically;
@synchronized(self) { @synchronized(self) {
_shouldLoadAutomatically = shouldLoadAutomatically;
_vic20.set_should_automatically_load_media(shouldLoadAutomatically ? true : false); _vic20.set_should_automatically_load_media(shouldLoadAutomatically ? true : false);
} }
} }
- (void)setRegion:(CSVic20Region)region {
_region = region;
@synchronized(self) {
_vic20.set_region( (region == CSVic20RegionPAL) ? Commodore::Vic20::Region::PAL : Commodore::Vic20::Region::NTSC);
}
}
- (void)setMemorySize:(CSVic20MemorySize)memorySize {
_memorySize = memorySize;
@synchronized(self) {
switch(memorySize) {
case CSVic20MemorySize5Kb: _vic20.set_memory_size(Commodore::Vic20::Default); break;
case CSVic20MemorySize8Kb: _vic20.set_memory_size(Commodore::Vic20::ThreeKB); break;
case CSVic20MemorySize32Kb: _vic20.set_memory_size(Commodore::Vic20::ThirtyTwoKB); break;
}
}
}
@end @end

View File

@ -3,15 +3,12 @@ ROM files would ordinarily go here; the copyright status of these is uncertain s
Expected files: Expected files:
basic.bin basic.bin
characters-english.bin
kernel-ntsc.bin
Likely to be desired in the future:
characters-danish.bin characters-danish.bin
characters-english.bin
characters-japanese.bin characters-japanese.bin
characters-swedish.bin characters-swedish.bin
kernel-danish.bin kernel-danish.bin
kernel-japanese.bin kernel-japanese.bin
kernel-ntsc.bin
kernel-pal.bin kernel-pal.bin
kernel-swedish.bin kernel-swedish.bin