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

Merge pull request #24 from TomHarte/RAMPRGs

Adds a check for whether PRGs should be loaded to RAM and, if so, installs them post-boot and performs a 'RUN'
This commit is contained in:
Thomas Harte 2016-06-19 16:39:03 -04:00 committed by GitHub
commit ee050d71ec
9 changed files with 279 additions and 7 deletions

58
Machines/Typer.cpp Normal file
View File

@ -0,0 +1,58 @@
//
// Typer.cpp
// Clock Signal
//
// Created by Thomas Harte on 19/06/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#include "Typer.hpp"
#include <stdlib.h>
using namespace Utility;
Typer::Typer(const char *string, int delay, int frequency, Delegate *delegate) :
_counter(-delay), _frequency(frequency), _string(strdup(string)), _string_pointer(0), _delegate(delegate), _phase(0) {}
void Typer::update(int duration)
{
if(_string)
{
if(_counter < 0 && _counter + duration >= 0)
{
type_next_character();
}
_counter += duration;
while(_counter > _frequency)
{
_counter -= _frequency;
type_next_character();
}
}
}
void Typer::type_next_character()
{
if(_delegate->typer_set_next_character(this, _string[_string_pointer], _phase))
{
_phase = 0;
if(!_string[_string_pointer])
{
free(_string);
_string = nullptr;
return;
}
_string_pointer++;
}
else
{
_phase++;
}
}
Typer::~Typer()
{
free(_string);
}

53
Machines/Typer.hpp Normal file
View File

@ -0,0 +1,53 @@
//
// Typer.hpp
// Clock Signal
//
// Created by Thomas Harte on 19/06/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#ifndef Typer_hpp
#define Typer_hpp
#include <memory>
namespace Utility {
class Typer {
public:
class Delegate {
public:
virtual bool typer_set_next_character(Typer *typer, char character, int phase) = 0;
};
Typer(const char *string, int delay, int frequency, Delegate *delegate);
~Typer();
void update(int duration);
private:
char *_string;
int _frequency;
int _counter;
int _phase;
Delegate *_delegate;
size_t _string_pointer;
void type_next_character();
};
class TypeRecipient: public Typer::Delegate {
public:
void set_typer_for_string(const char *string)
{
_typer = std::unique_ptr<Typer>(new Typer(string, get_typer_delay(), get_typer_frequency(), this));
}
protected:
virtual int get_typer_delay() = 0;
virtual int get_typer_frequency() = 0;
std::unique_ptr<Typer> _typer;
};
}
#endif /* Typer_hpp */

View File

@ -81,6 +81,7 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin
_userPortVIA.run_for_half_cycles(2);
_keyboardVIA.run_for_half_cycles(2);
if(_typer) _typer->update(1);
return 1;
}
@ -125,12 +126,125 @@ void Machine::add_prg(size_t length, const uint8_t *data)
_rom_length = (uint16_t)(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);
set_typer_for_string("RUN\n");
}
_rom = new uint8_t[length - 2];
memcpy(_rom, &data[2], length - 2);
}
}
#pragma mark - Typer
int Machine::get_typer_delay()
{
return get_reset_line() ? 1*263*60*65 : 0; // wait two seconds if resetting
}
int Machine::get_typer_frequency()
{
return 2*263*65; // accept a new character every two fields
}
bool Machine::typer_set_next_character(::Utility::Typer *typer, char character, int phase)
{
// If there's a 'ROM' installed that can never be accessed, assume that this typing was scheduled because
// it should be in RAM. So copy it there.
if(_rom && _rom_address >= 0x1000 && _rom_address+_rom_length < 0x2000)
{
memcpy(&_screenMemory[_rom_address - 0x1000], _rom, _rom_length);
delete[] _rom;
_rom = nullptr;
}
if(!phase) clear_all_keys();
// The following table is arranged in ASCII order
Key key_sequences[][3] = {
{NotMapped}, {NotMapped}, {NotMapped}, {NotMapped}, {NotMapped}, {NotMapped}, {NotMapped}, {NotMapped},
{KeyDelete, TerminateSequence},
{NotMapped},
{KeyReturn, TerminateSequence},
{NotMapped}, {NotMapped}, {NotMapped}, {NotMapped}, {NotMapped},
{NotMapped}, {NotMapped}, {NotMapped}, {NotMapped},
{NotMapped}, {NotMapped}, {NotMapped}, {NotMapped},
{NotMapped}, {NotMapped}, {NotMapped}, {NotMapped},
{NotMapped}, {NotMapped}, {NotMapped}, {NotMapped},
{KeySpace, TerminateSequence}, // space
{KeyLShift, Key1, TerminateSequence}, {KeyLShift, Key2, TerminateSequence}, // !, "
{KeyLShift, Key3, TerminateSequence}, {KeyLShift, Key4, TerminateSequence}, // #, $
{KeyLShift, Key5, TerminateSequence}, {KeyLShift, Key6, TerminateSequence}, // %, &
{KeyLShift, Key7, TerminateSequence}, {KeyLShift, Key8, TerminateSequence}, // ', (
{KeyLShift, Key9, TerminateSequence}, {KeyAsterisk, TerminateSequence}, // ), *
{KeyPlus, TerminateSequence}, {KeyComma, TerminateSequence}, // +, ,
{KeyDash, TerminateSequence}, {KeyFullStop, TerminateSequence}, // -, .
{KeySlash, TerminateSequence}, // /
{Key0, TerminateSequence}, {Key1, TerminateSequence}, // 0, 1
{Key2, TerminateSequence}, {Key3, TerminateSequence}, // 2, 3
{Key4, TerminateSequence}, {Key5, TerminateSequence}, // 4, 5
{Key6, TerminateSequence}, {Key7, TerminateSequence}, // 6, 7
{Key8, TerminateSequence}, {Key9, TerminateSequence}, // 8, 9
{KeyColon, TerminateSequence}, {KeySemicolon, TerminateSequence}, // :, ;
{KeyLShift, KeyComma, TerminateSequence}, {KeyEquals, TerminateSequence}, // <, =
{KeyLShift, KeyFullStop, TerminateSequence}, {KeyLShift, KeySlash, TerminateSequence}, // >, ?
{KeyAt, TerminateSequence}, // @
{KeyA, TerminateSequence}, {KeyB, TerminateSequence}, {KeyC, TerminateSequence}, {KeyD, TerminateSequence}, // A, B, C, D
{KeyE, TerminateSequence}, {KeyF, TerminateSequence}, {KeyG, TerminateSequence}, {KeyH, TerminateSequence}, // E, F, G, H
{KeyI, TerminateSequence}, {KeyJ, TerminateSequence}, {KeyK, TerminateSequence}, {KeyL, TerminateSequence}, // I, J, K L
{KeyM, TerminateSequence}, {KeyN, TerminateSequence}, {KeyO, TerminateSequence}, {KeyP, TerminateSequence}, // M, N, O, P
{KeyQ, TerminateSequence}, {KeyR, TerminateSequence}, {KeyS, TerminateSequence}, {KeyT, TerminateSequence}, // Q, R, S, T
{KeyU, TerminateSequence}, {KeyV, TerminateSequence}, {KeyW, TerminateSequence}, {KeyX, TerminateSequence}, // U, V, W X
{KeyY, TerminateSequence}, {KeyZ, TerminateSequence}, // Y, Z
{KeyLShift, KeyColon, TerminateSequence}, {NotMapped}, // [, '\'
{KeyLShift, KeyFullStop, TerminateSequence}, {NotMapped}, // ], ^
{NotMapped}, {NotMapped}, // _, `
{KeyA, TerminateSequence}, {KeyB, TerminateSequence}, {KeyC, TerminateSequence}, {KeyD, TerminateSequence}, // A, B, C, D
{KeyE, TerminateSequence}, {KeyF, TerminateSequence}, {KeyG, TerminateSequence}, {KeyH, TerminateSequence}, // E, F, G, H
{KeyI, TerminateSequence}, {KeyJ, TerminateSequence}, {KeyK, TerminateSequence}, {KeyL, TerminateSequence}, // I, J, K L
{KeyM, TerminateSequence}, {KeyN, TerminateSequence}, {KeyO, TerminateSequence}, {KeyP, TerminateSequence}, // M, N, O, P
{KeyQ, TerminateSequence}, {KeyR, TerminateSequence}, {KeyS, TerminateSequence}, {KeyT, TerminateSequence}, // Q, R, S, T
{KeyU, TerminateSequence}, {KeyV, TerminateSequence}, {KeyW, TerminateSequence}, {KeyX, TerminateSequence}, // U, V, W X
{KeyY, TerminateSequence}, {KeyZ, TerminateSequence}, // Y, Z
// {KeyLShift, KeyA, TerminateSequence}, {KeyLShift, KeyB, TerminateSequence}, // a, b
// {KeyLShift, KeyC, TerminateSequence}, {KeyLShift, KeyD, TerminateSequence}, // c, d
// {KeyLShift, KeyE, TerminateSequence}, {KeyLShift, KeyF, TerminateSequence}, // e, f
// {KeyLShift, KeyG, TerminateSequence}, {KeyLShift, KeyH, TerminateSequence}, // g, h
// {KeyLShift, KeyI, TerminateSequence}, {KeyLShift, KeyJ, TerminateSequence}, // i, j
// {KeyLShift, KeyK, TerminateSequence}, {KeyLShift, KeyL, TerminateSequence}, // k, l
// {KeyLShift, KeyM, TerminateSequence}, {KeyLShift, KeyN, TerminateSequence}, // m, n
// {KeyLShift, KeyO, TerminateSequence}, {KeyLShift, KeyP, TerminateSequence}, // o, p
// {KeyLShift, KeyQ, TerminateSequence}, {KeyLShift, KeyR, TerminateSequence}, // q, r
// {KeyLShift, KeyS, TerminateSequence}, {KeyLShift, KeyT, TerminateSequence}, // s, t
// {KeyLShift, KeyU, TerminateSequence}, {KeyLShift, KeyV, TerminateSequence}, // u, v
// {KeyLShift, KeyW, TerminateSequence}, {KeyLShift, KeyX, TerminateSequence}, // w, x
// {KeyLShift, KeyY, TerminateSequence}, {KeyLShift, KeyZ, TerminateSequence}, // y, z
};
Key *key_sequence = nullptr;
character &= 0x7f;
if(character < sizeof(key_sequences) / sizeof(*key_sequences))
{
key_sequence = key_sequences[character];
if(key_sequence[0] != NotMapped)
{
if(phase > 0)
{
set_key_state(key_sequence[phase-1], true);
return key_sequence[phase] == TerminateSequence;
}
else
return false;
}
}
return true;
}

View File

@ -12,7 +12,9 @@
#include "../../Processors/6502/CPU6502.hpp"
#include "../../Components/6560/6560.hpp"
#include "../../Components/6522/6522.hpp"
#include "../CRTMachine.hpp"
#include "../Typer.hpp"
namespace Vic20 {
@ -42,6 +44,8 @@ enum Key: uint16_t {
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), KeyDelete = key(0, 0x80),
TerminateSequence = 0, NotMapped = 0xffff
};
class UserPortVIA: public MOS::MOS6522<UserPortVIA>, public MOS::MOS6522IRQDelegate {
@ -88,7 +92,12 @@ class KeyboardVIA: public MOS::MOS6522<KeyboardVIA>, public MOS::MOS6522IRQDeleg
uint8_t _activation_mask;
};
class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine, public MOS::MOS6522IRQDelegate::Delegate {
class Machine:
public CPU6502::Processor<Machine>,
public CRTMachine::Machine,
public MOS::MOS6522IRQDelegate::Delegate,
public Utility::TypeRecipient {
public:
Machine();
~Machine();
@ -114,6 +123,11 @@ class Machine: public CPU6502::Processor<Machine>, public CRTMachine::Machine, p
// to satisfy MOS::MOS6522::Delegate
virtual void mos6522_did_change_interrupt_status(void *mos6522);
// for Utility::TypeRecipient
virtual int get_typer_delay();
virtual int get_typer_frequency();
virtual bool typer_set_next_character(Utility::Typer *typer, char character, int phase);
private:
uint8_t _characterROM[0x1000];
uint8_t _basicROM[0x2000];

View File

@ -13,6 +13,7 @@
4B14145E1B5887AA00E04248 /* CPU6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414591B58879D00E04248 /* CPU6502AllRAM.cpp */; };
4B1414601B58885000E04248 /* WolfgangLorenzTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */; };
4B1414621B58888700E04248 /* KlausDormannTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414611B58888700E04248 /* KlausDormannTests.swift */; };
4B1E85751D170228001EF87D /* Typer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1E85731D170228001EF87D /* Typer.cpp */; };
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2409531C45AB05004DA684 /* Speaker.cpp */; };
4B2A539F1D117D36003C6002 /* CSAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53911D117D36003C6002 /* CSAudioQueue.m */; };
4B2A53A01D117D36003C6002 /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2A53961D117D36003C6002 /* CSMachine.mm */; };
@ -352,6 +353,8 @@
4B14145A1B58879D00E04248 /* CPU6502AllRAM.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPU6502AllRAM.hpp; sourceTree = "<group>"; };
4B14145F1B58885000E04248 /* WolfgangLorenzTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WolfgangLorenzTests.swift; sourceTree = "<group>"; };
4B1414611B58888700E04248 /* KlausDormannTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KlausDormannTests.swift; sourceTree = "<group>"; };
4B1E85731D170228001EF87D /* Typer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Typer.cpp; sourceTree = "<group>"; };
4B1E85741D170228001EF87D /* Typer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Typer.hpp; sourceTree = "<group>"; };
4B2409531C45AB05004DA684 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Speaker.cpp; path = ../../Outputs/Speaker.cpp; sourceTree = "<group>"; };
4B2409541C45AB05004DA684 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Speaker.hpp; path = ../../Outputs/Speaker.hpp; sourceTree = "<group>"; };
4B24095A1C45DF85004DA684 /* Stepper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stepper.hpp; sourceTree = "<group>"; };
@ -1251,6 +1254,8 @@
4B2E2D961C3A06EC00138695 /* Atari2600 */,
4B2E2D9E1C3A070900138695 /* Electron */,
4B886FF61D03B632004291C3 /* Vic-20 */,
4B1E85731D170228001EF87D /* Typer.cpp */,
4B1E85741D170228001EF87D /* Typer.hpp */,
);
name = Machines;
path = ../../Machines;
@ -1764,6 +1769,7 @@
4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */,
4BBF99141C8FBA6F0075DAFB /* CRTInputBufferBuilder.cpp in Sources */,
4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */,
4B1E85751D170228001EF87D /* Typer.cpp in Sources */,
4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */,
4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */,
4B55CE5D1C3B7D6F0093A61B /* CSOpenGLView.m in Sources */,

View File

@ -80,6 +80,14 @@ class MachineDocument:
super.close()
}
// MARK: the pasteboard
func paste(sender: AnyObject!) {
let pasteboard = NSPasteboard.generalPasteboard()
if let string = pasteboard.stringForType(NSPasteboardTypeString) {
self.machine().paste(string)
}
}
// MARK: CSBestEffortUpdaterDelegate
final func bestEffortUpdater(bestEffortUpdater: CSBestEffortUpdater!, runForCycles cycles: UInt, didSkipPreviousUpdate: Bool) {
runForNumberOfCycles(Int32(cycles))

View File

@ -30,4 +30,6 @@
@property (nonatomic, weak) id<CSMachineDelegate> delegate;
@property (nonatomic, readonly) double clockRate;
- (void)paste:(NSString *)string;
@end

View File

@ -8,6 +8,7 @@
#import "CSMachine.h"
#import "CSMachine+Subclassing.h"
#include "Typer.hpp"
@interface CSMachine()
- (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length;
@ -92,4 +93,10 @@ struct SpeakerDelegate: public Outputs::Speaker::Delegate {
return self.machine->get_clock_rate();
}
- (void)paste:(NSString *)paste {
Utility::TypeRecipient *typeRecipient = dynamic_cast<Utility::TypeRecipient *>(self.machine);
if(typeRecipient)
typeRecipient->set_typer_for_string([paste UTF8String]);
}
@end

View File

@ -1150,6 +1150,16 @@ template <class T> class Processor {
_reset_line_is_enabled = active;
}
/*!
Gets the current level of the RST line.
@returns @c true if the line is logically active; @c false otherwise.
*/
inline bool get_reset_line()
{
return _reset_line_is_enabled;
}
/*!
Sets the current level of the IRQ line.