mirror of
https://github.com/DerekK19/PDP-8-E-Simulator.git
synced 2024-06-12 19:18:59 +00:00
Coverted to use Objective-C ARC
This commit is contained in:
parent
102b5c9a2e
commit
f4e79c13fb
|
@ -63,6 +63,7 @@
|
|||
BOOL isConsoleTTY;
|
||||
}
|
||||
|
||||
- (void) loadCoder:(NSCoder *)coder;
|
||||
- (unsigned short) getKBB;
|
||||
- (void) setKBB:(unsigned short)kbb;
|
||||
- (unsigned short) getTTO;
|
||||
|
|
554
ASR33/ASR33.m
554
ASR33/ASR33.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* ASR33.m - ASR 33 Teletype for the PDP-8/E Simulator
|
||||
* ASR33.m - ASR 33 Teletype for the PDP-8/E Simulator
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,6 +32,8 @@
|
|||
#import "PluginFramework/InputConsumerProtocol.h"
|
||||
#import "PluginFramework/NSThread+MainThread.h"
|
||||
|
||||
#import <mach/mach_time.h>
|
||||
|
||||
#define USE_ASR33_REGISTERS_DIRECTLY 1
|
||||
|
||||
#import "ASR33.h"
|
||||
|
@ -42,39 +44,39 @@
|
|||
#import "TypeaheadBuffer.h"
|
||||
|
||||
|
||||
#define ASR33_CONTTY_PLUGIN_NAME NSLocalizedStringFromTableInBundle( \
|
||||
@"ASR 33 Console Teletype.pdp8Plugin", nil, [self bundle], @"")
|
||||
#define ASR33_AUXTTY_IO_INFO_FILENAME @"auxtty-io-info"
|
||||
#define ASR33_CONTTY_PLUGIN_NAME NSLocalizedStringFromTableInBundle( \
|
||||
@"ASR 33 Console Teletype.pdp8Plugin", nil, [self bundle], @"")
|
||||
#define ASR33_AUXTTY_IO_INFO_FILENAME @"auxtty-io-info"
|
||||
|
||||
#define CODER_KEY_KBB @"kbb"
|
||||
#define CODER_KEY_TTO @"tto"
|
||||
#define CODER_KEY_INFLAG @"inflag"
|
||||
#define CODER_KEY_INMASK @"inmask"
|
||||
#define CODER_KEY_OUTFLAG @"outflag"
|
||||
#define CODER_KEY_OUTMASK @"outmask"
|
||||
#define CODER_KEY_ONLINE @"online"
|
||||
#define CODER_KEY_KBB @"kbb"
|
||||
#define CODER_KEY_TTO @"tto"
|
||||
#define CODER_KEY_INFLAG @"inflag"
|
||||
#define CODER_KEY_INMASK @"inmask"
|
||||
#define CODER_KEY_OUTFLAG @"outflag"
|
||||
#define CODER_KEY_OUTMASK @"outmask"
|
||||
#define CODER_KEY_ONLINE @"online"
|
||||
|
||||
#define NO_OUTPUT 0
|
||||
#define OUTPUT 1
|
||||
#define NO_INPUT 0
|
||||
#define INPUT 1
|
||||
#define NO_OUTPUT 0
|
||||
#define OUTPUT 1
|
||||
#define NO_INPUT 0
|
||||
#define INPUT 1
|
||||
|
||||
#define TELETYPE_DELAY 100000 // 100.000 microseconds = 0.1 second
|
||||
#define TELETYPE_DELAY 100000 // 100.000 microseconds = 0.1 second
|
||||
|
||||
#define SOUND_BACKSPACE @"tty-backspace"
|
||||
#define SOUND_BELL @"tty-bell"
|
||||
#define SOUND_CARRIAGE_RETURN @"tty-carriage-return"
|
||||
#define SOUND_KEYSTROKE1 @"tty-keystroke1"
|
||||
#define SOUND_KEYSTROKE2 @"tty-keystroke2"
|
||||
#define SOUND_KEYSTROKE3 @"tty-keystroke3"
|
||||
#define SOUND_KEYSTROKE4 @"tty-keystroke4"
|
||||
#define SOUND_SPACE @"tty-space"
|
||||
#define SOUND_TYPE @"mp3"
|
||||
#define SOUND_BACKSPACE @"tty-backspace"
|
||||
#define SOUND_BELL @"tty-bell"
|
||||
#define SOUND_CARRIAGE_RETURN @"tty-carriage-return"
|
||||
#define SOUND_KEYSTROKE1 @"tty-keystroke1"
|
||||
#define SOUND_KEYSTROKE2 @"tty-keystroke2"
|
||||
#define SOUND_KEYSTROKE3 @"tty-keystroke3"
|
||||
#define SOUND_KEYSTROKE4 @"tty-keystroke4"
|
||||
#define SOUND_SPACE @"tty-space"
|
||||
#define SOUND_TYPE @"mp3"
|
||||
|
||||
|
||||
@interface NSSound (SetVolume)
|
||||
|
||||
- (void) setVolume:(float)volume; // this is a Leopard method, not available with Tiger
|
||||
- (void) setVolume:(float)volume; // this is a Leopard method, not available with Tiger
|
||||
|
||||
@end
|
||||
|
||||
|
@ -90,84 +92,84 @@ API_VERSION
|
|||
|
||||
- (NSString *) ioInformationPlistName
|
||||
{
|
||||
isConsoleTTY = [[self pluginName] isEqualToString:ASR33_CONTTY_PLUGIN_NAME];
|
||||
return isConsoleTTY ? [super ioInformationPlistName] : ASR33_AUXTTY_IO_INFO_FILENAME;
|
||||
isConsoleTTY = [[self pluginName] isEqualToString:ASR33_CONTTY_PLUGIN_NAME];
|
||||
return isConsoleTTY ? [super ioInformationPlistName] : ASR33_AUXTTY_IO_INFO_FILENAME;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) iotsForAddress:(int)ioAddress
|
||||
{
|
||||
if (inAddress == 0) {
|
||||
inAddress = ioAddress;
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6030],
|
||||
[NSValue valueWithPointer:i6031],
|
||||
[NSValue valueWithPointer:i6032],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6034],
|
||||
[NSValue valueWithPointer:i6035],
|
||||
[NSValue valueWithPointer:i6036],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
} else {
|
||||
outAddress = ioAddress;
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6040],
|
||||
[NSValue valueWithPointer:i6041],
|
||||
[NSValue valueWithPointer:i6042],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6044],
|
||||
[NSValue valueWithPointer:i6045],
|
||||
[NSValue valueWithPointer:i6046],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
}
|
||||
if (inAddress == 0) {
|
||||
inAddress = ioAddress;
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6030],
|
||||
[NSValue valueWithPointer:i6031],
|
||||
[NSValue valueWithPointer:i6032],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6034],
|
||||
[NSValue valueWithPointer:i6035],
|
||||
[NSValue valueWithPointer:i6036],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
} else {
|
||||
outAddress = ioAddress;
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6040],
|
||||
[NSValue valueWithPointer:i6041],
|
||||
[NSValue valueWithPointer:i6042],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6044],
|
||||
[NSValue valueWithPointer:i6045],
|
||||
[NSValue valueWithPointer:i6046],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) skiptestsForAddress:(int)ioAddress
|
||||
{
|
||||
return ioAddress == inAddress ?
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6031],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil] :
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6041],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6045],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
return ioAddress == inAddress ?
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6031],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil] :
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6041],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6045],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) setIOFlag:(unsigned long)flag forIOFlagName:(NSString *)name;
|
||||
{
|
||||
if (inflag)
|
||||
outflag = flag;
|
||||
else
|
||||
inflag = flag;
|
||||
if (inflag)
|
||||
outflag = flag;
|
||||
else
|
||||
inflag = flag;
|
||||
}
|
||||
|
||||
|
||||
- (void) CAF:(int)ioAddress
|
||||
{
|
||||
if (ioAddress == inAddress) { // CAF is called twice, ignore second call
|
||||
KBB = 0;
|
||||
TTO = 0;
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
if (ioAddress == inAddress) { // CAF is called twice, ignore second call
|
||||
KBB = 0;
|
||||
TTO = 0;
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -177,23 +179,23 @@ API_VERSION
|
|||
Don't modify the on/off state of the reader/punch (else the user cannot
|
||||
load BIN tapes as described in the Small Computer Systems Handbook,
|
||||
where he must operate CLEAR/CONT *after* turning on the reader). */
|
||||
if (ioAddress == inAddress) { // CAF is called twice, ignore second call
|
||||
[self setKBB:0];
|
||||
[self setTTO:0];
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
if (ioAddress == inAddress) { // CAF is called twice, ignore second call
|
||||
[self setKBB:0];
|
||||
[self setTTO:0];
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) resetDevice
|
||||
{
|
||||
[typeaheadBuffer flush:self];
|
||||
[self setKBB:0];
|
||||
[self setTTO:0];
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
[self setOnline:YES];
|
||||
[typeaheadBuffer flush:self];
|
||||
[self setKBB:0];
|
||||
[self setTTO:0];
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
[self setOnline:YES];
|
||||
}
|
||||
|
||||
|
||||
|
@ -202,149 +204,146 @@ API_VERSION
|
|||
|
||||
- (void) playSound:(unsigned short)key
|
||||
{
|
||||
NSString *soundname;
|
||||
|
||||
NSAssertRunningOnMainThread ();
|
||||
key &= 0177;
|
||||
if (playSound || key == '\a') {
|
||||
if (isblank(key))
|
||||
soundname = SOUND_SPACE;
|
||||
else if (key == '\b')
|
||||
soundname = SOUND_BACKSPACE;
|
||||
else if (key == '\a')
|
||||
soundname = SOUND_BELL;
|
||||
else if (key == '\r')
|
||||
soundname = SOUND_CARRIAGE_RETURN;
|
||||
else if (isupper(key))
|
||||
soundname = SOUND_KEYSTROKE1;
|
||||
else if (islower(key))
|
||||
soundname = SOUND_KEYSTROKE2;
|
||||
else if (isdigit(key))
|
||||
soundname = SOUND_KEYSTROKE3;
|
||||
else
|
||||
soundname = SOUND_KEYSTROKE4;
|
||||
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:
|
||||
[[self bundle] pathForResource:soundname ofType:SOUND_TYPE] byReference:YES];
|
||||
[sound autorelease];
|
||||
if ([sound respondsToSelector:@selector(setVolume:)])
|
||||
[sound setVolume:soundVolume];
|
||||
[sound play];
|
||||
}
|
||||
NSString *soundname;
|
||||
|
||||
NSAssertRunningOnMainThread ();
|
||||
key &= 0177;
|
||||
if (playSound || key == '\a') {
|
||||
if (isblank(key))
|
||||
soundname = SOUND_SPACE;
|
||||
else if (key == '\b')
|
||||
soundname = SOUND_BACKSPACE;
|
||||
else if (key == '\a')
|
||||
soundname = SOUND_BELL;
|
||||
else if (key == '\r')
|
||||
soundname = SOUND_CARRIAGE_RETURN;
|
||||
else if (isupper(key))
|
||||
soundname = SOUND_KEYSTROKE1;
|
||||
else if (islower(key))
|
||||
soundname = SOUND_KEYSTROKE2;
|
||||
else if (isdigit(key))
|
||||
soundname = SOUND_KEYSTROKE3;
|
||||
else
|
||||
soundname = SOUND_KEYSTROKE4;
|
||||
NSSound *sound = [[NSSound alloc] initWithContentsOfFile:
|
||||
[[self bundle] pathForResource:soundname ofType:SOUND_TYPE] byReference:YES];
|
||||
if ([sound respondsToSelector:@selector(setVolume:)])
|
||||
[sound setVolume:soundVolume];
|
||||
[sound play];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) canContinueInput
|
||||
{
|
||||
if ([inputLock tryLockWhenCondition:NO_INPUT])
|
||||
[inputLock unlockWithCondition:INPUT];
|
||||
/* else
|
||||
User typed so fast that input would be lost, but the typeahead buffer keeps this input. */
|
||||
if ([inputLock tryLockWhenCondition:NO_INPUT])
|
||||
[inputLock unlockWithCondition:INPUT];
|
||||
/* else
|
||||
User typed so fast that input would be lost, but the typeahead buffer keeps this input. */
|
||||
}
|
||||
|
||||
|
||||
- (void) canContinueOutput
|
||||
{
|
||||
if ([outputLock tryLockWhenCondition:NO_OUTPUT])
|
||||
[outputLock unlockWithCondition:OUTPUT];
|
||||
if ([outputLock tryLockWhenCondition:NO_OUTPUT])
|
||||
[outputLock unlockWithCondition:OUTPUT];
|
||||
#if ! defined(NS_BLOCK_ASSERTIONS)
|
||||
else
|
||||
NSLog (@"PDP-8 software bug: TPC or TLS executed before preceding TTY output finished");
|
||||
else
|
||||
NSLog (@"PDP-8 software bug: TPC or TLS executed before preceding TTY output finished");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void) setTeletypeOutputFlag
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
[pdp8 setIOFlagBits:outflag];
|
||||
NSAssertRunningOnMainThread ();
|
||||
[pdp8 setIOFlagBits:outflag];
|
||||
}
|
||||
|
||||
|
||||
- (void) processInput
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
input &= 0377; // strip off Unicode characters etc.
|
||||
if (online) {
|
||||
[self setKBB:input];
|
||||
[pdp8 setIOFlagBits:inflag];
|
||||
} else {
|
||||
[self playSound:input];
|
||||
[punch putChar:input & punchMask handleBackspace:YES];
|
||||
[textview putChar:input & 0177];
|
||||
}
|
||||
NSAssertRunningOnMainThread ();
|
||||
input &= 0377; // strip off Unicode characters etc.
|
||||
if (online) {
|
||||
[self setKBB:input];
|
||||
[pdp8 setIOFlagBits:inflag];
|
||||
} else {
|
||||
[self playSound:input];
|
||||
[punch putChar:input & punchMask handleBackspace:YES];
|
||||
[textview putChar:input & 0177];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) processOutput
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
[self playSound:output];
|
||||
[self setTTO:output];
|
||||
[punch putChar:output & punchMask handleBackspace:NO];
|
||||
[textview putChar:output & 0177];
|
||||
NSAssertRunningOnMainThread ();
|
||||
[self playSound:output];
|
||||
[self setTTO:output];
|
||||
[punch putChar:output & punchMask handleBackspace:NO];
|
||||
[textview putChar:output & 0177];
|
||||
}
|
||||
|
||||
|
||||
- (void) getReaderChar
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
input = [reader getChar];
|
||||
NSAssertRunningOnMainThread ();
|
||||
input = [reader getChar];
|
||||
}
|
||||
|
||||
|
||||
- (uint64_t) realtimeDelay:(uint64_t)maTime
|
||||
{
|
||||
if (runWithRealtimeSpeed) {
|
||||
uint64_t us = absolute2nanoseconds(mach_absolute_time() - maTime) / 1000;
|
||||
if (us < TELETYPE_DELAY)
|
||||
usleep ((useconds_t)(TELETYPE_DELAY - us));
|
||||
maTime = mach_absolute_time();
|
||||
}
|
||||
return maTime;
|
||||
if (runWithRealtimeSpeed) {
|
||||
uint64_t us = absolute2nanoseconds(mach_absolute_time() - maTime) / 1000;
|
||||
if (us < TELETYPE_DELAY)
|
||||
usleep ((useconds_t)(TELETYPE_DELAY - us));
|
||||
maTime = mach_absolute_time();
|
||||
}
|
||||
return maTime;
|
||||
}
|
||||
|
||||
|
||||
- (void) asr33InputThread:(id)object
|
||||
{
|
||||
[[NSAutoreleasePool alloc] init];
|
||||
for (;;) {
|
||||
[inputLock lockWhenCondition:INPUT];
|
||||
uint64_t maTime = mach_absolute_time();
|
||||
while ((! online || [pdp8 getIOFlagBits:inflag] == 0) &&
|
||||
([self performSelectorOnMainThread:@selector(getReaderChar)
|
||||
withObject:nil waitUntilDone:YES], input != EOF)) {
|
||||
maTime = [self realtimeDelay:maTime];
|
||||
[self performSelectorOnMainThread:@selector(processInput)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
while ([typeaheadBuffer hasCharacters] &&
|
||||
(! online || [pdp8 isStopped] || [pdp8 getIOFlagBits:inflag] == 0)) {
|
||||
input = [typeaheadBuffer getNextChar] | 0200;
|
||||
maTime = [self realtimeDelay:maTime];
|
||||
[self performSelectorOnMainThread:@selector(processInput)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
[inputLock unlockWithCondition:NO_INPUT];
|
||||
}
|
||||
for (;;) {
|
||||
[inputLock lockWhenCondition:INPUT];
|
||||
uint64_t maTime = mach_absolute_time();
|
||||
while ((! online || [pdp8 getIOFlagBits:inflag] == 0) &&
|
||||
([self performSelectorOnMainThread:@selector(getReaderChar)
|
||||
withObject:nil waitUntilDone:YES], input != EOF)) {
|
||||
maTime = [self realtimeDelay:maTime];
|
||||
[self performSelectorOnMainThread:@selector(processInput)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
while ([typeaheadBuffer hasCharacters] &&
|
||||
(! online || [pdp8 isStopped] || [pdp8 getIOFlagBits:inflag] == 0)) {
|
||||
input = [typeaheadBuffer getNextChar] | 0200;
|
||||
maTime = [self realtimeDelay:maTime];
|
||||
[self performSelectorOnMainThread:@selector(processInput)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
[inputLock unlockWithCondition:NO_INPUT];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) asr33OutputThread:(id)object
|
||||
{
|
||||
[[NSAutoreleasePool alloc] init];
|
||||
[outputOnline lock];
|
||||
for (;;) {
|
||||
if (! online)
|
||||
[outputOnline wait];
|
||||
[outputLock lockWhenCondition:OUTPUT];
|
||||
uint64_t maTime = mach_absolute_time();
|
||||
[self performSelectorOnMainThread:@selector(processOutput)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
[self realtimeDelay:maTime];
|
||||
[outputLock unlockWithCondition:NO_OUTPUT];
|
||||
[self performSelectorOnMainThread:@selector(setTeletypeOutputFlag)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
[outputOnline lock];
|
||||
for (;;) {
|
||||
if (! online)
|
||||
[outputOnline wait];
|
||||
[outputLock lockWhenCondition:OUTPUT];
|
||||
uint64_t maTime = mach_absolute_time();
|
||||
[self performSelectorOnMainThread:@selector(processOutput)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
[self realtimeDelay:maTime];
|
||||
[outputLock unlockWithCondition:NO_OUTPUT];
|
||||
[self performSelectorOnMainThread:@selector(setTeletypeOutputFlag)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -353,46 +352,46 @@ API_VERSION
|
|||
|
||||
- (unsigned short) getKBB
|
||||
{
|
||||
return KBB;
|
||||
return KBB;
|
||||
}
|
||||
|
||||
|
||||
- (void) setKBB:(unsigned short)kbb
|
||||
{
|
||||
NSAssert1 ((kbb & ~0377) == 0, @"Bad KBB: 0%o", kbb);
|
||||
KBB = kbb;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBB_CHANGED_NOTIFICATION object:self];
|
||||
NSAssert1 ((kbb & ~0377) == 0, @"Bad KBB: 0%o", kbb);
|
||||
KBB = kbb;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KBB_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getTTO
|
||||
{
|
||||
return TTO;
|
||||
return TTO;
|
||||
}
|
||||
|
||||
|
||||
- (void) setTTO:(unsigned short)tto
|
||||
{
|
||||
NSAssert1 ((tto & ~0377) == 0, @"Bad TTO: 0%o", tto);
|
||||
TTO = tto;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:TTO_CHANGED_NOTIFICATION object:self];
|
||||
NSAssert1 ((tto & ~0377) == 0, @"Bad TTO: 0%o", tto);
|
||||
TTO = tto;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:TTO_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) getOnline
|
||||
{
|
||||
return online;
|
||||
return online;
|
||||
}
|
||||
|
||||
|
||||
- (void) setOnline:(BOOL)onlineOffline
|
||||
{
|
||||
online = onlineOffline;
|
||||
[outputOnline signal];
|
||||
if (! online)
|
||||
[self canContinueInput];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:TTY_ONLINE_CHANGED_NOTIFICATION object:self];
|
||||
online = onlineOffline;
|
||||
[outputOnline signal];
|
||||
if (! online)
|
||||
[self canContinueInput];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:TTY_ONLINE_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
|
@ -401,83 +400,84 @@ API_VERSION
|
|||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
[self setKBB:[coder decodeIntForKey:CODER_KEY_KBB]];
|
||||
[self setTTO:[coder decodeIntForKey:CODER_KEY_TTO]];
|
||||
[coder decodeBoolForKey:CODER_KEY_INFLAG] ?
|
||||
[pdp8 setIOFlagBits:inflag] : [pdp8 clearIOFlagBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_INMASK] ?
|
||||
[pdp8 setInterruptMaskBits:inflag] : [pdp8 clearInterruptMaskBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTFLAG] ?
|
||||
[pdp8 setIOFlagBits:outflag] : [pdp8 clearIOFlagBits:outflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTMASK] ?
|
||||
[pdp8 setInterruptMaskBits:outflag] : [pdp8 clearInterruptMaskBits:outflag];
|
||||
[self setOnline:[coder decodeBoolForKey:CODER_KEY_ONLINE]];
|
||||
return self;
|
||||
self = [super init];
|
||||
[self loadCoder: coder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) loadCoder:(NSCoder *)coder {
|
||||
[self setKBB:[coder decodeIntForKey:CODER_KEY_KBB]];
|
||||
[self setTTO:[coder decodeIntForKey:CODER_KEY_TTO]];
|
||||
[coder decodeBoolForKey:CODER_KEY_INFLAG] ?
|
||||
[pdp8 setIOFlagBits:inflag] : [pdp8 clearIOFlagBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_INMASK] ?
|
||||
[pdp8 setInterruptMaskBits:inflag] : [pdp8 clearInterruptMaskBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTFLAG] ?
|
||||
[pdp8 setIOFlagBits:outflag] : [pdp8 clearIOFlagBits:outflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTMASK] ?
|
||||
[pdp8 setInterruptMaskBits:outflag] : [pdp8 clearInterruptMaskBits:outflag];
|
||||
[self setOnline:[coder decodeBoolForKey:CODER_KEY_ONLINE]];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeInt:[self getKBB] forKey:CODER_KEY_KBB];
|
||||
[coder encodeInt:[self getTTO] forKey:CODER_KEY_TTO];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:inflag] ? YES : NO forKey:CODER_KEY_INFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:inflag] ? YES : NO forKey:CODER_KEY_INMASK];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:outflag] ? YES : NO forKey:CODER_KEY_OUTFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:outflag] ? YES : NO forKey:CODER_KEY_OUTMASK];
|
||||
[coder encodeBool:[self getOnline] forKey:CODER_KEY_ONLINE];
|
||||
[coder encodeInt:[self getKBB] forKey:CODER_KEY_KBB];
|
||||
[coder encodeInt:[self getTTO] forKey:CODER_KEY_TTO];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:inflag] ? YES : NO forKey:CODER_KEY_INFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:inflag] ? YES : NO forKey:CODER_KEY_INMASK];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:outflag] ? YES : NO forKey:CODER_KEY_OUTFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:outflag] ? YES : NO forKey:CODER_KEY_OUTMASK];
|
||||
[coder encodeBool:[self getOnline] forKey:CODER_KEY_ONLINE];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"ASR33 notifyApplicationWillTerminate");
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[archiver release];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
// NSLog (@"ASR33 notifyApplicationWillTerminate");
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPreferencesChanged:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"ASR33 notifyPreferencesChanged");
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
runWithRealtimeSpeed = [defaults integerForKey:ASR33_PREFS_SPEED_KEY];
|
||||
playSound = runWithRealtimeSpeed && [defaults boolForKey:ASR33_PREFS_PLAY_SOUND];
|
||||
soundVolume = [defaults objectForKey:ASR33_PREFS_SOUND_VOLUME] ?
|
||||
[defaults floatForKey:ASR33_PREFS_SOUND_VOLUME] : 0.5f;
|
||||
punchMask = [defaults boolForKey:ASR33_PREFS_MASK_HIGHBIT_KEY] ? 0177 : 0377;
|
||||
// NSLog (@"ASR33 notifyPreferencesChanged");
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
runWithRealtimeSpeed = [defaults integerForKey:ASR33_PREFS_SPEED_KEY];
|
||||
playSound = runWithRealtimeSpeed && [defaults boolForKey:ASR33_PREFS_PLAY_SOUND];
|
||||
soundVolume = [defaults objectForKey:ASR33_PREFS_SOUND_VOLUME] ?
|
||||
[defaults floatForKey:ASR33_PREFS_SOUND_VOLUME] : 0.5f;
|
||||
punchMask = [defaults boolForKey:ASR33_PREFS_MASK_HIGHBIT_KEY] ? 0177 : 0377;
|
||||
}
|
||||
|
||||
|
||||
- (void) pluginDidLoad
|
||||
{
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self initWithCoder:unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
[unarchiver release];
|
||||
} else
|
||||
[self setOnline:YES];
|
||||
inputLock = [[NSConditionLock alloc] initWithCondition:NO_INPUT];
|
||||
outputLock = [[NSConditionLock alloc] initWithCondition:NO_OUTPUT];
|
||||
outputOnline = [[NSCondition alloc] init];
|
||||
[NSThread detachNewThreadSelector:@selector(asr33InputThread:) toTarget:self withObject:nil];
|
||||
[NSThread detachNewThreadSelector:@selector(asr33OutputThread:) toTarget:self withObject:nil];
|
||||
[windowController setWindowTitle:[[self pluginName] stringByDeletingPathExtension]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPreferencesChanged:)
|
||||
name:NSUserDefaultsDidChangeNotification object:nil];
|
||||
[self notifyPreferencesChanged:nil];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self loadCoder:unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
} else
|
||||
[self setOnline:YES];
|
||||
inputLock = [[NSConditionLock alloc] initWithCondition:NO_INPUT];
|
||||
outputLock = [[NSConditionLock alloc] initWithCondition:NO_OUTPUT];
|
||||
outputOnline = [[NSCondition alloc] init];
|
||||
[NSThread detachNewThreadSelector:@selector(asr33InputThread:) toTarget:self withObject:nil];
|
||||
[NSThread detachNewThreadSelector:@selector(asr33OutputThread:) toTarget:self withObject:nil];
|
||||
[windowController setWindowTitle:[[self pluginName] stringByDeletingPathExtension]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPreferencesChanged:)
|
||||
name:NSUserDefaultsDidChangeNotification object:nil];
|
||||
[self notifyPreferencesChanged:nil];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* ASR33TextView.m - NSTextView for the ASR 33 Teletype
|
||||
* ASR33TextView.m - NSTextView for the ASR 33 Teletype
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -33,128 +33,128 @@
|
|||
|
||||
- (BOOL) validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem >)item
|
||||
{
|
||||
SEL action = [item action];
|
||||
return (action == @selector(copy:) ||
|
||||
action == @selector(paste:) ||
|
||||
action == @selector(selectAll:) ||
|
||||
action == @selector(_learnSpellingFromMenu:) ||
|
||||
action == @selector(spotlight:) ||
|
||||
action == @selector(_searchWithGoogleFromMenu:) ||
|
||||
action == @selector(_lookUpIndefiniteRangeInDictionaryFromMenu:) ||
|
||||
action == @selector(startSpeaking:) ||
|
||||
action == @selector(stopSpeaking:)) ?
|
||||
[super validateUserInterfaceItem:item] : FALSE;
|
||||
SEL action = [item action];
|
||||
return (action == @selector(copy:) ||
|
||||
action == @selector(paste:) ||
|
||||
action == @selector(selectAll:) ||
|
||||
action == @selector(_learnSpellingFromMenu:) ||
|
||||
action == @selector(spotlight:) ||
|
||||
action == @selector(_searchWithGoogleFromMenu:) ||
|
||||
action == @selector(_lookUpIndefiniteRangeInDictionaryFromMenu:) ||
|
||||
action == @selector(startSpeaking:) ||
|
||||
action == @selector(stopSpeaking:)) ?
|
||||
[super validateUserInterfaceItem:item] : FALSE;
|
||||
}
|
||||
|
||||
|
||||
- (void) doCommandBySelector:(SEL)selector
|
||||
{
|
||||
NSString *selectorName = NSStringFromSelector(selector);
|
||||
// NSLog (@"doCommandByselector %@", selectorName);
|
||||
if (selector == @selector(insertNewline:))
|
||||
[typeaheadBuffer typeahead:@"\r"];
|
||||
else if (selector == @selector(deleteBackward:))
|
||||
[typeaheadBuffer typeahead:@"\b"];
|
||||
else if (selector == @selector(deleteForward:))
|
||||
[typeaheadBuffer typeahead:@"\177"]; // Rubout
|
||||
else if (selector == @selector(cancelOperation:))
|
||||
[typeaheadBuffer typeahead:@"\033"]; // Escape
|
||||
else if (selector == @selector(centerSelectionInVisibleArea:))
|
||||
[typeaheadBuffer typeahead:@"\f"]; // Ctrl-L
|
||||
else if (selector == @selector(pageDown:))
|
||||
[typeaheadBuffer typeahead:@"\026"]; // Ctrl-V
|
||||
else if (selector == @selector(noop:)) {
|
||||
NSEvent *currentEvent = [NSApp currentEvent];
|
||||
unsigned modifierFlags = [currentEvent modifierFlags];
|
||||
unsigned c = [[currentEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
if (modifierFlags & NSEventModifierFlagControl) {
|
||||
switch (c) {
|
||||
case 'c' :
|
||||
case 'C' :
|
||||
[typeaheadBuffer typeahead:@"\003"]; // Ctrl-C
|
||||
break;
|
||||
case 'z' :
|
||||
case 'Z' :
|
||||
[typeaheadBuffer typeahead:@"\032"]; // Ctrl-Z
|
||||
break;
|
||||
default :
|
||||
NSLog (@"character %c (%o) ignored", c, c);
|
||||
break;
|
||||
}
|
||||
} else if (modifierFlags & NSEventModifierFlagFunction) {
|
||||
if (c == 0xf739) // fn-6 = forward delete on notebook keyboards
|
||||
[typeaheadBuffer typeahead:@"\177"]; // Rubout
|
||||
}
|
||||
} else if (selector != @selector(complete:) &&
|
||||
! [selectorName hasPrefix:@"delete"]) // ignore all delete* selectors
|
||||
[super doCommandBySelector:selector];
|
||||
NSString *selectorName = NSStringFromSelector(selector);
|
||||
// NSLog (@"doCommandByselector %@", selectorName);
|
||||
if (selector == @selector(insertNewline:))
|
||||
[typeaheadBuffer typeahead:@"\r"];
|
||||
else if (selector == @selector(deleteBackward:))
|
||||
[typeaheadBuffer typeahead:@"\b"];
|
||||
else if (selector == @selector(deleteForward:))
|
||||
[typeaheadBuffer typeahead:@"\177"]; // Rubout
|
||||
else if (selector == @selector(cancelOperation:))
|
||||
[typeaheadBuffer typeahead:@"\033"]; // Escape
|
||||
else if (selector == @selector(centerSelectionInVisibleArea:))
|
||||
[typeaheadBuffer typeahead:@"\f"]; // Ctrl-L
|
||||
else if (selector == @selector(pageDown:))
|
||||
[typeaheadBuffer typeahead:@"\026"]; // Ctrl-V
|
||||
else if (selector == @selector(noop:)) {
|
||||
NSEvent *currentEvent = [NSApp currentEvent];
|
||||
unsigned modifierFlags = [currentEvent modifierFlags];
|
||||
unsigned c = [[currentEvent charactersIgnoringModifiers] characterAtIndex:0];
|
||||
if (modifierFlags & NSEventModifierFlagControl) {
|
||||
switch (c) {
|
||||
case 'c' :
|
||||
case 'C' :
|
||||
[typeaheadBuffer typeahead:@"\003"]; // Ctrl-C
|
||||
break;
|
||||
case 'z' :
|
||||
case 'Z' :
|
||||
[typeaheadBuffer typeahead:@"\032"]; // Ctrl-Z
|
||||
break;
|
||||
default :
|
||||
NSLog (@"character %c (%o) ignored", c, c);
|
||||
break;
|
||||
}
|
||||
} else if (modifierFlags & NSEventModifierFlagFunction) {
|
||||
if (c == 0xf739) // fn-6 = forward delete on notebook keyboards
|
||||
[typeaheadBuffer typeahead:@"\177"]; // Rubout
|
||||
}
|
||||
} else if (selector != @selector(complete:) &&
|
||||
! [selectorName hasPrefix:@"delete"]) // ignore all delete* selectors
|
||||
[super doCommandBySelector:selector];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) readSelectionFromPasteboard:(NSPasteboard *)pasteboard type:(NSString *)type
|
||||
{
|
||||
[pasteboard types]; // required before accessing the pasteboards data
|
||||
if ([type isEqualToString:NSStringPboardType]) {
|
||||
[typeaheadBuffer typeahead:[pasteboard stringForType:type]];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
[pasteboard types]; // required before accessing the pasteboards data
|
||||
if ([type isEqualToString:NSStringPboardType]) {
|
||||
[typeaheadBuffer typeahead:[pasteboard stringForType:type]];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (void) insertText:(NSString *)string
|
||||
{
|
||||
[typeaheadBuffer typeahead:string];
|
||||
[typeaheadBuffer typeahead:string];
|
||||
}
|
||||
|
||||
|
||||
- (void) putChar:(unichar)c
|
||||
{
|
||||
NSTextStorage *storage = [self textStorage];
|
||||
NSUInteger length = [storage length];
|
||||
NSRange endOfText = NSMakeRange(length, 0);
|
||||
[self scrollRangeToVisible:endOfText];
|
||||
[self setSelectedRange:endOfText];
|
||||
switch (c) {
|
||||
case '\a' :
|
||||
// NSBeep (); // handled by the ASR33 method playSound:
|
||||
break;
|
||||
case '\b' :
|
||||
if (length && [[storage string] characterAtIndex:length - 1] != '\n')
|
||||
[super deleteBackward:self];
|
||||
break;
|
||||
default :
|
||||
[super insertText:[NSString stringWithCharacters:&c length:1] replacementRange:[self selectedRange]];
|
||||
break;
|
||||
}
|
||||
NSTextStorage *storage = [self textStorage];
|
||||
NSUInteger length = [storage length];
|
||||
NSRange endOfText = NSMakeRange(length, 0);
|
||||
[self scrollRangeToVisible:endOfText];
|
||||
[self setSelectedRange:endOfText];
|
||||
switch (c) {
|
||||
case '\a' :
|
||||
// NSBeep (); // handled by the ASR33 method playSound:
|
||||
break;
|
||||
case '\b' :
|
||||
if (length && [[storage string] characterAtIndex:length - 1] != '\n')
|
||||
[super deleteBackward:self];
|
||||
break;
|
||||
default :
|
||||
[super insertText:[NSString stringWithCharacters:&c length:1] replacementRange:[self selectedRange]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
// set size of container - to make horizontal scroller appear
|
||||
NSTextContainer *container = [self textContainer];
|
||||
NSSize size = [container containerSize];
|
||||
size.width = UINT_MAX;
|
||||
[container setContainerSize:size];
|
||||
[container setWidthTracksTextView:NO];
|
||||
|
||||
// set default font
|
||||
NSFont *font = [NSFont userFixedPitchFontOfSize:11];
|
||||
[self setFont:font];
|
||||
// set size of container - to make horizontal scroller appear
|
||||
NSTextContainer *container = [self textContainer];
|
||||
NSSize size = [container containerSize];
|
||||
size.width = UINT_MAX;
|
||||
[container setContainerSize:size];
|
||||
[container setWidthTracksTextView:NO];
|
||||
|
||||
// set default font
|
||||
NSFont *font = [NSFont userFixedPitchFontOfSize:11];
|
||||
[self setFont:font];
|
||||
|
||||
// set tabstop every 8 character
|
||||
NSMutableParagraphStyle *style = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
|
||||
[style setTabStops:[NSArray array]];
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
|
||||
NSAttributedString *str =
|
||||
[[[NSAttributedString alloc] initWithString:@" " attributes:attrs] autorelease];
|
||||
[style setDefaultTabInterval:8 * [str size].width /* == 7 */];
|
||||
[self setTypingAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
style, NSParagraphStyleAttributeName, font, NSFontAttributeName, nil]];
|
||||
if ([self respondsToSelector:@selector(setAutomaticTextReplacementEnabled:)])
|
||||
[self performSelector:@selector(setAutomaticTextReplacementEnabled:)
|
||||
withObject:(NSObject *) NO];
|
||||
// set tabstop every 8 character
|
||||
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[style setTabStops:[NSArray array]];
|
||||
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
|
||||
NSAttributedString *str =
|
||||
[[NSAttributedString alloc] initWithString:@" " attributes:attrs];
|
||||
[style setDefaultTabInterval:8 * [str size].width /* == 7 */];
|
||||
[self setTypingAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
style, NSParagraphStyleAttributeName, font, NSFontAttributeName, nil]];
|
||||
if ([self respondsToSelector:@selector(setAutomaticTextReplacementEnabled:)])
|
||||
[self performSelector:@selector(setAutomaticTextReplacementEnabled:)
|
||||
withObject:(NSObject *) NO];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@class ASR33, PaperTapeController, ASR33TextView, RegisterFormCell, KeepInMenuWindow;
|
||||
|
||||
|
||||
@interface ASR33WindowController : NSObject
|
||||
@interface ASR33WindowController : NSObject <NSToolbarDelegate>
|
||||
{
|
||||
@private
|
||||
IBOutlet ASR33 *asr33;
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* ASR33WindowController.h - ASR 33 Teletype Window Controller
|
||||
* ASR33WindowController.h - ASR 33 Teletype Window Controller
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
|||
#import "PluginFramework/Utilities.h"
|
||||
#import "PluginFramework/InputConsumerProtocol.h"
|
||||
#import "PluginFramework/RegisterFormCell.h"
|
||||
#import "PluginFramework/PaperTapeController.h"
|
||||
|
||||
#import "ASR33WindowController.h"
|
||||
#import "ASR33.h"
|
||||
|
@ -37,9 +38,9 @@
|
|||
@implementation ASR33WindowController
|
||||
|
||||
|
||||
#define TTY_TOOLBAR_ITEM_IDENTIFIER @"ttyTBItemIdentifier"
|
||||
#define READER_TOOLBAR_ITEM_IDENTIFIER @"readerTBItemIdentifier"
|
||||
#define PUNCH_TOOLBAR_ITEM_IDENTIFIER @"punchTBItemIdentifier"
|
||||
#define TTY_TOOLBAR_ITEM_IDENTIFIER @"ttyTBItemIdentifier"
|
||||
#define READER_TOOLBAR_ITEM_IDENTIFIER @"readerTBItemIdentifier"
|
||||
#define PUNCH_TOOLBAR_ITEM_IDENTIFIER @"punchTBItemIdentifier"
|
||||
|
||||
|
||||
#pragma mark Toolbar
|
||||
|
@ -47,107 +48,107 @@
|
|||
|
||||
- (void) setupToolbar
|
||||
{
|
||||
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:@"ASR33WindowToolbar"] autorelease];
|
||||
[toolbar setAllowsUserCustomization:NO];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setDisplayMode:NSToolbarDisplayModeIconAndLabel];
|
||||
[toolbar setSizeMode:NSToolbarSizeModeDefault];
|
||||
[toolbar setDelegate:self];
|
||||
[window setToolbar:toolbar];
|
||||
[window setShowsToolbarButton:YES];
|
||||
adjustToolbarControlForTiger ([kbb controlView]);
|
||||
adjustToolbarControlForTiger ([tto controlView]);
|
||||
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"ASR33WindowToolbar"];
|
||||
[toolbar setAllowsUserCustomization:NO];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setDisplayMode:NSToolbarDisplayModeIconAndLabel];
|
||||
[toolbar setSizeMode:NSToolbarSizeModeDefault];
|
||||
[toolbar setDelegate:self];
|
||||
[window setToolbar:toolbar];
|
||||
[window setShowsToolbarButton:YES];
|
||||
adjustToolbarControlForTiger ([kbb controlView]);
|
||||
adjustToolbarControlForTiger ([tto controlView]);
|
||||
}
|
||||
|
||||
|
||||
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdent
|
||||
willBeInsertedIntoToolbar:(BOOL)willBeInserted
|
||||
willBeInsertedIntoToolbar:(BOOL)willBeInserted
|
||||
{
|
||||
NSRect rect;
|
||||
NSRect rect;
|
||||
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdent] autorelease];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdent];
|
||||
|
||||
if ([itemIdent isEqual:TTY_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"ASR 33 Teletype", nil, bundle, @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"ASR 33 Teletype", nil, bundle, @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedStringFromTableInBundle(
|
||||
@"This area contains the registers and switches of the ASR 33 teletype",
|
||||
nil, bundle, @"")];
|
||||
[toolbarItem setView:ttyToolbarView];
|
||||
rect = [ttyToolbarView frame];
|
||||
[toolbarItem setMinSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
[toolbarItem setMaxSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
} else if ([itemIdent isEqual:READER_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Reader", nil, bundle, @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Reader", nil, bundle, @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedStringFromTableInBundle(
|
||||
@"This area displays the state of the low speed paper tape reader",
|
||||
nil, bundle, @"")];
|
||||
[toolbarItem setView:readerToolbarView];
|
||||
rect = [readerToolbarView frame];
|
||||
[toolbarItem setMinSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
[toolbarItem setMaxSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
} else if ([itemIdent isEqual:PUNCH_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Punch", nil, bundle, @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Punch", nil, bundle, @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedStringFromTableInBundle(
|
||||
@"This area displays the state of the low speed paper tape punch",
|
||||
nil, bundle, @"")];
|
||||
[toolbarItem setView:punchToolbarView];
|
||||
rect = [punchToolbarView frame];
|
||||
[toolbarItem setMinSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
[toolbarItem setMaxSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
} else
|
||||
toolbarItem = nil;
|
||||
return toolbarItem;
|
||||
if ([itemIdent isEqual:TTY_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"ASR 33 Teletype", nil, bundle, @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"ASR 33 Teletype", nil, bundle, @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedStringFromTableInBundle(
|
||||
@"This area contains the registers and switches of the ASR 33 teletype",
|
||||
nil, bundle, @"")];
|
||||
[toolbarItem setView:ttyToolbarView];
|
||||
rect = [ttyToolbarView frame];
|
||||
[toolbarItem setMinSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
[toolbarItem setMaxSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
} else if ([itemIdent isEqual:READER_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Reader", nil, bundle, @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Reader", nil, bundle, @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedStringFromTableInBundle(
|
||||
@"This area displays the state of the low speed paper tape reader",
|
||||
nil, bundle, @"")];
|
||||
[toolbarItem setView:readerToolbarView];
|
||||
rect = [readerToolbarView frame];
|
||||
[toolbarItem setMinSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
[toolbarItem setMaxSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
} else if ([itemIdent isEqual:PUNCH_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Punch", nil, bundle, @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedStringFromTableInBundle(
|
||||
@"Low Speed Paper Tape Punch", nil, bundle, @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedStringFromTableInBundle(
|
||||
@"This area displays the state of the low speed paper tape punch",
|
||||
nil, bundle, @"")];
|
||||
[toolbarItem setView:punchToolbarView];
|
||||
rect = [punchToolbarView frame];
|
||||
[toolbarItem setMinSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
[toolbarItem setMaxSize:NSMakeSize(NSWidth(rect), NSHeight(rect))];
|
||||
} else
|
||||
toolbarItem = nil;
|
||||
return toolbarItem;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
TTY_TOOLBAR_ITEM_IDENTIFIER, NSToolbarSeparatorItemIdentifier,
|
||||
READER_TOOLBAR_ITEM_IDENTIFIER, NSToolbarSeparatorItemIdentifier,
|
||||
PUNCH_TOOLBAR_ITEM_IDENTIFIER,
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
TTY_TOOLBAR_ITEM_IDENTIFIER, NSToolbarSeparatorItemIdentifier,
|
||||
READER_TOOLBAR_ITEM_IDENTIFIER, NSToolbarSeparatorItemIdentifier,
|
||||
PUNCH_TOOLBAR_ITEM_IDENTIFIER,
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
TTY_TOOLBAR_ITEM_IDENTIFIER, READER_TOOLBAR_ITEM_IDENTIFIER,
|
||||
PUNCH_TOOLBAR_ITEM_IDENTIFIER, NSToolbarSeparatorItemIdentifier,
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
TTY_TOOLBAR_ITEM_IDENTIFIER, READER_TOOLBAR_ITEM_IDENTIFIER,
|
||||
PUNCH_TOOLBAR_ITEM_IDENTIFIER, NSToolbarSeparatorItemIdentifier,
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) windowDidBecomeMain:(NSNotification *)notification
|
||||
{
|
||||
if (runningOnLionOrNewer()) {
|
||||
[kbb setEnabled:YES];
|
||||
[tto setEnabled:YES];
|
||||
[readerController setEnabled:YES];
|
||||
[punchController setEnabled:YES];
|
||||
}
|
||||
if (runningOnLionOrNewer()) {
|
||||
[kbb setEnabled:YES];
|
||||
[tto setEnabled:YES];
|
||||
[readerController setEnabled:YES];
|
||||
[punchController setEnabled:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) windowDidResignMain:(NSNotification *)notification
|
||||
{
|
||||
if (runningOnLionOrNewer()) {
|
||||
[kbb setEnabled:NO];
|
||||
[tto setEnabled:NO];
|
||||
[readerController setEnabled:NO];
|
||||
[punchController setEnabled:NO];
|
||||
}
|
||||
if (runningOnLionOrNewer()) {
|
||||
[kbb setEnabled:NO];
|
||||
[tto setEnabled:NO];
|
||||
[readerController setEnabled:NO];
|
||||
[punchController setEnabled:NO];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,38 +157,38 @@
|
|||
|
||||
- (void) windowWillBeginSheet:(NSNotification *)notification
|
||||
{
|
||||
[localOnline setEnabled:NO];
|
||||
[kbb setEnabled:NO];
|
||||
[tto setEnabled:NO];
|
||||
[readerController setEnabled:NO];
|
||||
[punchController setEnabled:NO];
|
||||
[localOnline setEnabled:NO];
|
||||
[kbb setEnabled:NO];
|
||||
[tto setEnabled:NO];
|
||||
[readerController setEnabled:NO];
|
||||
[punchController setEnabled:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void) windowDidEndSheet:(NSNotification *)notification;
|
||||
{
|
||||
[localOnline setEnabled:YES];
|
||||
[kbb setEnabled:YES];
|
||||
[tto setEnabled:YES];
|
||||
[readerController setEnabled:YES];
|
||||
[punchController setEnabled:YES];
|
||||
[localOnline setEnabled:YES];
|
||||
[kbb setEnabled:YES];
|
||||
[tto setEnabled:YES];
|
||||
[readerController setEnabled:YES];
|
||||
[punchController setEnabled:YES];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPluginsLoaded:(NSNotification *)notification
|
||||
{
|
||||
[self windowDidResignMain:notification];
|
||||
[window orderBackFromDefaults:self];
|
||||
[self windowDidResignMain:notification];
|
||||
[window orderBackFromDefaults:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) setupNotifications
|
||||
{
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyOnlineChanged:) name:TTY_ONLINE_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyOnlineChanged:) name:TTY_ONLINE_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
}
|
||||
|
||||
|
||||
|
@ -196,13 +197,13 @@
|
|||
|
||||
- (IBAction) localOnlineClicked:(id)sender
|
||||
{
|
||||
[asr33 setOnline:[sender selectedSegment]];
|
||||
[asr33 setOnline:[sender selectedSegment]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyOnlineChanged:(NSNotification *)notification
|
||||
{
|
||||
[localOnline setSelectedSegment:[asr33 getOnline]];
|
||||
[localOnline setSelectedSegment:[asr33 getOnline]];
|
||||
}
|
||||
|
||||
|
||||
|
@ -211,31 +212,31 @@
|
|||
|
||||
- (void) setWindowTitle:(NSString *)title
|
||||
{
|
||||
BOOL isAuxTTY = ! [[window title] isEqualToString:title];
|
||||
NSRect oldFrame = [window frame];
|
||||
[window setTitle:title];
|
||||
[window setFrameAutosaveName:title];
|
||||
/* this is a hack to move the AuxTTY window away from the exact position of the ConTTY when the
|
||||
simulator starts for the first time without existing preferences file */
|
||||
if (isAuxTTY && NSEqualRects(oldFrame, [window frame]))
|
||||
[window setFrameOrigin:NSMakePoint(oldFrame.origin.x + 20, oldFrame.origin.y - 20)];
|
||||
BOOL isAuxTTY = ! [[window title] isEqualToString:title];
|
||||
NSRect oldFrame = [window frame];
|
||||
[window setTitle:title];
|
||||
[window setFrameAutosaveName:title];
|
||||
/* this is a hack to move the AuxTTY window away from the exact position of the ConTTY when the
|
||||
simulator starts for the first time without existing preferences file */
|
||||
if (isAuxTTY && NSEqualRects(oldFrame, [window frame]))
|
||||
[window setFrameOrigin:NSMakePoint(oldFrame.origin.x + 20, oldFrame.origin.y - 20)];
|
||||
}
|
||||
|
||||
|
||||
- (void) setupRegisters
|
||||
{
|
||||
[kbb setupRegisterFor:asr33 getRegisterValue:@selector(getKBB) setRegisterValue:@selector(setKBB:)
|
||||
changedNotificationName:KBB_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
[tto setupRegisterFor:asr33 getRegisterValue:@selector(getTTO) setRegisterValue:@selector(setTTO:)
|
||||
changedNotificationName:TTO_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
[kbb setupRegisterFor:asr33 getRegisterValue:@selector(getKBB) setRegisterValue:@selector(setKBB:)
|
||||
changedNotificationName:KBB_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
[tto setupRegisterFor:asr33 getRegisterValue:@selector(getTTO) setRegisterValue:@selector(setTTO:)
|
||||
changedNotificationName:TTO_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
[self setupToolbar];
|
||||
[self setupNotifications];
|
||||
[self setupRegisters];
|
||||
[self setupToolbar];
|
||||
[self setupNotifications];
|
||||
[self setupRegisters];
|
||||
}
|
||||
|
||||
|
||||
|
|
2061
ASR33/English.lproj/ASR33.nib/designable.nib
generated
2061
ASR33/English.lproj/ASR33.nib/designable.nib
generated
File diff suppressed because it is too large
Load Diff
BIN
ASR33/English.lproj/ASR33.nib/keyedobjects.nib
generated
BIN
ASR33/English.lproj/ASR33.nib/keyedobjects.nib
generated
Binary file not shown.
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* TypeaheadBuffer.m - Typeahead buffer for a keyboard input device
|
||||
* TypeaheadBuffer.m - Typeahead buffer for a keyboard input device
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -33,58 +33,58 @@
|
|||
@implementation TypeaheadBuffer
|
||||
|
||||
|
||||
#define MIN_LENGTH_TO_SHOW_FLUSH_TYPEAHEAD_BUTTON 5
|
||||
#define MIN_LENGTH_TO_SHOW_FLUSH_TYPEAHEAD_BUTTON 5
|
||||
|
||||
|
||||
- (IBAction) flush:(id)sender
|
||||
{
|
||||
[typeaheadBuffer deleteCharactersInRange:NSMakeRange(0, [typeaheadBuffer length])];
|
||||
[flushTypeaheadBufferButton setHidden:YES];
|
||||
[typeaheadBuffer deleteCharactersInRange:NSMakeRange(0, [typeaheadBuffer length])];
|
||||
[flushTypeaheadBufferButton setHidden:YES];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) hasCharacters
|
||||
{
|
||||
return [typeaheadBuffer length] > 0;
|
||||
return [typeaheadBuffer length] > 0;
|
||||
}
|
||||
|
||||
|
||||
- (signed short) getNextChar
|
||||
{
|
||||
signed short c = 0;
|
||||
NSUInteger length = [typeaheadBuffer length];
|
||||
if (length < MIN_LENGTH_TO_SHOW_FLUSH_TYPEAHEAD_BUTTON)
|
||||
[flushTypeaheadBufferButton setHidden:YES];
|
||||
if (length > 0) {
|
||||
c = [typeaheadBuffer characterAtIndex:0];
|
||||
[typeaheadBuffer deleteCharactersInRange:NSMakeRange(0, 1)];
|
||||
}
|
||||
return c;
|
||||
signed short c = 0;
|
||||
NSUInteger length = [typeaheadBuffer length];
|
||||
if (length < MIN_LENGTH_TO_SHOW_FLUSH_TYPEAHEAD_BUTTON)
|
||||
[flushTypeaheadBufferButton setHidden:YES];
|
||||
if (length > 0) {
|
||||
c = [typeaheadBuffer characterAtIndex:0];
|
||||
[typeaheadBuffer deleteCharactersInRange:NSMakeRange(0, 1)];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
- (void) typeahead:(NSString *)string
|
||||
{
|
||||
NSUInteger length = [typeaheadBuffer length];
|
||||
[typeaheadBuffer appendString:string];
|
||||
if ([typeaheadBuffer length] >= MIN_LENGTH_TO_SHOW_FLUSH_TYPEAHEAD_BUTTON)
|
||||
[flushTypeaheadBufferButton setHidden:NO];
|
||||
if (length == 0)
|
||||
[inputConsumer canContinueInput];
|
||||
NSUInteger length = [typeaheadBuffer length];
|
||||
[typeaheadBuffer appendString:string];
|
||||
if ([typeaheadBuffer length] >= MIN_LENGTH_TO_SHOW_FLUSH_TYPEAHEAD_BUTTON)
|
||||
[flushTypeaheadBufferButton setHidden:NO];
|
||||
if (length == 0)
|
||||
[inputConsumer canContinueInput];
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
if (runningOnTiger()) {
|
||||
NSPoint p = [flushTypeaheadBufferButton frame].origin;
|
||||
p.x += 2; p.y += 1;
|
||||
[flushTypeaheadBufferButton setFrameOrigin:p];
|
||||
[flushTypeaheadBufferButton setBezelStyle:NSRoundRectBezelStyle];
|
||||
[flushTypeaheadBufferButton setShowsBorderOnlyWhileMouseInside:NO];
|
||||
[[flushTypeaheadBufferButton cell] setImagePosition:NSNoImage];
|
||||
}
|
||||
typeaheadBuffer = [[NSMutableString stringWithCapacity:128] retain];
|
||||
if (runningOnTiger()) {
|
||||
NSPoint p = [flushTypeaheadBufferButton frame].origin;
|
||||
p.x += 2; p.y += 1;
|
||||
[flushTypeaheadBufferButton setFrameOrigin:p];
|
||||
[flushTypeaheadBufferButton setBezelStyle:NSRoundRectBezelStyle];
|
||||
[flushTypeaheadBufferButton setShowsBorderOnlyWhileMouseInside:NO];
|
||||
[[flushTypeaheadBufferButton cell] setImagePosition:NSNoImage];
|
||||
}
|
||||
typeaheadBuffer = [NSMutableString stringWithCapacity:128];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,6 @@
|
|||
}
|
||||
|
||||
- (IBAction) handleContextMenu:(id)sender;
|
||||
- (NSString *) operandInfoAtAddress:(int)addr; // private delegate method, declared here to avoid warning
|
||||
- (NSString *) operandInfoAtAddress:(NSInteger)addr; // private delegate method, declared here to avoid warning
|
||||
|
||||
@end
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -25,7 +25,7 @@
|
|||
@class RegisterFormCell, EnableDisableTextField, PDP8;
|
||||
|
||||
|
||||
@interface CPUWindowController : NSObject
|
||||
@interface CPUWindowController : NSObject <NSToolbarDelegate>
|
||||
{
|
||||
@private
|
||||
IBOutlet NSWindow *window;
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* CPUWindowController.m - Controller for the CPU window
|
||||
* CPUWindowController.m - Controller for the CPU window
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
|||
#import "MainController.h"
|
||||
#import "PDP8.h"
|
||||
#import "RegisterFormCell.h"
|
||||
#import "EnableDisableTextField.h"
|
||||
#import "GeneralPreferences.h"
|
||||
#import "Unicode.h"
|
||||
|
||||
|
@ -35,17 +36,17 @@
|
|||
@implementation CPUWindowController
|
||||
|
||||
|
||||
#define STOP_TOOLBAR_ITEM_IDENTIFIER @"stopTBItemIdentifier"
|
||||
#define GO_TOOLBAR_ITEM_IDENTIFIER @"goTBItemIdentifier"
|
||||
#define TRACE_TOOLBAR_ITEM_IDENTIFIER @"traceTBItemIdentifier"
|
||||
#define STEP_TOOLBAR_ITEM_IDENTIFIER @"stepTBItemIdentifier"
|
||||
#define BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER @"breakpointTBItemIdentifier"
|
||||
#define BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER @"bootstrapTBItemIdentifier"
|
||||
#define RESET_TOOLBAR_ITEM_IDENTIFIER @"resetTBItemIdentifier"
|
||||
#define MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER @"memoryInspectorTBItemIdentifier"
|
||||
#define STOP_TOOLBAR_ITEM_IDENTIFIER @"stopTBItemIdentifier"
|
||||
#define GO_TOOLBAR_ITEM_IDENTIFIER @"goTBItemIdentifier"
|
||||
#define TRACE_TOOLBAR_ITEM_IDENTIFIER @"traceTBItemIdentifier"
|
||||
#define STEP_TOOLBAR_ITEM_IDENTIFIER @"stepTBItemIdentifier"
|
||||
#define BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER @"breakpointTBItemIdentifier"
|
||||
#define BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER @"bootstrapTBItemIdentifier"
|
||||
#define RESET_TOOLBAR_ITEM_IDENTIFIER @"resetTBItemIdentifier"
|
||||
#define MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER @"memoryInspectorTBItemIdentifier"
|
||||
|
||||
#define RESIZE_WINDOW_ON_PDP8STOP_NOTIFICATION @"cpuwindowResizeOnPDP8StopNotification"
|
||||
#define RESIZE_WINDOW_ON_PDP8GO_NOTIFICATION @"cpuwindowResizeOnPDP8GoNotification"
|
||||
#define RESIZE_WINDOW_ON_PDP8STOP_NOTIFICATION @"cpuwindowResizeOnPDP8StopNotification"
|
||||
#define RESIZE_WINDOW_ON_PDP8GO_NOTIFICATION @"cpuwindowResizeOnPDP8GoNotification"
|
||||
|
||||
|
||||
#pragma mark Toolbar
|
||||
|
@ -53,119 +54,119 @@
|
|||
|
||||
- (void) setupToolbar
|
||||
{
|
||||
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:@"CPUWindowToolbar"] autorelease];
|
||||
[toolbar setAllowsUserCustomization:YES];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setDisplayMode: NSToolbarDisplayModeIconOnly];
|
||||
[toolbar setSizeMode:NSToolbarSizeModeSmall];
|
||||
[toolbar setDelegate:self];
|
||||
[window setToolbar:toolbar];
|
||||
[window setShowsToolbarButton:YES];
|
||||
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"CPUWindowToolbar"];
|
||||
[toolbar setAllowsUserCustomization:YES];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setDisplayMode: NSToolbarDisplayModeIconOnly];
|
||||
[toolbar setSizeMode:NSToolbarSizeModeSmall];
|
||||
[toolbar setDelegate:self];
|
||||
[window setToolbar:toolbar];
|
||||
[window setShowsToolbarButton:YES];
|
||||
}
|
||||
|
||||
|
||||
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdent
|
||||
willBeInsertedIntoToolbar:(BOOL) willBeInserted
|
||||
willBeInsertedIntoToolbar:(BOOL) willBeInserted
|
||||
{
|
||||
NSToolbarItem *toolbarItem = [[[NSToolbarItem alloc]
|
||||
initWithItemIdentifier:itemIdent] autorelease];
|
||||
NSToolbarItem *toolbarItem = [[NSToolbarItem alloc]
|
||||
initWithItemIdentifier:itemIdent];
|
||||
|
||||
if ([itemIdent isEqual:STOP_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Stop", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Stop", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Stops the running PDP-8/E", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"stopToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(stop:)];
|
||||
} else if ([itemIdent isEqual:GO_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Go", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Starts the simulated PDP-8/E to run continuously", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"goToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(go:)];
|
||||
} else if ([itemIdent isEqual:TRACE_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Trace", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Trace", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Starts the simulated PDP-8/E to run in trace mode", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"traceToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(trace:)];
|
||||
} else if ([itemIdent isEqual:STEP_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Step", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Step", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Executes a single PDP-8/E instruction", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"stepToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(step:)];
|
||||
} else if ([itemIdent isEqual:BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Breakpoints", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Breakpoints", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Shows or hides the Breakpoints & Break Opcodes Panel", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"breakpointsToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(showHideBreakpointPanel:)];
|
||||
} else if ([itemIdent isEqual:BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Bootstrap Loader", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Bootstrap Loader", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Shows or hides the Bootstrap Loader Panel", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"bootstrapToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(showHideBootstrapPanel:)];
|
||||
} else if ([itemIdent isEqual:RESET_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Reset", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Reset", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Resets registers and memory of the PDP-8/E", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"resetToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(reset:)];
|
||||
} else if ([itemIdent isEqual:MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Memory Inspector", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Memory Inspector", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Shows or hides the memory inspector drawer", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"memoryInspectorToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(toggleMemoryInspectorDrawer:)];
|
||||
} else
|
||||
toolbarItem = nil;
|
||||
return toolbarItem;
|
||||
if ([itemIdent isEqual:STOP_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Stop", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Stop", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Stops the running PDP-8/E", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"stopToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(stop:)];
|
||||
} else if ([itemIdent isEqual:GO_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Go", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Go", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Starts the simulated PDP-8/E to run continuously", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"goToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(go:)];
|
||||
} else if ([itemIdent isEqual:TRACE_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Trace", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Trace", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Starts the simulated PDP-8/E to run in trace mode", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"traceToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(trace:)];
|
||||
} else if ([itemIdent isEqual:STEP_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Step", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Step", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Executes a single PDP-8/E instruction", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"stepToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(step:)];
|
||||
} else if ([itemIdent isEqual:BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Breakpoints", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Breakpoints", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Shows or hides the Breakpoints & Break Opcodes Panel", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"breakpointsToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(showHideBreakpointPanel:)];
|
||||
} else if ([itemIdent isEqual:BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Bootstrap Loader", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Bootstrap Loader", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Shows or hides the Bootstrap Loader Panel", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"bootstrapToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(showHideBootstrapPanel:)];
|
||||
} else if ([itemIdent isEqual:RESET_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Reset", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Reset", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Resets registers and memory of the PDP-8/E", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"resetToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(reset:)];
|
||||
} else if ([itemIdent isEqual:MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER]) {
|
||||
[toolbarItem setLabel:NSLocalizedString(@"Memory Inspector", @"")];
|
||||
[toolbarItem setPaletteLabel:NSLocalizedString(@"Memory Inspector", @"")];
|
||||
[toolbarItem setToolTip:NSLocalizedString(
|
||||
@"Shows or hides the memory inspector drawer", @"")];
|
||||
[toolbarItem setImage:[NSImage imageNamed:@"memoryInspectorToolbarIcon"]];
|
||||
[toolbarItem setTarget:[NSApp delegate]];
|
||||
[toolbarItem setAction:@selector(toggleMemoryInspectorDrawer:)];
|
||||
} else
|
||||
toolbarItem = nil;
|
||||
return toolbarItem;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
NSToolbarFlexibleSpaceItemIdentifier,
|
||||
RESET_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarSpaceItemIdentifier,
|
||||
BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER, BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarSpaceItemIdentifier,
|
||||
STOP_TOOLBAR_ITEM_IDENTIFIER, STEP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
TRACE_TOOLBAR_ITEM_IDENTIFIER, GO_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarSpaceItemIdentifier,
|
||||
MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER,
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
NSToolbarFlexibleSpaceItemIdentifier,
|
||||
RESET_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarSpaceItemIdentifier,
|
||||
BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER, BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarSpaceItemIdentifier,
|
||||
STOP_TOOLBAR_ITEM_IDENTIFIER, STEP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
TRACE_TOOLBAR_ITEM_IDENTIFIER, GO_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarSpaceItemIdentifier,
|
||||
MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER,
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
STOP_TOOLBAR_ITEM_IDENTIFIER, STEP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
TRACE_TOOLBAR_ITEM_IDENTIFIER, GO_TOOLBAR_ITEM_IDENTIFIER,
|
||||
BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER, BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER, RESET_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarCustomizeToolbarItemIdentifier, NSToolbarSeparatorItemIdentifier,
|
||||
NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier,
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
STOP_TOOLBAR_ITEM_IDENTIFIER, STEP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
TRACE_TOOLBAR_ITEM_IDENTIFIER, GO_TOOLBAR_ITEM_IDENTIFIER,
|
||||
BREAKPOINT_TOOLBAR_ITEM_IDENTIFIER, BOOTSTRAP_TOOLBAR_ITEM_IDENTIFIER,
|
||||
MEMORYINSPECTOR_TOOLBAR_ITEM_IDENTIFIER, RESET_TOOLBAR_ITEM_IDENTIFIER,
|
||||
NSToolbarCustomizeToolbarItemIdentifier, NSToolbarSeparatorItemIdentifier,
|
||||
NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier,
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
|
@ -174,146 +175,146 @@
|
|||
|
||||
- (void) setupNotifications
|
||||
{
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyResizeWindowOnPDP8Stop:)
|
||||
name:RESIZE_WINDOW_ON_PDP8STOP_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyResizeWindowOnPDP8Go:)
|
||||
name:RESIZE_WINDOW_ON_PDP8GO_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyStopPDP8:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyTracePDP8:) name:PDP8_TRACE_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyGoPDP8:) name:PDP8_GO_NOTIFICATION object:nil];
|
||||
|
||||
[defaultCenter addObserver:self selector:@selector(notifyEnableChanged:)
|
||||
name:ENABLE_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyDelayChanged:)
|
||||
name:DELAY_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyInhibitChanged:)
|
||||
name:INHIBIT_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyEAEModeChanged:)
|
||||
name:EAE_MODE_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyEAEMount:)
|
||||
name:EAE_MOUNT_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyKM8EMount:)
|
||||
name:KM8E_MOUNT_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPreferencesChanged:)
|
||||
name:NSUserDefaultsDidChangeNotification object:nil];
|
||||
|
||||
[defaultCenter addObserver:self selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyResizeWindowOnPDP8Stop:)
|
||||
name:RESIZE_WINDOW_ON_PDP8STOP_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyResizeWindowOnPDP8Go:)
|
||||
name:RESIZE_WINDOW_ON_PDP8GO_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyStopPDP8:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyTracePDP8:) name:PDP8_TRACE_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self
|
||||
selector:@selector(notifyGoPDP8:) name:PDP8_GO_NOTIFICATION object:nil];
|
||||
|
||||
[defaultCenter addObserver:self selector:@selector(notifyEnableChanged:)
|
||||
name:ENABLE_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyDelayChanged:)
|
||||
name:DELAY_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyInhibitChanged:)
|
||||
name:INHIBIT_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyEAEModeChanged:)
|
||||
name:EAE_MODE_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyEAEMount:)
|
||||
name:EAE_MOUNT_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyKM8EMount:)
|
||||
name:KM8E_MOUNT_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPreferencesChanged:)
|
||||
name:NSUserDefaultsDidChangeNotification object:nil];
|
||||
|
||||
[defaultCenter addObserver:self selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyResizeWindowOnPDP8Stop:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"CPUWindowController got a notifyResizeWindowOnPDP8Stop notification");
|
||||
NSRect rect = [window frame];
|
||||
rect.size.height += normalContentHeight;
|
||||
rect.origin.y -= normalContentHeight;
|
||||
normalContentHeight = 0;
|
||||
[window setFrame:rect display:YES animate:YES];
|
||||
[window setTitle:NSLocalizedString(@"PDP-8/E CPU", @"")];
|
||||
[[window contentView] setAutoresizesSubviews:YES];
|
||||
[[window toolbar] validateVisibleItems];
|
||||
// NSLog (@"CPUWindowController got a notifyResizeWindowOnPDP8Stop notification");
|
||||
NSRect rect = [window frame];
|
||||
rect.size.height += normalContentHeight;
|
||||
rect.origin.y -= normalContentHeight;
|
||||
normalContentHeight = 0;
|
||||
[window setFrame:rect display:YES animate:YES];
|
||||
[window setTitle:NSLocalizedString(@"PDP-8/E CPU", @"")];
|
||||
[[window contentView] setAutoresizesSubviews:YES];
|
||||
[[window toolbar] validateVisibleItems];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyStopPDP8:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"CPUWindowController got a STOP PDP8 notification");
|
||||
// delay the resizing until all GUI elements in the CPU window and other windows are updated
|
||||
[[NSNotificationQueue defaultQueue] enqueueNotification:
|
||||
[NSNotification notificationWithName:RESIZE_WINDOW_ON_PDP8STOP_NOTIFICATION object:self]
|
||||
postingStyle:NSPostWhenIdle]; // don't use NSPostNow or NSPostASAP, that's too fast
|
||||
// NSLog (@"CPUWindowController got a STOP PDP8 notification");
|
||||
// delay the resizing until all GUI elements in the CPU window and other windows are updated
|
||||
[[NSNotificationQueue defaultQueue] enqueueNotification:
|
||||
[NSNotification notificationWithName:RESIZE_WINDOW_ON_PDP8STOP_NOTIFICATION object:self]
|
||||
postingStyle:NSPostWhenIdle]; // don't use NSPostNow or NSPostASAP, that's too fast
|
||||
}
|
||||
|
||||
|
||||
- (void) setGoWindowTitle
|
||||
{
|
||||
NSString *title;
|
||||
NSString *title;
|
||||
|
||||
switch ([[NSUserDefaults standardUserDefaults] integerForKey:GENERAL_PREFS_GO_SPEED_KEY]) {
|
||||
case GO_AS_FAST_AS_POSSIBLE :
|
||||
title = NSLocalizedString(
|
||||
@"PDP-8/E CPU " UNICODE_EM_DASH_UTF8 " running as fast as possible", @"");
|
||||
break;
|
||||
case GO_WITH_PDP8_SPEED :
|
||||
title = NSLocalizedString(
|
||||
@"PDP-8/E CPU " UNICODE_EM_DASH_UTF8 " running with real speed", @"");
|
||||
break;
|
||||
case GO_WITH_PDP8_SPEED_PRECISE :
|
||||
title = NSLocalizedString(
|
||||
@"PDP-8/E CPU " UNICODE_EM_DASH_UTF8 " running with precise timing", @"");
|
||||
break;
|
||||
default :
|
||||
title = @"";
|
||||
NSAssert (FALSE, @"Illegal go speed in the preferences");
|
||||
break;
|
||||
}
|
||||
[window setTitle:title];
|
||||
switch ([[NSUserDefaults standardUserDefaults] integerForKey:GENERAL_PREFS_GO_SPEED_KEY]) {
|
||||
case GO_AS_FAST_AS_POSSIBLE :
|
||||
title = NSLocalizedString(
|
||||
@"PDP-8/E CPU " UNICODE_EM_DASH_UTF8 " running as fast as possible", @"");
|
||||
break;
|
||||
case GO_WITH_PDP8_SPEED :
|
||||
title = NSLocalizedString(
|
||||
@"PDP-8/E CPU " UNICODE_EM_DASH_UTF8 " running with real speed", @"");
|
||||
break;
|
||||
case GO_WITH_PDP8_SPEED_PRECISE :
|
||||
title = NSLocalizedString(
|
||||
@"PDP-8/E CPU " UNICODE_EM_DASH_UTF8 " running with precise timing", @"");
|
||||
break;
|
||||
default :
|
||||
title = @"";
|
||||
NSAssert (FALSE, @"Illegal go speed in the preferences");
|
||||
break;
|
||||
}
|
||||
[window setTitle:title];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPreferencesChanged:(NSNotification *)notification
|
||||
{
|
||||
if ([pdp8 isGoing])
|
||||
[self setGoWindowTitle];
|
||||
if ([pdp8 isGoing])
|
||||
[self setGoWindowTitle];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyResizeWindowOnPDP8Go:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"CPUWindowController got a notifyResizeWindowOnPDP8Go notification");
|
||||
NSRect rect = [window frame];
|
||||
normalContentHeight = [[window contentView] frame].size.height;
|
||||
rect.origin.y += normalContentHeight;
|
||||
rect.size.height -= normalContentHeight;
|
||||
[[window contentView] setAutoresizesSubviews:NO];
|
||||
[window setFrame:rect display:YES animate:YES];
|
||||
[self setGoWindowTitle];
|
||||
[[window toolbar] validateVisibleItems];
|
||||
// NSLog (@"CPUWindowController got a notifyResizeWindowOnPDP8Go notification");
|
||||
NSRect rect = [window frame];
|
||||
normalContentHeight = [[window contentView] frame].size.height;
|
||||
rect.origin.y += normalContentHeight;
|
||||
rect.size.height -= normalContentHeight;
|
||||
[[window contentView] setAutoresizesSubviews:NO];
|
||||
[window setFrame:rect display:YES animate:YES];
|
||||
[self setGoWindowTitle];
|
||||
[[window toolbar] validateVisibleItems];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyGoPDP8:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"CPUWindowController got a GO PDP8 notification");
|
||||
// delay the resizing until all GUI elements in the CPU window and other windows are in "Go" mode
|
||||
// (the memory view needs the old size to remember the visible memory area)
|
||||
[[NSNotificationQueue defaultQueue] enqueueNotification:
|
||||
[NSNotification notificationWithName:RESIZE_WINDOW_ON_PDP8GO_NOTIFICATION object:self]
|
||||
postingStyle:NSPostASAP];
|
||||
// don't use NSPostNow, that's too fast; don't use NSPostWhenIdle, that's too slow
|
||||
// NSLog (@"CPUWindowController got a GO PDP8 notification");
|
||||
// delay the resizing until all GUI elements in the CPU window and other windows are in "Go" mode
|
||||
// (the memory view needs the old size to remember the visible memory area)
|
||||
[[NSNotificationQueue defaultQueue] enqueueNotification:
|
||||
[NSNotification notificationWithName:RESIZE_WINDOW_ON_PDP8GO_NOTIFICATION object:self]
|
||||
postingStyle:NSPostASAP];
|
||||
// don't use NSPostNow, that's too fast; don't use NSPostWhenIdle, that's too slow
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyTracePDP8:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"CPUWindowController got a TRACE PDP8 notification");
|
||||
[[window toolbar] validateVisibleItems];
|
||||
// NSLog (@"CPUWindowController got a TRACE PDP8 notification");
|
||||
[[window toolbar] validateVisibleItems];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"CPUWindowController notifyApplicationWillTerminate");
|
||||
/* When the simulator quits while the PDP-8 is running, the CPU window is shrunk, and this size
|
||||
is stored in the user defaults. On the next launch, it resizes to the default height at the top
|
||||
of the screen and not to the last position/size. To avoid that, resize it before quitting. */
|
||||
if (normalContentHeight) {
|
||||
[window orderOut:self];
|
||||
NSRect rect = [window frame];
|
||||
rect.size.height += normalContentHeight;
|
||||
rect.origin.y -= normalContentHeight;
|
||||
normalContentHeight = 0;
|
||||
[window setFrame:rect display:NO];
|
||||
[window saveFrameUsingName:[window frameAutosaveName]];
|
||||
}
|
||||
// NSLog (@"CPUWindowController notifyApplicationWillTerminate");
|
||||
/* When the simulator quits while the PDP-8 is running, the CPU window is shrunk, and this size
|
||||
is stored in the user defaults. On the next launch, it resizes to the default height at the top
|
||||
of the screen and not to the last position/size. To avoid that, resize it before quitting. */
|
||||
if (normalContentHeight) {
|
||||
[window orderOut:self];
|
||||
NSRect rect = [window frame];
|
||||
rect.size.height += normalContentHeight;
|
||||
rect.origin.y -= normalContentHeight;
|
||||
normalContentHeight = 0;
|
||||
[window setFrame:rect display:NO];
|
||||
[window saveFrameUsingName:[window frameAutosaveName]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -322,13 +323,13 @@
|
|||
|
||||
- (NSSize) windowWillResize:(NSWindow *)sender toSize:(NSSize)newSize
|
||||
{
|
||||
return normalContentHeight ? [window frame].size : newSize;
|
||||
return normalContentHeight ? [window frame].size : newSize;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame
|
||||
{
|
||||
return normalContentHeight ? NO : YES;
|
||||
return normalContentHeight ? NO : YES;
|
||||
}
|
||||
|
||||
|
||||
|
@ -337,74 +338,74 @@
|
|||
|
||||
- (void) notifyEAEMount:(NSNotification *)notification
|
||||
{
|
||||
BOOL hasEAE = [pdp8 hasEAE];
|
||||
[sc setEnabled:hasEAE];
|
||||
[gtf setEnabled:hasEAE];
|
||||
[mode setEnabled:hasEAE];
|
||||
[a setEnabled:hasEAE];
|
||||
[b setEnabled:hasEAE];
|
||||
BOOL hasEAE = [pdp8 hasEAE];
|
||||
[sc setEnabled:hasEAE];
|
||||
[gtf setEnabled:hasEAE];
|
||||
[mode setEnabled:hasEAE];
|
||||
[a setEnabled:hasEAE];
|
||||
[b setEnabled:hasEAE];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) eaeModeButtonClick:(id)sender
|
||||
{
|
||||
[pdp8 setEAEmode:EAE_MODE_A + [sender tag]];
|
||||
[pdp8 setEAEmode:EAE_MODE_A + [sender tag]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyEAEModeChanged:(NSNotification *)notification
|
||||
{
|
||||
[a setIntValue:EAE_MODE_B - [pdp8 getEAEmode]];
|
||||
[b setIntValue:[pdp8 getEAEmode] - EAE_MODE_A];
|
||||
[a setIntValue:EAE_MODE_B - [pdp8 getEAEmode]];
|
||||
[b setIntValue:[pdp8 getEAEmode] - EAE_MODE_A];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyKM8EMount:(NSNotification *)notification
|
||||
{
|
||||
BOOL hasKM8E = [pdp8 hasKM8E];
|
||||
[df setEnabled:hasKM8E];
|
||||
[_if setEnabled:hasKM8E];
|
||||
[ib setEnabled:hasKM8E];
|
||||
[uf setEnabled:hasKM8E];
|
||||
[ub setEnabled:hasKM8E];
|
||||
[sf setEnabled:hasKM8E];
|
||||
[inhibit setEnabled:hasKM8E];
|
||||
BOOL hasKM8E = [pdp8 hasKM8E];
|
||||
[df setEnabled:hasKM8E];
|
||||
[_if setEnabled:hasKM8E];
|
||||
[ib setEnabled:hasKM8E];
|
||||
[uf setEnabled:hasKM8E];
|
||||
[ub setEnabled:hasKM8E];
|
||||
[sf setEnabled:hasKM8E];
|
||||
[inhibit setEnabled:hasKM8E];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) enableCheckboxClicked:(id)sender
|
||||
{
|
||||
[pdp8 setEnable:[sender intValue]];
|
||||
[pdp8 setEnable:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyEnableChanged:(NSNotification *)notification
|
||||
{
|
||||
[enable setIntValue:[pdp8 getEnable]];
|
||||
[enable setIntValue:[pdp8 getEnable]];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) delayCheckboxClicked:(id)sender;
|
||||
{
|
||||
[pdp8 setDelay:[sender intValue]];
|
||||
[pdp8 setDelay:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyDelayChanged:(NSNotification *)notification
|
||||
{
|
||||
[delay setIntValue:[pdp8 getDelay]];
|
||||
[delay setIntValue:[pdp8 getDelay]];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) inhibitCheckboxClicked:(id)sender;
|
||||
{
|
||||
[pdp8 setInhibit:[sender intValue]];
|
||||
[pdp8 setInhibit:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyInhibitChanged:(NSNotification *)notification
|
||||
{
|
||||
[inhibit setIntValue:[pdp8 getInhibit]];
|
||||
[inhibit setIntValue:[pdp8 getInhibit]];
|
||||
}
|
||||
|
||||
|
||||
|
@ -413,48 +414,48 @@
|
|||
|
||||
- (void) setupRegisters
|
||||
{
|
||||
// KK8-E CPU
|
||||
[sr setupRegisterFor:pdp8 getRegisterValue:@selector(getSR) setRegisterValue:@selector(setSR:)
|
||||
changedNotificationName:SR_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[l setupRegisterFor:pdp8 getRegisterValue:@selector(getL) setRegisterValue:@selector(setL:)
|
||||
changedNotificationName:ACCUMULATOR_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[ac setupRegisterFor:pdp8 getRegisterValue:@selector(getAC) setRegisterValue:@selector(setAC:)
|
||||
changedNotificationName:ACCUMULATOR_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[pc setupRegisterFor:pdp8 getRegisterValue:@selector(getPC) setRegisterValue:@selector(setPC:)
|
||||
changedNotificationName:PROGRAM_COUNTER_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
// KE8-E EAE
|
||||
[sc setupRegisterFor:pdp8 getRegisterValue:@selector(getSC) setRegisterValue:@selector(setSC:)
|
||||
changedNotificationName:SC_CHANGED_NOTIFICATION mask:037 base:8];
|
||||
[gtf setupRegisterFor:pdp8 getRegisterValue:@selector(getGTF) setRegisterValue:@selector(setGTF:)
|
||||
changedNotificationName:GTF_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[mq setupRegisterFor:pdp8 getRegisterValue:@selector(getMQ) setRegisterValue:@selector(setMQ:)
|
||||
changedNotificationName:MQ_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
// KM8-E Memory Extension
|
||||
[df setupRegisterFor:pdp8 getRegisterValue:@selector(getDF) setRegisterValue:@selector(setDF:)
|
||||
changedNotificationName:DF_CHANGED_NOTIFICATION mask:07 base:8];
|
||||
[_if setupRegisterFor:pdp8 getRegisterValue:@selector(getIF) setRegisterValue:@selector(setIF:)
|
||||
changedNotificationName:PROGRAM_COUNTER_CHANGED_NOTIFICATION mask:07 base:8];
|
||||
[ib setupRegisterFor:pdp8 getRegisterValue:@selector(getIB) setRegisterValue:@selector(setIB:)
|
||||
changedNotificationName:PROGRAM_COUNTER_CHANGED_NOTIFICATION mask:07 base:8];
|
||||
[uf setupRegisterFor:pdp8 getRegisterValue:@selector(getUF) setRegisterValue:@selector(setUF:)
|
||||
changedNotificationName:UF_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[ub setupRegisterFor:pdp8 getRegisterValue:@selector(getUB) setRegisterValue:@selector(setUB:)
|
||||
changedNotificationName:UB_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[sf setupRegisterFor:pdp8 getRegisterValue:@selector(getSF) setRegisterValue:@selector(setSF:)
|
||||
changedNotificationName:SF_CHANGED_NOTIFICATION mask:0177 base:8];
|
||||
// KK8-E CPU
|
||||
[sr setupRegisterFor:pdp8 getRegisterValue:@selector(getSR) setRegisterValue:@selector(setSR:)
|
||||
changedNotificationName:SR_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[l setupRegisterFor:pdp8 getRegisterValue:@selector(getL) setRegisterValue:@selector(setL:)
|
||||
changedNotificationName:ACCUMULATOR_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[ac setupRegisterFor:pdp8 getRegisterValue:@selector(getAC) setRegisterValue:@selector(setAC:)
|
||||
changedNotificationName:ACCUMULATOR_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[pc setupRegisterFor:pdp8 getRegisterValue:@selector(getPC) setRegisterValue:@selector(setPC:)
|
||||
changedNotificationName:PROGRAM_COUNTER_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
// KE8-E EAE
|
||||
[sc setupRegisterFor:pdp8 getRegisterValue:@selector(getSC) setRegisterValue:@selector(setSC:)
|
||||
changedNotificationName:SC_CHANGED_NOTIFICATION mask:037 base:8];
|
||||
[gtf setupRegisterFor:pdp8 getRegisterValue:@selector(getGTF) setRegisterValue:@selector(setGTF:)
|
||||
changedNotificationName:GTF_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[mq setupRegisterFor:pdp8 getRegisterValue:@selector(getMQ) setRegisterValue:@selector(setMQ:)
|
||||
changedNotificationName:MQ_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
// KM8-E Memory Extension
|
||||
[df setupRegisterFor:pdp8 getRegisterValue:@selector(getDF) setRegisterValue:@selector(setDF:)
|
||||
changedNotificationName:DF_CHANGED_NOTIFICATION mask:07 base:8];
|
||||
[_if setupRegisterFor:pdp8 getRegisterValue:@selector(getIF) setRegisterValue:@selector(setIF:)
|
||||
changedNotificationName:PROGRAM_COUNTER_CHANGED_NOTIFICATION mask:07 base:8];
|
||||
[ib setupRegisterFor:pdp8 getRegisterValue:@selector(getIB) setRegisterValue:@selector(setIB:)
|
||||
changedNotificationName:PROGRAM_COUNTER_CHANGED_NOTIFICATION mask:07 base:8];
|
||||
[uf setupRegisterFor:pdp8 getRegisterValue:@selector(getUF) setRegisterValue:@selector(setUF:)
|
||||
changedNotificationName:UF_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[ub setupRegisterFor:pdp8 getRegisterValue:@selector(getUB) setRegisterValue:@selector(setUB:)
|
||||
changedNotificationName:UB_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
[sf setupRegisterFor:pdp8 getRegisterValue:@selector(getSF) setRegisterValue:@selector(setSF:)
|
||||
changedNotificationName:SF_CHANGED_NOTIFICATION mask:0177 base:8];
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
[self setupToolbar];
|
||||
[self setupNotifications];
|
||||
[self setupRegisters];
|
||||
/* set max width = min width of the panel: IB only allows max width one pixel more
|
||||
than min width, so the user can resize the width for one pixel - bug in IB? */
|
||||
NSSize size = [window minSize];
|
||||
size.height = [window maxSize].height;
|
||||
[window setMaxSize:size];
|
||||
[self setupToolbar];
|
||||
[self setupNotifications];
|
||||
[self setupRegisters];
|
||||
/* set max width = min width of the panel: IB only allows max width one pixel more
|
||||
than min width, so the user can resize the width for one pixel - bug in IB? */
|
||||
NSSize size = [window minSize];
|
||||
size.height = [window maxSize].height;
|
||||
[window setMaxSize:size];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* IOFlagController.m - Controller for the I/O flags table view in the CPU window
|
||||
* IOFlagController.m - Controller for the I/O flags table view in the CPU window
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -29,11 +29,11 @@
|
|||
#import "Utilities.h"
|
||||
|
||||
|
||||
#define NAME_COLUMN 0
|
||||
#define IENABLE_COLUMN 1
|
||||
#define IOFLAG_COLUMN 2
|
||||
#define NAME_COLUMN 0
|
||||
#define IENABLE_COLUMN 1
|
||||
#define IOFLAG_COLUMN 2
|
||||
|
||||
#define USER_MODE_ROW 0
|
||||
#define USER_MODE_ROW 0
|
||||
|
||||
|
||||
@implementation IOFlagController
|
||||
|
@ -41,159 +41,159 @@
|
|||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
adjustTableHeaderForElCapitan (ioFlagsView);
|
||||
deviceNames = [[NSMutableArray alloc] init];
|
||||
[self addIODevice:NSLocalizedString(@"User Mode", @"")];
|
||||
[[[[ioFlagsView tableColumns] objectAtIndex:NAME_COLUMN] dataCell]
|
||||
setFont:[NSFont userFontOfSize:11]];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyIOFlagsChanged:)
|
||||
name:IOFLAGS_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyKM8EMount:)
|
||||
name:KM8E_MOUNT_NOTIFICATION object:nil];
|
||||
/* Under certain contitions, the checkboxes in the I/O column are not activated/deactivated
|
||||
when the CPU window activates/deactivates. The notifyKeyWindowChanged notification is
|
||||
a workaround. Maybe a Cocoa bug with 10.4 and 10.5 (it does not appear when the table
|
||||
control has the 10.5 only hilight style "sourcelist"). */
|
||||
[defaultCenter addObserver:self selector:@selector(notifyMainWindowChanged:)
|
||||
name:NSWindowDidResignMainNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyMainWindowChanged:)
|
||||
name:NSWindowDidBecomeMainNotification object:nil];
|
||||
adjustTableHeaderForElCapitan (ioFlagsView);
|
||||
deviceNames = [[NSMutableArray alloc] init];
|
||||
[self addIODevice:NSLocalizedString(@"User Mode", @"")];
|
||||
[[[[ioFlagsView tableColumns] objectAtIndex:NAME_COLUMN] dataCell]
|
||||
setFont:[NSFont userFontOfSize:11]];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyIOFlagsChanged:)
|
||||
name:IOFLAGS_CHANGED_NOTIFICATION object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyKM8EMount:)
|
||||
name:KM8E_MOUNT_NOTIFICATION object:nil];
|
||||
/* Under certain contitions, the checkboxes in the I/O column are not activated/deactivated
|
||||
when the CPU window activates/deactivates. The notifyKeyWindowChanged notification is
|
||||
a workaround. Maybe a Cocoa bug with 10.4 and 10.5 (it does not appear when the table
|
||||
control has the 10.5 only hilight style "sourcelist"). */
|
||||
[defaultCenter addObserver:self selector:@selector(notifyMainWindowChanged:)
|
||||
name:NSWindowDidResignMainNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyMainWindowChanged:)
|
||||
name:NSWindowDidBecomeMainNotification object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyMainWindowChanged:(NSNotification *)notification
|
||||
{
|
||||
if ([[notification object] isEqualTo:[ioFlagsView window]])
|
||||
[ioFlagsView reloadData];
|
||||
if ([[notification object] isEqualTo:[ioFlagsView window]])
|
||||
[ioFlagsView reloadData];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyIOFlagsChanged:(NSNotification *)notification
|
||||
{
|
||||
[ioFlagsView reloadData];
|
||||
[ioFlagsView reloadData];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyKM8EMount:(NSNotification *)notification
|
||||
{
|
||||
if ([pdp8 hasKM8E])
|
||||
[self enableIODevice:userFLAG];
|
||||
else
|
||||
[self disableIODevice:userFLAG];
|
||||
if ([pdp8 hasKM8E])
|
||||
[self enableIODevice:userFLAG];
|
||||
else
|
||||
[self disableIODevice:userFLAG];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) numberOfAvailableFlags
|
||||
{
|
||||
return (unsigned)(8 * sizeof(enabledFlags) - [deviceNames count]);
|
||||
return (unsigned)(8 * sizeof(enabledFlags) - [deviceNames count]);
|
||||
}
|
||||
|
||||
|
||||
- (unsigned long) addIODevice:(NSString *)name
|
||||
{
|
||||
unsigned long ioflag;
|
||||
|
||||
if ([deviceNames count] == 8 * sizeof(enabledFlags))
|
||||
return 0; // all flags already allocated
|
||||
[deviceNames addObject:name];
|
||||
[ioFlagsView noteNumberOfRowsChanged];
|
||||
ioflag = 1 << ([deviceNames count] - 1);
|
||||
enabledFlags |= ioflag;
|
||||
return ioflag;
|
||||
unsigned long ioflag;
|
||||
|
||||
if ([deviceNames count] == 8 * sizeof(enabledFlags))
|
||||
return 0; // all flags already allocated
|
||||
[deviceNames addObject:name];
|
||||
[ioFlagsView noteNumberOfRowsChanged];
|
||||
ioflag = 1 << ([deviceNames count] - 1);
|
||||
enabledFlags |= ioflag;
|
||||
return ioflag;
|
||||
}
|
||||
|
||||
|
||||
- (void) disableIODevice:(unsigned long)ioflag
|
||||
{
|
||||
NSAssert1 ((((1 << [deviceNames count]) - 1) & ioflag) == ioflag, @"Invalid IO flag: %o", (uint)ioflag);
|
||||
enabledFlags &= ~ioflag;
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[ioFlagsView reloadData];
|
||||
NSAssert1 ((((1 << [deviceNames count]) - 1) & ioflag) == ioflag, @"Invalid IO flag: %o", (uint)ioflag);
|
||||
enabledFlags &= ~ioflag;
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[ioFlagsView reloadData];
|
||||
}
|
||||
|
||||
|
||||
- (void) enableIODevice:(unsigned long)ioflag
|
||||
{
|
||||
NSAssert1 ((((1 << [deviceNames count]) - 1) & ioflag) == ioflag, @"Invalid IO flag: %o", (uint)ioflag);
|
||||
enabledFlags |= ioflag;
|
||||
[ioFlagsView reloadData];
|
||||
NSAssert1 ((((1 << [deviceNames count]) - 1) & ioflag) == ioflag, @"Invalid IO flag: %o", (uint)ioflag);
|
||||
enabledFlags |= ioflag;
|
||||
[ioFlagsView reloadData];
|
||||
}
|
||||
|
||||
|
||||
- (int) numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
return (int)([deviceNames count]);
|
||||
return (int)([deviceNames count]);
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) tableView:(NSTableView *)tableView shouldSelectRow:(int)row
|
||||
{
|
||||
return ((1 << row) & enabledFlags) != 0;
|
||||
return ((1 << row) & enabledFlags) != 0;
|
||||
}
|
||||
|
||||
|
||||
- (id) tableView:(NSTableView *)tableView
|
||||
objectValueForTableColumn:(NSTableColumn *)column row:(int)row
|
||||
objectValueForTableColumn:(NSTableColumn *)column row:(int)row
|
||||
{
|
||||
switch ([[column identifier] intValue]) {
|
||||
case NAME_COLUMN :
|
||||
if ((1 << row) & enabledFlags)
|
||||
return [deviceNames objectAtIndex:row];
|
||||
// disabled devices are gray
|
||||
return [[[NSAttributedString alloc] initWithString:[deviceNames objectAtIndex:row]
|
||||
attributes:[NSDictionary dictionaryWithObject:[NSColor grayColor]
|
||||
forKey:NSForegroundColorAttributeName]] autorelease];
|
||||
case IENABLE_COLUMN :
|
||||
return [NSNumber numberWithBool:[pdp8 getInterruptMaskBits:1 << row] != 0];
|
||||
case IOFLAG_COLUMN :
|
||||
return [NSNumber numberWithBool:[pdp8 getIOFlagBits:1 << row] != 0];
|
||||
}
|
||||
return nil;
|
||||
switch ([[column identifier] intValue]) {
|
||||
case NAME_COLUMN :
|
||||
if ((1 << row) & enabledFlags)
|
||||
return [deviceNames objectAtIndex:row];
|
||||
// disabled devices are gray
|
||||
return [[NSAttributedString alloc] initWithString:[deviceNames objectAtIndex:row]
|
||||
attributes:[NSDictionary dictionaryWithObject:[NSColor grayColor]
|
||||
forKey:NSForegroundColorAttributeName]];
|
||||
case IENABLE_COLUMN :
|
||||
return [NSNumber numberWithBool:[pdp8 getInterruptMaskBits:1 << row] != 0];
|
||||
case IOFLAG_COLUMN :
|
||||
return [NSNumber numberWithBool:[pdp8 getIOFlagBits:1 << row] != 0];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (void) tableView:(NSTableView *)tableView setObjectValue:(id)val
|
||||
forTableColumn:(NSTableColumn *)column row:(int)row
|
||||
forTableColumn:(NSTableColumn *)column row:(int)row
|
||||
{
|
||||
// when the currently selected row becomes deactivated, the user can still click the check boxes
|
||||
if (((1 << row) & enabledFlags) == 0)
|
||||
return;
|
||||
switch ([[column identifier] intValue]) {
|
||||
case IENABLE_COLUMN :
|
||||
if (row == USER_MODE_ROW) // can't clear or set this flag manually,
|
||||
break; // it's set iff the KM8-E is present
|
||||
if ([val intValue])
|
||||
[pdp8 setInterruptMaskBits:1 << row];
|
||||
else
|
||||
[pdp8 clearInterruptMaskBits:1 << row];
|
||||
break;
|
||||
case IOFLAG_COLUMN :
|
||||
if ([val intValue])
|
||||
[pdp8 setIOFlagBits:1 << row];
|
||||
else
|
||||
[pdp8 clearIOFlagBits:1 << row];
|
||||
break;
|
||||
}
|
||||
// when the currently selected row becomes deactivated, the user can still click the check boxes
|
||||
if (((1 << row) & enabledFlags) == 0)
|
||||
return;
|
||||
switch ([[column identifier] intValue]) {
|
||||
case IENABLE_COLUMN :
|
||||
if (row == USER_MODE_ROW) // can't clear or set this flag manually,
|
||||
break; // it's set iff the KM8-E is present
|
||||
if ([val intValue])
|
||||
[pdp8 setInterruptMaskBits:1 << row];
|
||||
else
|
||||
[pdp8 clearInterruptMaskBits:1 << row];
|
||||
break;
|
||||
case IOFLAG_COLUMN :
|
||||
if ([val intValue])
|
||||
[pdp8 setIOFlagBits:1 << row];
|
||||
else
|
||||
[pdp8 clearIOFlagBits:1 << row];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) tableView:(NSTableView *)tableView toolTipForCell:(NSCell *)cell
|
||||
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
||||
mouseLocation:(NSPoint)mouseLocation
|
||||
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
||||
mouseLocation:(NSPoint)mouseLocation
|
||||
{
|
||||
switch ([[column identifier] intValue]) {
|
||||
case NAME_COLUMN :
|
||||
break;
|
||||
case IENABLE_COLUMN :
|
||||
return NSLocalizedString(@"When the Interrupt Enable Flag is set, the "
|
||||
@"corresponding device can cause interrupts.", @"");
|
||||
case IOFLAG_COLUMN :
|
||||
return NSLocalizedString(@"A device raises its I/O Flag to signal to the CPU "
|
||||
@"that it has completed an I/O operation.", @"");
|
||||
}
|
||||
return nil;
|
||||
switch ([[column identifier] intValue]) {
|
||||
case NAME_COLUMN :
|
||||
break;
|
||||
case IENABLE_COLUMN :
|
||||
return NSLocalizedString(@"When the Interrupt Enable Flag is set, the "
|
||||
@"corresponding device can cause interrupts.", @"");
|
||||
case IOFLAG_COLUMN :
|
||||
return NSLocalizedString(@"A device raises its I/O Flag to signal to the CPU "
|
||||
@"that it has completed an I/O operation.", @"");
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* NSFileManager+Additions.h - Additional functions for file management
|
||||
* NSFileManager+Additions.h - Additional functions for file management
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,14 +32,14 @@
|
|||
|
||||
|
||||
/*
|
||||
NSFileManager: Resolve an alias
|
||||
Original Source: <http://cocoa.karelia.com/Foundation_Categories/NSFileManager__Reso.m>
|
||||
(See copyright notice at <http://cocoa.karelia.com>)
|
||||
|
||||
The old Alias Manager functions are depecated since Mac OS 10.8 and no longer work with OS X 10.10.
|
||||
The CFURL Bookmark functions are available since Mac OS 10.6. Because we build against the
|
||||
Mac OS X 10.4 SDK, we call them dynamically. For the new code, see
|
||||
http://stackoverflow.com/questions/21244781
|
||||
NSFileManager: Resolve an alias
|
||||
Original Source: <http://cocoa.karelia.com/Foundation_Categories/NSFileManager__Reso.m>
|
||||
(See copyright notice at <http://cocoa.karelia.com>)
|
||||
|
||||
The old Alias Manager functions are depecated since Mac OS 10.8 and no longer work with OS X 10.10.
|
||||
The CFURL Bookmark functions are available since Mac OS 10.6. Because we build against the
|
||||
Mac OS X 10.4 SDK, we call them dynamically. For the new code, see
|
||||
http://stackoverflow.com/questions/21244781
|
||||
*/
|
||||
|
||||
|
||||
|
@ -75,20 +75,21 @@
|
|||
}
|
||||
CFRelease (url);
|
||||
}
|
||||
return [((NSString *) resolvedPath) autorelease];
|
||||
NSString *rValue = (NSString *)CFBridgingRelease(resolvedPath);
|
||||
return rValue;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isAliasPath:(NSString *)path
|
||||
{
|
||||
return [self pathResolved:path] != nil;
|
||||
return [self pathResolved:path] != nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) resolveAliasPath:(NSString *)path
|
||||
{
|
||||
NSString *resolved = [self pathResolved:path];
|
||||
return resolved ? resolved : path;
|
||||
NSString *resolved = [self pathResolved:path];
|
||||
return resolved ? resolved : path;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,24 +40,32 @@
|
|||
NSRange range = NSMakeRange(0, n);
|
||||
while (range.length > 0) {
|
||||
NSUInteger m = range.location + range.length / 2;
|
||||
switch ((NSComparisonResult)
|
||||
[[self objectAtIndex:m] performSelector:compare withObject:object]) {
|
||||
case NSOrderedAscending:
|
||||
n = range.location + range.length;
|
||||
range.location = m + 1;
|
||||
range.length = n - range.location;
|
||||
break;
|
||||
case NSOrderedDescending:
|
||||
range.length = m - range.location;
|
||||
break;
|
||||
case NSOrderedSame:
|
||||
if (replace)
|
||||
[self replaceObjectAtIndex:m withObject:object];
|
||||
return (unsigned)m;
|
||||
default:
|
||||
NSAssert (FALSE, @"Invalid comparison result");
|
||||
break;
|
||||
}
|
||||
id obj = [self objectAtIndex:m];
|
||||
if ([obj respondsToSelector:compare]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
NSComparisonResult result = (NSComparisonResult) [obj performSelector:compare withObject:object];
|
||||
#pragma clang diagnostic pop
|
||||
switch (result) {
|
||||
case NSOrderedAscending:
|
||||
n = range.location + range.length;
|
||||
range.location = m + 1;
|
||||
range.length = n - range.location;
|
||||
break;
|
||||
case NSOrderedDescending:
|
||||
range.length = m - range.location;
|
||||
break;
|
||||
case NSOrderedSame:
|
||||
if (replace)
|
||||
[self replaceObjectAtIndex:m withObject:object];
|
||||
return (unsigned)m;
|
||||
default:
|
||||
NSAssert (FALSE, @"Invalid comparison result");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:compare(1)");
|
||||
}
|
||||
}
|
||||
[self insertObject:object atIndex:range.location];
|
||||
return (unsigned)(range.location);
|
||||
|
@ -72,22 +80,30 @@
|
|||
NSRange range = NSMakeRange(0, n);
|
||||
while (range.length > 0) {
|
||||
NSUInteger m = range.location + range.length / 2;
|
||||
switch ((NSComparisonResult)
|
||||
[[self objectAtIndex:m] performSelector:compare withObject:object]) {
|
||||
case NSOrderedAscending:
|
||||
n = range.location + range.length;
|
||||
range.location = m + 1;
|
||||
range.length = n - range.location;
|
||||
break;
|
||||
case NSOrderedDescending:
|
||||
range.length = m - range.location;
|
||||
break;
|
||||
case NSOrderedSame:
|
||||
return (unsigned)m;
|
||||
default:
|
||||
NSAssert (FALSE, @"Invalid comparison result");
|
||||
break;
|
||||
}
|
||||
id obj = [self objectAtIndex:m];
|
||||
if ([obj respondsToSelector:compare]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
NSComparisonResult result = (NSComparisonResult) [obj performSelector:compare withObject:object];
|
||||
#pragma clang diagnostic pop
|
||||
switch (result) {
|
||||
case NSOrderedAscending:
|
||||
n = range.location + range.length;
|
||||
range.location = m + 1;
|
||||
range.length = n - range.location;
|
||||
break;
|
||||
case NSOrderedDescending:
|
||||
range.length = m - range.location;
|
||||
break;
|
||||
case NSOrderedSame:
|
||||
return (unsigned)m;
|
||||
default:
|
||||
NSAssert (FALSE, @"Invalid comparison result");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:compare(2)");
|
||||
}
|
||||
}
|
||||
return NSNotFound;
|
||||
}
|
||||
|
|
1473
Emulation/PDP8.m
1473
Emulation/PDP8.m
File diff suppressed because it is too large
Load Diff
|
@ -145,7 +145,7 @@ VOID i6007 (VOID) /* CAF 6007 */
|
|||
int i;
|
||||
for (i = 0; i < PDP8_IOADDRS; i++) {
|
||||
if (pdp8->_state.pluginPointer[i])
|
||||
[(PDP8Plugin *) pdp8->_state.pluginPointer[i] CAF:i];
|
||||
[(__bridge PDP8Plugin *) pdp8->_state.pluginPointer[i] CAF:i];
|
||||
}
|
||||
|
||||
#ifdef FPP
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* ConsoleSwitchCell.h - NSButtonCell subclass for the console switches
|
||||
* ConsoleSwitchCell.h - NSButtonCell subclass for the console switches
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,60 +32,70 @@
|
|||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
if ([self tag] == -1) {
|
||||
upWithoutShadow = [[NSImage alloc] initByReferencingFile:
|
||||
[[NSBundle bundleForClass:[self class]]
|
||||
pathForResource:[self alternateTitle] ofType:@"png"]];
|
||||
upWithShadow = [[self image] retain];
|
||||
} else {
|
||||
upWithoutShadow = [[self alternateImage] retain];
|
||||
upWithShadow = [[NSImage alloc] initByReferencingFile:
|
||||
[[NSBundle bundleForClass:[self class]]
|
||||
pathForResource:[self alternateTitle] ofType:@"png"]];
|
||||
}
|
||||
[(NSButton *)[self controlView] setAlternateTitle:@""];
|
||||
if ([self tag] == -1) {
|
||||
upWithoutShadow = [[NSImage alloc] initByReferencingFile:
|
||||
[[NSBundle bundleForClass:[self class]]
|
||||
pathForResource:[self alternateTitle] ofType:@"png"]];
|
||||
upWithShadow = [self image];
|
||||
} else {
|
||||
upWithoutShadow = [self alternateImage];
|
||||
upWithShadow = [[NSImage alloc] initByReferencingFile:
|
||||
[[NSBundle bundleForClass:[self class]]
|
||||
pathForResource:[self alternateTitle] ofType:@"png"]];
|
||||
}
|
||||
[(NSButton *)[self controlView] setAlternateTitle:@""];
|
||||
}
|
||||
|
||||
|
||||
- (void) highlight:(BOOL)flag withFrame:(NSRect)frame inView:(NSView *)view
|
||||
{
|
||||
// we need highlight only for momentary changing switches, detected via tag value -1
|
||||
if ([self tag] == -1) {
|
||||
[super highlight:flag withFrame:frame inView:view];
|
||||
[leftNeighbour updateShadow:! flag];
|
||||
}
|
||||
else
|
||||
[view setNeedsDisplay:YES];
|
||||
// we need highlight only for momentary changing switches, detected via tag value -1
|
||||
if ([self tag] == -1) {
|
||||
[super highlight:flag withFrame:frame inView:view];
|
||||
[leftNeighbour updateShadow:! flag];
|
||||
}
|
||||
else
|
||||
[view setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
|
||||
- (void) performClick:(id)sender
|
||||
{
|
||||
// called by the key equivalents; the default method causes the switch to highlight
|
||||
// we need highlight only for momentary changing switches, detected via tag value -1
|
||||
if ([self tag] == -1)
|
||||
[super performClick:sender];
|
||||
else {
|
||||
[self setState:! [self state]];
|
||||
[[self target] performSelector:[self action] withObject:sender];
|
||||
}
|
||||
[[self controlView] setNeedsDisplay:YES]; // to show keyboad operation via space key with Tiger
|
||||
// called by the key equivalents; the default method causes the switch to highlight
|
||||
// we need highlight only for momentary changing switches, detected via tag value -1
|
||||
if ([self tag] == -1)
|
||||
[super performClick:sender];
|
||||
else {
|
||||
[self setState:! [self state]];
|
||||
id targ = [self target];
|
||||
SEL act = [self action];
|
||||
if ([targ respondsToSelector:act])
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[targ performSelector:act withObject:sender];
|
||||
#pragma clang diagnostic pop
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:%s", sel_getName(act));
|
||||
}
|
||||
}
|
||||
[[self controlView] setNeedsDisplay:YES]; // to show keyboad operation via space key with Tiger
|
||||
}
|
||||
|
||||
|
||||
- (void) setState:(NSInteger)state
|
||||
{
|
||||
[super setState:state];
|
||||
[leftNeighbour updateShadow:state];
|
||||
[super setState:state];
|
||||
[leftNeighbour updateShadow:state];
|
||||
}
|
||||
|
||||
|
||||
- (void) updateShadow:(BOOL)showShadow
|
||||
{
|
||||
if ([self tag] == -1)
|
||||
[self setImage:showShadow ? upWithShadow : upWithoutShadow];
|
||||
else
|
||||
[self setAlternateImage:showShadow ? upWithShadow : upWithoutShadow];
|
||||
if ([self tag] == -1)
|
||||
[self setImage:showShadow ? upWithShadow : upWithoutShadow];
|
||||
else
|
||||
[self setAlternateImage:showShadow ? upWithShadow : upWithoutShadow];
|
||||
}
|
||||
|
||||
|
||||
|
|
692
KC8EA/KC8EA.m
692
KC8EA/KC8EA.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* KC8EA.m - KC8-EA Programmer’s Console for the PDP-8/E Simulator
|
||||
* KC8EA.m - KC8-EA Programmer’s Console for the PDP-8/E Simulator
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -35,38 +35,38 @@
|
|||
|
||||
|
||||
// notifications
|
||||
#define KC8EA_UPDATE_DISPLAY_NOTIFICATION @"kc8eaUpdateDisplayNotification"
|
||||
#define KC8EA_SW_CHANGED_NOTIFICATION @"kc8eaSWChangedNotification"
|
||||
/* Notification posted when the SW switch changes; notification object is a NSNumber
|
||||
with the new state of SW (0 or 1) */
|
||||
#define KC8EA_UPDATE_DISPLAY_NOTIFICATION @"kc8eaUpdateDisplayNotification"
|
||||
#define KC8EA_SW_CHANGED_NOTIFICATION @"kc8eaSWChangedNotification"
|
||||
/* Notification posted when the SW switch changes; notification object is a NSNumber
|
||||
with the new state of SW (0 or 1) */
|
||||
|
||||
// coder keys
|
||||
#define CODER_KEY_POWER_KEY @"power"
|
||||
#define CODER_KEY_DISPLAY_SELECTOR_KNOB @"knob"
|
||||
#define CODER_KEY_SW @"sw"
|
||||
#define CODER_KEY_HALT @"halt"
|
||||
#define CODER_KEY_SINGSTEP @"singstep"
|
||||
#define CODER_KEY_POWER_KEY @"power"
|
||||
#define CODER_KEY_DISPLAY_SELECTOR_KNOB @"knob"
|
||||
#define CODER_KEY_SW @"sw"
|
||||
#define CODER_KEY_HALT @"halt"
|
||||
#define CODER_KEY_SINGSTEP @"singstep"
|
||||
|
||||
// tag values of the display selection knob
|
||||
#define DISPLAY_STATE 0
|
||||
#define DISPLAY_STATUS 1
|
||||
#define DISPLAY_AC 2
|
||||
#define DISPLAY_MD 3
|
||||
#define DISPLAY_MQ 4
|
||||
#define DISPLAY_BUS 5
|
||||
#define DISPLAY_STATE 0
|
||||
#define DISPLAY_STATUS 1
|
||||
#define DISPLAY_AC 2
|
||||
#define DISPLAY_MD 3
|
||||
#define DISPLAY_MQ 4
|
||||
#define DISPLAY_BUS 5
|
||||
|
||||
// tag values of the power key
|
||||
#define KEY_OFF 0
|
||||
#define KEY_POWER 1
|
||||
#define KEY_PANEL_LOCK 2
|
||||
#define KEY_OFF 0
|
||||
#define KEY_POWER 1
|
||||
#define KEY_PANEL_LOCK 2
|
||||
|
||||
// states of the console switches
|
||||
#define UP 1
|
||||
#define DOWN 0
|
||||
#define UP 1
|
||||
#define DOWN 0
|
||||
|
||||
// states of the lights
|
||||
#define OFF 0
|
||||
#define ON 1
|
||||
#define OFF 0
|
||||
#define ON 1
|
||||
|
||||
|
||||
@implementation KC8EA
|
||||
|
@ -80,236 +80,235 @@ API_VERSION
|
|||
|
||||
- (void) updateDisplay
|
||||
{
|
||||
unsigned short val = 0;
|
||||
if ([key tag] == KEY_POWER) {
|
||||
switch ([knob tag]) {
|
||||
case DISPLAY_STATE :
|
||||
val = [stateMachine state:! [sw state]];
|
||||
break;
|
||||
case DISPLAY_STATUS :
|
||||
val = [stateMachine status];
|
||||
break;
|
||||
case DISPLAY_AC :
|
||||
val = [pdp8 getAC];
|
||||
break;
|
||||
case DISPLAY_MD :
|
||||
val = [stateMachine md];
|
||||
break;
|
||||
case DISPLAY_MQ :
|
||||
val = [pdp8 getMQ];
|
||||
break;
|
||||
case DISPLAY_BUS :
|
||||
val = [stateMachine bus];
|
||||
break;
|
||||
default :
|
||||
NSAssert (FALSE, @"Invalid display selection knob tag");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (displayValue != val) { // optimization
|
||||
[display0 setState:val & 00001];
|
||||
[display1 setState:val & 00002];
|
||||
[display2 setState:val & 00004];
|
||||
[display3 setState:val & 00010];
|
||||
[display4 setState:val & 00020];
|
||||
[display5 setState:val & 00040];
|
||||
[display6 setState:val & 00100];
|
||||
[display7 setState:val & 00200];
|
||||
[display8 setState:val & 00400];
|
||||
[display9 setState:val & 01000];
|
||||
[display10 setState:val & 02000];
|
||||
[display11 setState:val & 04000];
|
||||
displayValue = val;
|
||||
}
|
||||
unsigned short val = 0;
|
||||
if ([key tag] == KEY_POWER) {
|
||||
switch ([knob tag]) {
|
||||
case DISPLAY_STATE :
|
||||
val = [stateMachine state:! [sw state]];
|
||||
break;
|
||||
case DISPLAY_STATUS :
|
||||
val = [stateMachine status];
|
||||
break;
|
||||
case DISPLAY_AC :
|
||||
val = [pdp8 getAC];
|
||||
break;
|
||||
case DISPLAY_MD :
|
||||
val = [stateMachine md];
|
||||
break;
|
||||
case DISPLAY_MQ :
|
||||
val = [pdp8 getMQ];
|
||||
break;
|
||||
case DISPLAY_BUS :
|
||||
val = [stateMachine bus];
|
||||
break;
|
||||
default :
|
||||
NSAssert (FALSE, @"Invalid display selection knob tag");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (displayValue != val) { // optimization
|
||||
[display0 setState:val & 00001];
|
||||
[display1 setState:val & 00002];
|
||||
[display2 setState:val & 00004];
|
||||
[display3 setState:val & 00010];
|
||||
[display4 setState:val & 00020];
|
||||
[display5 setState:val & 00040];
|
||||
[display6 setState:val & 00100];
|
||||
[display7 setState:val & 00200];
|
||||
[display8 setState:val & 00400];
|
||||
[display9 setState:val & 01000];
|
||||
[display10 setState:val & 02000];
|
||||
[display11 setState:val & 04000];
|
||||
displayValue = val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) updateAddress
|
||||
{
|
||||
unsigned short addr = 0;
|
||||
if ([key tag] == KEY_POWER)
|
||||
addr = [stateMachine cpma];
|
||||
if (addressValue != addr) { // optimization
|
||||
[addr0 setState:addr & 000001];
|
||||
[addr1 setState:addr & 000002];
|
||||
[addr2 setState:addr & 000004];
|
||||
[addr3 setState:addr & 000010];
|
||||
[addr4 setState:addr & 000020];
|
||||
[addr5 setState:addr & 000040];
|
||||
[addr6 setState:addr & 000100];
|
||||
[addr7 setState:addr & 000200];
|
||||
[addr8 setState:addr & 000400];
|
||||
[addr9 setState:addr & 001000];
|
||||
[addr10 setState:addr & 002000];
|
||||
[addr11 setState:addr & 004000];
|
||||
[addr12 setState:addr & 010000];
|
||||
[addr13 setState:addr & 020000];
|
||||
[addr14 setState:addr & 040000];
|
||||
addressValue = addr;
|
||||
}
|
||||
unsigned short addr = 0;
|
||||
if ([key tag] == KEY_POWER)
|
||||
addr = [stateMachine cpma];
|
||||
if (addressValue != addr) { // optimization
|
||||
[addr0 setState:addr & 000001];
|
||||
[addr1 setState:addr & 000002];
|
||||
[addr2 setState:addr & 000004];
|
||||
[addr3 setState:addr & 000010];
|
||||
[addr4 setState:addr & 000020];
|
||||
[addr5 setState:addr & 000040];
|
||||
[addr6 setState:addr & 000100];
|
||||
[addr7 setState:addr & 000200];
|
||||
[addr8 setState:addr & 000400];
|
||||
[addr9 setState:addr & 001000];
|
||||
[addr10 setState:addr & 002000];
|
||||
[addr11 setState:addr & 004000];
|
||||
[addr12 setState:addr & 010000];
|
||||
[addr13 setState:addr & 020000];
|
||||
[addr14 setState:addr & 040000];
|
||||
addressValue = addr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) update
|
||||
{
|
||||
[self updateDisplay];
|
||||
[self updateAddress];
|
||||
[self updateDisplay];
|
||||
[self updateAddress];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) srClicked:(id)sender
|
||||
{
|
||||
[pdp8 setSR:[pdp8 getSR] ^ (04000 >> [sender tag])];
|
||||
[pdp8 setSR:[pdp8 getSR] ^ (04000 >> [sender tag])];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) swClicked:(id)sender
|
||||
{
|
||||
[self updateDisplay];
|
||||
/* The SW switch is not used by the simulator, but plugins that want to know about the
|
||||
corresponding OMNIBUS signal can listen for this notification */
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KC8EA_SW_CHANGED_NOTIFICATION
|
||||
object:[NSNumber numberWithInt:[sender state] == UP]];
|
||||
[self updateDisplay];
|
||||
/* The SW switch is not used by the simulator, but plugins that want to know about the
|
||||
corresponding OMNIBUS signal can listen for this notification */
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:KC8EA_SW_CHANGED_NOTIFICATION
|
||||
object:[NSNumber numberWithInt:[sender state] == UP]];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) addrloadClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[stateMachine loadAddress];
|
||||
[self update];
|
||||
}
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[stateMachine loadAddress];
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) extdaddrloadClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[stateMachine loadExtendedAddress];
|
||||
[self update];
|
||||
}
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[stateMachine loadExtendedAddress];
|
||||
[self update];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) clearClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK)
|
||||
[pdp8 clearAllFlags];
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK)
|
||||
[pdp8 clearAllFlags];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) contClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK && [pdp8 isStopped]) {
|
||||
[run setState:ON];
|
||||
[window display];
|
||||
if ([singstep state] == DOWN) {
|
||||
[stateMachine executeSingleCycle];
|
||||
[self update];
|
||||
[run setState:OFF];
|
||||
} else if ([halt state] == DOWN) {
|
||||
do {
|
||||
[stateMachine executeSingleCycle];
|
||||
[self update];
|
||||
[window display];
|
||||
} while (! [stateMachine isInFetchCycle]);
|
||||
[run setState:OFF];
|
||||
} else {
|
||||
while (! [stateMachine isInFetchCycle])
|
||||
[stateMachine executeSingleCycle];
|
||||
[[NSApp delegate] performSelector:@selector(go:) withObject:self];
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK && [pdp8 isStopped]) {
|
||||
[run setState:ON];
|
||||
[window display];
|
||||
if ([singstep state] == DOWN) {
|
||||
[stateMachine executeSingleCycle];
|
||||
[self update];
|
||||
[run setState:OFF];
|
||||
} else if ([halt state] == DOWN) {
|
||||
do {
|
||||
[stateMachine executeSingleCycle];
|
||||
[self update];
|
||||
[window display];
|
||||
} while (! [stateMachine isInFetchCycle]);
|
||||
[run setState:OFF];
|
||||
} else {
|
||||
while (! [stateMachine isInFetchCycle])
|
||||
[stateMachine executeSingleCycle];
|
||||
[[NSApp delegate] performSelector:@selector(go:) withObject:self];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) examClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK && [pdp8 isStopped]) {
|
||||
[run setState:ON];
|
||||
[window display];
|
||||
[stateMachine examine];
|
||||
[self update];
|
||||
[run setState:OFF];
|
||||
}
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK && [pdp8 isStopped]) {
|
||||
[run setState:ON];
|
||||
[window display];
|
||||
[stateMachine examine];
|
||||
[self update];
|
||||
[run setState:OFF];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) haltClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[pdp8 setHalt:[sender state] == DOWN || [singstep state] == DOWN];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
}
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[pdp8 setHalt:[sender state] == DOWN || [singstep state] == DOWN];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) stingstepClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[pdp8 setHalt:[sender state] == DOWN || [halt state] == DOWN];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
}
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK) {
|
||||
[pdp8 setHalt:[sender state] == DOWN || [halt state] == DOWN];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) depClicked:(id)sender
|
||||
{
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK && [pdp8 isStopped]) {
|
||||
[run setState:ON];
|
||||
[window display];
|
||||
[stateMachine deposit];
|
||||
[self update];
|
||||
[run setState:OFF];
|
||||
}
|
||||
if (powerKeyPosition != KEY_PANEL_LOCK && [pdp8 isStopped]) {
|
||||
[run setState:ON];
|
||||
[window display];
|
||||
[stateMachine deposit];
|
||||
[self update];
|
||||
[run setState:OFF];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) knobClicked:(id)sender
|
||||
{
|
||||
[self updateDisplay];
|
||||
[self updateDisplay];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) keyClicked:(id)sender
|
||||
{
|
||||
NSEventType eventType = [[NSApp currentEvent] type];
|
||||
switch ([sender tag]) {
|
||||
case KEY_OFF :
|
||||
if (eventType == NSEventTypeLeftMouseUp || eventType == NSEventTypeKeyDown) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
[alert setMessageText:NSLocalizedStringFromTableInBundle(
|
||||
@"Do you really want to power off the\nPDP-8/E Simulator?", nil, bundle, @"")];
|
||||
[alert addButtonWithTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"No", nil, bundle, @"")];
|
||||
[alert addButtonWithTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"Yes", nil, bundle, @"")];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
[[sender cell] setTag:eventType == NSEventTypeKeyDown ? KEY_POWER : powerKeyPosition];
|
||||
[self update];
|
||||
} else
|
||||
[NSApp terminate:self];
|
||||
[alert release];
|
||||
}
|
||||
break;
|
||||
case KEY_POWER :
|
||||
powerKeyPosition = KEY_POWER;
|
||||
[self update];
|
||||
[pdp8 setHalt:[halt state] == DOWN || [singstep state] == DOWN];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
break;
|
||||
case KEY_PANEL_LOCK :
|
||||
powerKeyPosition = KEY_PANEL_LOCK;
|
||||
[self update];
|
||||
[pdp8 setHalt:NO];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
break;
|
||||
default :
|
||||
NSAssert (FALSE, @"Invalid power key tag");
|
||||
break;
|
||||
}
|
||||
NSEventType eventType = [[NSApp currentEvent] type];
|
||||
switch ([sender tag]) {
|
||||
case KEY_OFF :
|
||||
if (eventType == NSEventTypeLeftMouseUp || eventType == NSEventTypeKeyDown) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
[alert setMessageText:NSLocalizedStringFromTableInBundle(
|
||||
@"Do you really want to power off the\nPDP-8/E Simulator?", nil, bundle, @"")];
|
||||
[alert addButtonWithTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"No", nil, bundle, @"")];
|
||||
[alert addButtonWithTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"Yes", nil, bundle, @"")];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
[[sender cell] setTag:eventType == NSEventTypeKeyDown ? KEY_POWER : powerKeyPosition];
|
||||
[self update];
|
||||
} else
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
break;
|
||||
case KEY_POWER :
|
||||
powerKeyPosition = KEY_POWER;
|
||||
[self update];
|
||||
[pdp8 setHalt:[halt state] == DOWN || [singstep state] == DOWN];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
break;
|
||||
case KEY_PANEL_LOCK :
|
||||
powerKeyPosition = KEY_PANEL_LOCK;
|
||||
[self update];
|
||||
[pdp8 setHalt:NO];
|
||||
[NSApp setWindowsNeedUpdate:YES]; // cause Step/Trace/Go CPU window toolbar items update
|
||||
break;
|
||||
default :
|
||||
NSAssert (FALSE, @"Invalid power key tag");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -318,89 +317,89 @@ API_VERSION
|
|||
|
||||
- (void) goTimerFireMethod:(NSTimer *)timer
|
||||
{
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyGo:(NSNotification *)notification
|
||||
{
|
||||
// hardcoded refresh rate at 60 Hz
|
||||
goTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self
|
||||
selector:@selector(goTimerFireMethod:) userInfo:nil repeats:YES];
|
||||
[run setState:ON];
|
||||
// hardcoded refresh rate at 60 Hz
|
||||
goTimer = [NSTimer scheduledTimerWithTimeInterval:1/60.0 target:self
|
||||
selector:@selector(goTimerFireMethod:) userInfo:nil repeats:YES];
|
||||
[run setState:ON];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyStep:(NSNotification *)notification
|
||||
{
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyTrace:(NSNotification *)notification
|
||||
{
|
||||
[run setState:YES];
|
||||
[run setState:YES];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyStop:(NSNotification *)notification
|
||||
{
|
||||
[goTimer invalidate];
|
||||
goTimer = nil;
|
||||
[run setState:OFF];
|
||||
[stateMachine updateState:YES];
|
||||
[self update];
|
||||
[goTimer invalidate];
|
||||
goTimer = nil;
|
||||
[run setState:OFF];
|
||||
[stateMachine updateState:YES];
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPDP8Changed:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"KC8EA notifyPDP8Changed");
|
||||
[[NSNotificationQueue defaultQueue] enqueueNotification:
|
||||
[NSNotification notificationWithName:KC8EA_UPDATE_DISPLAY_NOTIFICATION object:self]
|
||||
postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil];
|
||||
// NSLog (@"KC8EA notifyPDP8Changed");
|
||||
[[NSNotificationQueue defaultQueue] enqueueNotification:
|
||||
[NSNotification notificationWithName:KC8EA_UPDATE_DISPLAY_NOTIFICATION object:self]
|
||||
postingStyle:NSPostASAP coalesceMask:NSNotificationCoalescingOnName forModes:nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyUpdateDisplay:(NSNotification *) notification
|
||||
{
|
||||
// NSLog (@"KC8EA notifyUpdateDisplay");
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
// NSLog (@"KC8EA notifyUpdateDisplay");
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifySRChanged:(NSNotification *)notification
|
||||
{
|
||||
unsigned short sreg = [pdp8 getSR];
|
||||
[sr0 setState:sreg & 04000 ? 1 : 0];
|
||||
[sr1 setState:sreg & 02000 ? 1 : 0];
|
||||
[sr2 setState:sreg & 01000 ? 1 : 0];
|
||||
[sr3 setState:sreg & 00400 ? 1 : 0];
|
||||
[sr4 setState:sreg & 00200 ? 1 : 0];
|
||||
[sr5 setState:sreg & 00100 ? 1 : 0];
|
||||
[sr6 setState:sreg & 00040 ? 1 : 0];
|
||||
[sr7 setState:sreg & 00020 ? 1 : 0];
|
||||
[sr8 setState:sreg & 00010 ? 1 : 0];
|
||||
[sr9 setState:sreg & 00004 ? 1 : 0];
|
||||
[sr10 setState:sreg & 00002 ? 1 : 0];
|
||||
[sr11 setState:sreg & 00001 ? 1 : 0];
|
||||
unsigned short sreg = [pdp8 getSR];
|
||||
[sr0 setState:sreg & 04000 ? 1 : 0];
|
||||
[sr1 setState:sreg & 02000 ? 1 : 0];
|
||||
[sr2 setState:sreg & 01000 ? 1 : 0];
|
||||
[sr3 setState:sreg & 00400 ? 1 : 0];
|
||||
[sr4 setState:sreg & 00200 ? 1 : 0];
|
||||
[sr5 setState:sreg & 00100 ? 1 : 0];
|
||||
[sr6 setState:sreg & 00040 ? 1 : 0];
|
||||
[sr7 setState:sreg & 00020 ? 1 : 0];
|
||||
[sr8 setState:sreg & 00010 ? 1 : 0];
|
||||
[sr9 setState:sreg & 00004 ? 1 : 0];
|
||||
[sr10 setState:sreg & 00002 ? 1 : 0];
|
||||
[sr11 setState:sreg & 00001 ? 1 : 0];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyClearAllFlags:(NSNotification *)notification
|
||||
{
|
||||
[clear highlight:UP];
|
||||
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self
|
||||
selector:@selector(unhighliteClearTimerFireMethod:) userInfo:nil repeats:NO];
|
||||
[clear highlight:UP];
|
||||
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self
|
||||
selector:@selector(unhighliteClearTimerFireMethod:) userInfo:nil repeats:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void) unhighliteClearTimerFireMethod:(NSTimer *)timer
|
||||
{
|
||||
[clear highlight:DOWN];
|
||||
[clear highlight:DOWN];
|
||||
}
|
||||
|
||||
|
||||
|
@ -409,146 +408,153 @@ API_VERSION
|
|||
|
||||
- (void) resetDevice
|
||||
{
|
||||
[[key cell] setTag:KEY_POWER];
|
||||
[[knob cell] setTag:DISPLAY_AC];
|
||||
[sw setState:UP];
|
||||
[halt setState:UP];
|
||||
[singstep setState:UP];
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
[[key cell] setTag:KEY_POWER];
|
||||
[[knob cell] setTag:DISPLAY_AC];
|
||||
[sw setState:UP];
|
||||
[halt setState:UP];
|
||||
[singstep setState:UP];
|
||||
[stateMachine updateState:NO];
|
||||
[self update];
|
||||
}
|
||||
|
||||
|
||||
- (id) init
|
||||
{
|
||||
self = [super init];
|
||||
powerKeyPosition = KEY_POWER;
|
||||
[[key cell] setTag:powerKeyPosition];
|
||||
[[knob cell] setTag:DISPLAY_AC];
|
||||
[sw setState:UP];
|
||||
addressValue = displayValue = -1;
|
||||
/* dummy assignments to suppress Analyzer warning "never used" for the GUI elements not
|
||||
accessed by source code; for the sake of completeness, they are connected in Interface Builder */
|
||||
addrload = nil;
|
||||
extdaddrload = nil;
|
||||
cont = nil;
|
||||
dep = nil;
|
||||
exam = nil;
|
||||
return self;
|
||||
self = [super init];
|
||||
[self reset];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) reset
|
||||
{
|
||||
powerKeyPosition = KEY_POWER;
|
||||
[[key cell] setTag:powerKeyPosition];
|
||||
[[knob cell] setTag:DISPLAY_AC];
|
||||
[sw setState:UP];
|
||||
addressValue = displayValue = -1;
|
||||
/* dummy assignments to suppress Analyzer warning "never used" for the GUI elements not
|
||||
accessed by source code; for the sake of completeness, they are connected in Interface Builder */
|
||||
addrload = nil;
|
||||
extdaddrload = nil;
|
||||
cont = nil;
|
||||
dep = nil;
|
||||
exam = nil;
|
||||
}
|
||||
|
||||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
powerKeyPosition = [coder decodeIntForKey:CODER_KEY_POWER_KEY];
|
||||
[[key cell] setTag:powerKeyPosition];
|
||||
[[knob cell] setTag:[coder decodeIntForKey:CODER_KEY_DISPLAY_SELECTOR_KNOB]];
|
||||
[sw setState:[coder decodeBoolForKey:CODER_KEY_SW]];
|
||||
[halt setState:[coder decodeBoolForKey:CODER_KEY_HALT]];
|
||||
[singstep setState:DOWN]; // to cause the HALT cell update shaddow to be called
|
||||
[singstep setState:[coder decodeBoolForKey:CODER_KEY_SINGSTEP]];
|
||||
[pdp8 setHalt:[key tag] == KEY_PANEL_LOCK ? NO : ([halt state] == DOWN || [singstep state] == DOWN)];
|
||||
addressValue = displayValue = -1;
|
||||
return self;
|
||||
self = [super init];
|
||||
[self loadCoder: coder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadCoder:(NSCoder *)coder
|
||||
{
|
||||
powerKeyPosition = [coder decodeIntForKey:CODER_KEY_POWER_KEY];
|
||||
[[key cell] setTag:powerKeyPosition];
|
||||
[[knob cell] setTag:[coder decodeIntForKey:CODER_KEY_DISPLAY_SELECTOR_KNOB]];
|
||||
[sw setState:[coder decodeBoolForKey:CODER_KEY_SW]];
|
||||
[halt setState:[coder decodeBoolForKey:CODER_KEY_HALT]];
|
||||
[singstep setState:DOWN]; // to cause the HALT cell update shaddow to be called
|
||||
[singstep setState:[coder decodeBoolForKey:CODER_KEY_SINGSTEP]];
|
||||
[pdp8 setHalt:[key tag] == KEY_PANEL_LOCK ? NO : ([halt state] == DOWN || [singstep state] == DOWN)];
|
||||
addressValue = displayValue = -1;
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeInt:powerKeyPosition forKey:CODER_KEY_POWER_KEY];
|
||||
[coder encodeInt:(int)([knob tag]) forKey:CODER_KEY_DISPLAY_SELECTOR_KNOB];
|
||||
[coder encodeBool:[sw state] forKey:CODER_KEY_SW];
|
||||
[coder encodeBool:[halt state] forKey:CODER_KEY_HALT];
|
||||
[coder encodeBool:[singstep state] forKey:CODER_KEY_SINGSTEP];
|
||||
[coder encodeInt:powerKeyPosition forKey:CODER_KEY_POWER_KEY];
|
||||
[coder encodeInt:(int)([knob tag]) forKey:CODER_KEY_DISPLAY_SELECTOR_KNOB];
|
||||
[coder encodeBool:[sw state] forKey:CODER_KEY_SW];
|
||||
[coder encodeBool:[halt state] forKey:CODER_KEY_HALT];
|
||||
[coder encodeBool:[singstep state] forKey:CODER_KEY_SINGSTEP];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"KC8EA notifyApplicationWillTerminate");
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[stateMachine encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[archiver release];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
// NSLog (@"KC8EA notifyApplicationWillTerminate");
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[stateMachine encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPluginsLoaded:(NSNotification *)notification
|
||||
{
|
||||
[self notifySRChanged:nil];
|
||||
[self swClicked:sw];
|
||||
[self notifyUpdateDisplay:nil];
|
||||
[window orderBackFromDefaults:self];
|
||||
[self notifySRChanged:nil];
|
||||
[self swClicked:sw];
|
||||
[self notifyUpdateDisplay:nil];
|
||||
[window orderBackFromDefaults:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) pluginDidLoad
|
||||
{
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self initWithCoder:unarchiver];
|
||||
stateMachine = [[StateMachine alloc] initWithCoder:unarchiver pdp8:pdp8];
|
||||
[unarchiver finishDecoding];
|
||||
[unarchiver release];
|
||||
} else {
|
||||
[self init];
|
||||
stateMachine = [[StateMachine alloc] initWithPDP8:pdp8];
|
||||
}
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyGo:) name:PDP8_GO_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStop:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStep:) name:PDP8_STEP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyTrace:) name:PDP8_TRACE_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifySRChanged:) name:SR_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:MEMORY_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:PROGRAM_COUNTER_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:ACCUMULATOR_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:SC_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:GTF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:MQ_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:EAE_MODE_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:DF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:UF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:UB_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:SF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:ENABLE_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:DELAY_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:INHIBIT_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:IOFLAGS_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyUpdateDisplay:) name:KC8EA_UPDATE_DISPLAY_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyClearAllFlags:) name:CLEAR_ALL_FLAGS_NOTIFICATION object:nil];
|
||||
[(BackgroundView *) [window contentView] setBackgroundImage:@"background" ofType:@"png"];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self loadCoder:unarchiver];
|
||||
stateMachine = [[StateMachine alloc] initWithCoder:unarchiver pdp8:pdp8];
|
||||
[unarchiver finishDecoding];
|
||||
} else {
|
||||
[self reset];
|
||||
stateMachine = [[StateMachine alloc] initWithPDP8:pdp8];
|
||||
}
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyGo:) name:PDP8_GO_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStop:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStep:) name:PDP8_STEP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyTrace:) name:PDP8_TRACE_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifySRChanged:) name:SR_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:MEMORY_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:PROGRAM_COUNTER_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:ACCUMULATOR_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:SC_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:GTF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:MQ_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:EAE_MODE_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:DF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:UF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:UB_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:SF_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:ENABLE_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:DELAY_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:INHIBIT_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8Changed:) name:IOFLAGS_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyUpdateDisplay:) name:KC8EA_UPDATE_DISPLAY_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyClearAllFlags:) name:CLEAR_ALL_FLAGS_NOTIFICATION object:nil];
|
||||
[(BackgroundView *) [window contentView] setBackgroundImage:@"background" ofType:@"png"];
|
||||
}
|
||||
|
||||
|
||||
|
|
143
KC8EA/KnobCell.m
143
KC8EA/KnobCell.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* KnobCell.m - NSButtonCell subclass for the console turning switches
|
||||
* KnobCell.m - NSButtonCell subclass for the console turning switches
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,21 +32,21 @@
|
|||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
NSInteger i;
|
||||
NSInteger i;
|
||||
|
||||
NSString *imageNamePrefix = [self alternateTitle];
|
||||
[(NSButton *)[self controlView] setAlternateTitle:@""];
|
||||
NSInteger numberOfImages = [self tag];
|
||||
if (numberOfImages < 0)
|
||||
numberOfImages = -numberOfImages;
|
||||
images = [[NSMutableArray alloc] initWithCapacity:numberOfImages];
|
||||
for (i = 0; i < numberOfImages; i++) {
|
||||
[images insertObject:[[[NSImage alloc] initByReferencingFile:
|
||||
[[NSBundle bundleForClass:[self class]]
|
||||
pathForResource:[imageNamePrefix stringByAppendingFormat:@"%d", (int)i]
|
||||
ofType:@"png"]] autorelease]
|
||||
atIndex:i];
|
||||
}
|
||||
NSString *imageNamePrefix = [self alternateTitle];
|
||||
[(NSButton *)[self controlView] setAlternateTitle:@""];
|
||||
NSInteger numberOfImages = [self tag];
|
||||
if (numberOfImages < 0)
|
||||
numberOfImages = -numberOfImages;
|
||||
images = [[NSMutableArray alloc] initWithCapacity:numberOfImages];
|
||||
for (i = 0; i < numberOfImages; i++) {
|
||||
[images insertObject:[[NSImage alloc] initByReferencingFile:
|
||||
[[NSBundle bundleForClass:[self class]]
|
||||
pathForResource:[imageNamePrefix stringByAppendingFormat:@"%d", (int)i]
|
||||
ofType:@"png"]]
|
||||
atIndex:i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -54,65 +54,86 @@
|
|||
// correctly, we would have to overwrite [NSButton setTag], but to avoid subclassing NSButton,
|
||||
// we use the cell method to set the buttons tag and image
|
||||
{
|
||||
NSButton *button = (NSButton *)[self controlView];
|
||||
[button setTag:tag];
|
||||
[button setImage:[images objectAtIndex:tag]];
|
||||
[button setAlternateImage:[images objectAtIndex:tag]];
|
||||
NSButton *button = (NSButton *)[self controlView];
|
||||
[button setTag:tag];
|
||||
[button setImage:[images objectAtIndex:tag]];
|
||||
[button setAlternateImage:[images objectAtIndex:tag]];
|
||||
}
|
||||
|
||||
|
||||
- (void) performClick:(id)sender
|
||||
{
|
||||
// called by the key equivalents
|
||||
NSInteger newsegment = ([sender tag] + 1) % [images count];
|
||||
[sender setImage:[images objectAtIndex:newsegment]];
|
||||
[sender setAlternateImage:[images objectAtIndex:newsegment]];
|
||||
[sender setTag:newsegment];
|
||||
[[self target] performSelector:[self action] withObject:sender];
|
||||
[[self controlView] setNeedsDisplay:YES]; // to show keyboad operation via space key with Tiger
|
||||
// called by the key equivalents
|
||||
NSInteger newsegment = ([sender tag] + 1) % [images count];
|
||||
[sender setImage:[images objectAtIndex:newsegment]];
|
||||
[sender setAlternateImage:[images objectAtIndex:newsegment]];
|
||||
[sender setTag:newsegment];
|
||||
id targ = [self target];
|
||||
SEL act = [self action];
|
||||
if ([targ respondsToSelector:act])
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[targ performSelector:act withObject:sender];
|
||||
#pragma clang diagnostic pop
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:%s", sel_getName(act));
|
||||
}
|
||||
[[self controlView] setNeedsDisplay:YES]; // to show keyboad operation via space key with Tiger
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (BOOL) startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
|
||||
{
|
||||
return YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void) trackAt:(NSPoint)currentPoint inView:(NSButton *)control sendAction:(BOOL)sendAction
|
||||
{
|
||||
NSInteger segments = [self tag];
|
||||
NSSize size = [control bounds].size;
|
||||
float length = size.height;
|
||||
float pos = currentPoint.y;
|
||||
if (segments < 0) {
|
||||
segments = -segments;
|
||||
length = size.width;
|
||||
pos = currentPoint.x;
|
||||
}
|
||||
int newsegment = pos / length * segments;
|
||||
if (newsegment != [control tag]) {
|
||||
[control setImage:[images objectAtIndex:newsegment]];
|
||||
[control setAlternateImage:[images objectAtIndex:newsegment]];
|
||||
[control setTag:newsegment];
|
||||
if (sendAction)
|
||||
[[self target] performSelector:[self action] withObject:control];
|
||||
}
|
||||
NSInteger segments = [self tag];
|
||||
NSSize size = [control bounds].size;
|
||||
float length = size.height;
|
||||
float pos = currentPoint.y;
|
||||
if (segments < 0) {
|
||||
segments = -segments;
|
||||
length = size.width;
|
||||
pos = currentPoint.x;
|
||||
}
|
||||
int newsegment = pos / length * segments;
|
||||
if (newsegment != [control tag]) {
|
||||
[control setImage:[images objectAtIndex:newsegment]];
|
||||
[control setAlternateImage:[images objectAtIndex:newsegment]];
|
||||
[control setTag:newsegment];
|
||||
if (sendAction) {
|
||||
id targ = [self target];
|
||||
SEL act = [self action];
|
||||
if ([targ respondsToSelector:act])
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[targ performSelector:act withObject:control];
|
||||
#pragma clang diagnostic pop
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:%s", sel_getName(act));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSButton *)control
|
||||
{
|
||||
[self trackAt:currentPoint inView:control sendAction:YES];
|
||||
return YES;
|
||||
[self trackAt:currentPoint inView:control sendAction:YES];
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void) stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSButton *)control mouseIsUp:(BOOL)up
|
||||
{
|
||||
if (up)
|
||||
[self trackAt:stopPoint inView:control sendAction:NO];
|
||||
if (up)
|
||||
[self trackAt:stopPoint inView:control sendAction:NO];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* MainController.m - Main Application Controller Class
|
||||
* MainController.m - Main Application Controller Class
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -42,273 +42,272 @@
|
|||
|
||||
- (void) notifyStopPDP8:(NSNotification *)notification
|
||||
{
|
||||
if (memoryInspectorVisibleBeforeGo) {
|
||||
[memoryInspectorDrawer open:self];
|
||||
memoryInspectorVisibleBeforeGo = NO;
|
||||
}
|
||||
if (breakpointPanelVisibleBeforeGo) {
|
||||
[breakpointPanel orderBack:self];
|
||||
breakpointPanelVisibleBeforeGo = NO;
|
||||
}
|
||||
if (bootstrapPanelVisibleBeforeGo) {
|
||||
[bootstrapPanel orderBack:self];
|
||||
bootstrapPanelVisibleBeforeGo = NO;
|
||||
}
|
||||
if (memoryInspectorVisibleBeforeGo) {
|
||||
[memoryInspectorDrawer open:self];
|
||||
memoryInspectorVisibleBeforeGo = NO;
|
||||
}
|
||||
if (breakpointPanelVisibleBeforeGo) {
|
||||
[breakpointPanel orderBack:self];
|
||||
breakpointPanelVisibleBeforeGo = NO;
|
||||
}
|
||||
if (bootstrapPanelVisibleBeforeGo) {
|
||||
[bootstrapPanel orderBack:self];
|
||||
bootstrapPanelVisibleBeforeGo = NO;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPreferencesChanged:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"MainController notifyPreferencesChanged");
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[pdp8 mountEAE:[defaults boolForKey:CPU_PREFS_EAE_KEY]];
|
||||
/* The preferences may be inconsistent here because NSUserDefaultsController sends the
|
||||
notification before the km8eClick: method of CPUPreferences is called. */
|
||||
BOOL hasKM8E = [defaults boolForKey:CPU_PREFS_KM8E_KEY];
|
||||
unsigned memsize = (int)([defaults integerForKey:CPU_PREFS_MEMORYSIZE_KEY]);
|
||||
memsize = hasKM8E ? max(memsize, 2 * PDP8_FIELDSIZE) : PDP8_FIELDSIZE;
|
||||
BOOL hasTimesharing = hasKM8E ? [defaults boolForKey:CPU_PREFS_TIMESHARING_KEY] : NO;
|
||||
[pdp8 mountKM8E:hasKM8E memorySize:memsize timesharingEnabled:hasTimesharing];
|
||||
[pdp8 setTraceSpeed:[defaults floatForKey:GENERAL_PREFS_TRACE_SPEED_KEY]];
|
||||
[pdp8 setGoSpeed:(int)([defaults integerForKey:GENERAL_PREFS_GO_SPEED_KEY])];
|
||||
// NSLog (@"MainController notifyPreferencesChanged");
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[pdp8 mountEAE:[defaults boolForKey:CPU_PREFS_EAE_KEY]];
|
||||
/* The preferences may be inconsistent here because NSUserDefaultsController sends the
|
||||
notification before the km8eClick: method of CPUPreferences is called. */
|
||||
BOOL hasKM8E = [defaults boolForKey:CPU_PREFS_KM8E_KEY];
|
||||
unsigned memsize = (int)([defaults integerForKey:CPU_PREFS_MEMORYSIZE_KEY]);
|
||||
memsize = hasKM8E ? max(memsize, 2 * PDP8_FIELDSIZE) : PDP8_FIELDSIZE;
|
||||
BOOL hasTimesharing = hasKM8E ? [defaults boolForKey:CPU_PREFS_TIMESHARING_KEY] : NO;
|
||||
[pdp8 mountKM8E:hasKM8E memorySize:memsize timesharingEnabled:hasTimesharing];
|
||||
[pdp8 setTraceSpeed:[defaults floatForKey:GENERAL_PREFS_TRACE_SPEED_KEY]];
|
||||
[pdp8 setGoSpeed:(int)([defaults integerForKey:GENERAL_PREFS_GO_SPEED_KEY])];
|
||||
}
|
||||
|
||||
|
||||
- (void) cancelEditing
|
||||
{
|
||||
/* Cancel editing (in memory table views). Otherwise the [tableview reload]
|
||||
caused by [pdp8 reset] ends editing normally, and this causes values from
|
||||
the active input field to be written back to the PDP-8 memory. Send the
|
||||
cancelOperation: only to NSTextView subclasses to avoid a beep caused by
|
||||
other responders. */
|
||||
NSResponder *firstResponder = [[NSApp keyWindow] firstResponder];
|
||||
if ([[firstResponder class] isSubclassOfClass:[NSTextView class]])
|
||||
[firstResponder doCommandBySelector:@selector(cancelOperation:)];
|
||||
/* Cancel editing (in memory table views). Otherwise the [tableview reload]
|
||||
caused by [pdp8 reset] ends editing normally, and this causes values from
|
||||
the active input field to be written back to the PDP-8 memory. Send the
|
||||
cancelOperation: only to NSTextView subclasses to avoid a beep caused by
|
||||
other responders. */
|
||||
NSResponder *firstResponder = [[NSApp keyWindow] firstResponder];
|
||||
if ([[firstResponder class] isSubclassOfClass:[NSTextView class]])
|
||||
[firstResponder doCommandBySelector:@selector(cancelOperation:)];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) reset:(id)sender
|
||||
{
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
|
||||
[alert setMessageText:NSLocalizedString(@"Do you really want to reset the PDP-8/E?", @"")];
|
||||
[alert setInformativeText:NSLocalizedString(
|
||||
@"All registers and the memory content will be set to zero. "
|
||||
@"The preferences and mounted tapes, disks etc. will be preserved. "
|
||||
@"All breakpoints and break opcodes will be disabled.", @"")];
|
||||
[[alert addButtonWithTitle:NSLocalizedString(@"Yes", @"")] setKeyEquivalent:@"\r"];
|
||||
[[alert addButtonWithTitle:NSLocalizedString(@"No", @"")] setKeyEquivalent:@"\e"];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
[self cancelEditing];
|
||||
[pdp8 reset];
|
||||
[breakpoints setAllValues:0];
|
||||
[breakopcodes setAllValues:0];
|
||||
[pluginManager resetAllDevices];
|
||||
}
|
||||
[alert release];
|
||||
[alert setMessageText:NSLocalizedString(@"Do you really want to reset the PDP-8/E?", @"")];
|
||||
[alert setInformativeText:NSLocalizedString(
|
||||
@"All registers and the memory content will be set to zero. "
|
||||
@"The preferences and mounted tapes, disks etc. will be preserved. "
|
||||
@"All breakpoints and break opcodes will be disabled.", @"")];
|
||||
[[alert addButtonWithTitle:NSLocalizedString(@"Yes", @"")] setKeyEquivalent:@"\r"];
|
||||
[[alert addButtonWithTitle:NSLocalizedString(@"No", @"")] setKeyEquivalent:@"\e"];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
[self cancelEditing];
|
||||
[pdp8 reset];
|
||||
[breakpoints setAllValues:0];
|
||||
[breakopcodes setAllValues:0];
|
||||
[pluginManager resetAllDevices];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) step:(id)sender
|
||||
{
|
||||
[self cancelEditing];
|
||||
[pdp8 step];
|
||||
[self cancelEditing];
|
||||
[pdp8 step];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) trace:(id)sender
|
||||
{
|
||||
[self cancelEditing];
|
||||
[pdp8 trace:NO_STOP_ADDRESS];
|
||||
[self cancelEditing];
|
||||
[pdp8 trace:NO_STOP_ADDRESS];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) go:(id)sender
|
||||
{
|
||||
NSInteger s = [memoryInspectorDrawer state];
|
||||
memoryInspectorVisibleBeforeGo = s == NSDrawerOpenState || s == NSDrawerOpeningState;
|
||||
breakpointPanelVisibleBeforeGo = [breakpointPanel isVisible];
|
||||
bootstrapPanelVisibleBeforeGo = [bootstrapPanel isVisible];
|
||||
[breakpointPanel orderOut:self];
|
||||
[bootstrapPanel orderOut:self];
|
||||
[memoryInspectorDrawer close:self];
|
||||
[self cancelEditing];
|
||||
[pdp8 go:NO_STOP_ADDRESS];
|
||||
NSInteger s = [memoryInspectorDrawer state];
|
||||
memoryInspectorVisibleBeforeGo = s == NSDrawerOpenState || s == NSDrawerOpeningState;
|
||||
breakpointPanelVisibleBeforeGo = [breakpointPanel isVisible];
|
||||
bootstrapPanelVisibleBeforeGo = [bootstrapPanel isVisible];
|
||||
[breakpointPanel orderOut:self];
|
||||
[bootstrapPanel orderOut:self];
|
||||
[memoryInspectorDrawer close:self];
|
||||
[self cancelEditing];
|
||||
[pdp8 go:NO_STOP_ADDRESS];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) stop:(id)sender
|
||||
{
|
||||
[pdp8 stop];
|
||||
[pdp8 stop];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) showPreferencesPanel:(id)sender
|
||||
{
|
||||
[preferencesPanel makeKeyAndOrderFront:self];
|
||||
[preferencesPanel makeKeyAndOrderFront:self];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) showHideBreakpointPanel:(id)sender
|
||||
{
|
||||
if ([breakpointPanel isVisible])
|
||||
[breakpointPanel orderOut:sender];
|
||||
else {
|
||||
[breakpointPanel setBecomesKeyOnlyIfNeeded:YES];
|
||||
[breakpointPanel orderFront:sender];
|
||||
}
|
||||
if ([breakpointPanel isVisible])
|
||||
[breakpointPanel orderOut:sender];
|
||||
else {
|
||||
[breakpointPanel setBecomesKeyOnlyIfNeeded:YES];
|
||||
[breakpointPanel orderFront:sender];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) showHideBootstrapPanel:(id)sender
|
||||
{
|
||||
if ([bootstrapPanel isVisible])
|
||||
[bootstrapPanel orderOut:sender];
|
||||
else {
|
||||
[bootstrapPanel setBecomesKeyOnlyIfNeeded:YES];
|
||||
[bootstrapPanel orderFront:sender];
|
||||
}
|
||||
if ([bootstrapPanel isVisible])
|
||||
[bootstrapPanel orderOut:sender];
|
||||
else {
|
||||
[bootstrapPanel setBecomesKeyOnlyIfNeeded:YES];
|
||||
[bootstrapPanel orderFront:sender];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) toggleMemoryInspectorDrawer:(id)sender
|
||||
{
|
||||
[memoryInspectorDrawer toggle:sender];
|
||||
[memoryInspectorDrawer toggle:sender];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) loadPaperTape:(id)sender
|
||||
{
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setTitle:NSLocalizedString(@"Load a Paper Tape", @"")];
|
||||
[panel setPrompt:NSLocalizedString(@"Load", @"")];
|
||||
[loadPaperTapeFieldView retain];
|
||||
// [loadPaperTapeFieldStepper setIntValue:[pdp8 getIF]];
|
||||
int lastField = ([pdp8 memorySize] >> 12) - 1;
|
||||
[loadPaperTapeFieldStepper setMaxValue:lastField];
|
||||
[loadPaperTapeFieldStepper setEnabled:lastField != 0];
|
||||
[[loadPaperTapeFieldStepper target] performSelector:[loadPaperTapeFieldStepper action]
|
||||
withObject:loadPaperTapeFieldStepper];
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setTitle:NSLocalizedString(@"Load a Paper Tape", @"")];
|
||||
[panel setPrompt:NSLocalizedString(@"Load", @"")];
|
||||
// [loadPaperTapeFieldStepper setIntValue:[pdp8 getIF]];
|
||||
int lastField = ([pdp8 memorySize] >> 12) - 1;
|
||||
[loadPaperTapeFieldStepper setMaxValue:lastField];
|
||||
[loadPaperTapeFieldStepper setEnabled:lastField != 0];
|
||||
SEL action = [loadPaperTapeFieldStepper action];
|
||||
if ([[loadPaperTapeFieldStepper target] respondsToSelector:action])
|
||||
[[loadPaperTapeFieldStepper target] performSelector:@selector(action)
|
||||
withObject:loadPaperTapeFieldStepper];
|
||||
[panel setDirectoryURL: [NSURL fileURLWithPath:[[NSUserDefaults standardUserDefaults] stringForKey:LAST_FILE_PANEL_DIR_KEY] isDirectory: YES]];
|
||||
[panel setAccessoryView: loadPaperTapeFieldView];
|
||||
[panel setAccessoryView: loadPaperTapeFieldView];
|
||||
[panel setAllowedFileTypes:[NSArray arrayWithObjects:
|
||||
NSFileTypeForHFSTypeCode(0x504e4348l /* 'PNCH' */),
|
||||
@"BIN", @"bin", @"BN", @"bn", @"RIM", @"rim", @"PT", @"pt", nil]];
|
||||
if ([panel runModal ] == NSModalResponseOK) {
|
||||
[self cancelEditing];
|
||||
NSString *error = [pdp8 loadPaperTape:[[panel URL] path]
|
||||
toField:[loadPaperTapeFieldStepper intValue]];
|
||||
if (error) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSAlertStyleWarning];
|
||||
[alert setMessageText:error];
|
||||
[alert setInformativeText:[[panel URL] path]];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
}
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
[self cancelEditing];
|
||||
NSString *error = [pdp8 loadPaperTape:[[panel URL] path]
|
||||
toField:[loadPaperTapeFieldStepper intValue]];
|
||||
if (error) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSAlertStyleWarning];
|
||||
[alert setMessageText:error];
|
||||
[alert setInformativeText:[[panel URL] path]];
|
||||
[alert runModal];
|
||||
}
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) clearAllFlags:(id)sender
|
||||
{
|
||||
[self cancelEditing];
|
||||
[pdp8 clearAllFlags];
|
||||
[self cancelEditing];
|
||||
[pdp8 clearAllFlags];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) loadExtendedAddress:(id)sender
|
||||
{
|
||||
[self cancelEditing];
|
||||
[pdp8 loadExtendedAddress];
|
||||
[self cancelEditing];
|
||||
[pdp8 loadExtendedAddress];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) validateMenuItem:(NSMenuItem *)menuItem
|
||||
{
|
||||
SEL action = [menuItem action];
|
||||
if (action == @selector(stop:))
|
||||
return [pdp8 isRunning];
|
||||
if (action == @selector(step:) || action == @selector(trace:) || action == @selector(go:))
|
||||
return ! [pdp8 isHalted] && [pdp8 isStopped];
|
||||
if (action == @selector(reset:) || action == @selector(loadPaperTape:) ||
|
||||
action == @selector(clearAllFlags:) || action == @selector(loadExtendedAddress:))
|
||||
return [pdp8 isStopped];
|
||||
if (action == @selector(showHideBreakpointPanel:)) {
|
||||
if ([menuItem respondsToSelector:@selector(setState:)])
|
||||
[menuItem setState:[breakpointPanel isVisible]];
|
||||
return ! [pdp8 isGoing];
|
||||
}
|
||||
if (action == @selector(showHideBootstrapPanel:)) {
|
||||
if ([menuItem respondsToSelector:@selector(setState:)])
|
||||
[menuItem setState:[bootstrapPanel isVisible]];
|
||||
return ! [pdp8 isGoing];
|
||||
}
|
||||
if (action == @selector(toggleMemoryInspectorDrawer:)) {
|
||||
if ([menuItem respondsToSelector:@selector(setState:)]) {
|
||||
NSInteger s = [memoryInspectorDrawer state];
|
||||
[menuItem setState:s == NSDrawerOpenState || s == NSDrawerOpeningState ?
|
||||
NSOnState : NSOffState];
|
||||
}
|
||||
return [[memoryInspectorDrawer parentWindow] isVisible] && ! [pdp8 isGoing];
|
||||
}
|
||||
if (action == @selector(performZoomAll:)) { // don't know how to archieve this automatically
|
||||
NSWindow *window;
|
||||
NSEnumerator *enumerator = [[NSApp windows] objectEnumerator];
|
||||
while ((window = [enumerator nextObject])) {
|
||||
if ([window level] == NSNormalWindowLevel &&
|
||||
[window isZoomable] && [window isVisible])
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
SEL action = [menuItem action];
|
||||
if (action == @selector(stop:))
|
||||
return [pdp8 isRunning];
|
||||
if (action == @selector(step:) || action == @selector(trace:) || action == @selector(go:))
|
||||
return ! [pdp8 isHalted] && [pdp8 isStopped];
|
||||
if (action == @selector(reset:) || action == @selector(loadPaperTape:) ||
|
||||
action == @selector(clearAllFlags:) || action == @selector(loadExtendedAddress:))
|
||||
return [pdp8 isStopped];
|
||||
if (action == @selector(showHideBreakpointPanel:)) {
|
||||
if ([menuItem respondsToSelector:@selector(setState:)])
|
||||
[menuItem setState:[breakpointPanel isVisible]];
|
||||
return ! [pdp8 isGoing];
|
||||
}
|
||||
if (action == @selector(showHideBootstrapPanel:)) {
|
||||
if ([menuItem respondsToSelector:@selector(setState:)])
|
||||
[menuItem setState:[bootstrapPanel isVisible]];
|
||||
return ! [pdp8 isGoing];
|
||||
}
|
||||
if (action == @selector(toggleMemoryInspectorDrawer:)) {
|
||||
if ([menuItem respondsToSelector:@selector(setState:)]) {
|
||||
NSInteger s = [memoryInspectorDrawer state];
|
||||
[menuItem setState:s == NSDrawerOpenState || s == NSDrawerOpeningState ?
|
||||
NSOnState : NSOffState];
|
||||
}
|
||||
return [[memoryInspectorDrawer parentWindow] isVisible] && ! [pdp8 isGoing];
|
||||
}
|
||||
if (action == @selector(performZoomAll:)) { // don't know how to archieve this automatically
|
||||
NSWindow *window;
|
||||
NSEnumerator *enumerator = [[NSApp windows] objectEnumerator];
|
||||
while ((window = [enumerator nextObject])) {
|
||||
if ([window level] == NSNormalWindowLevel &&
|
||||
[window isZoomable] && [window isVisible])
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) validateToolbarItem:(NSToolbarItem *)toolbarItem
|
||||
{
|
||||
return [self validateMenuItem:(NSMenuItem *)toolbarItem];
|
||||
return [self validateMenuItem:(NSMenuItem *)toolbarItem];
|
||||
}
|
||||
|
||||
|
||||
- (void) applicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
LOG_ASSERTING ();
|
||||
LOG_ASSERTING ();
|
||||
}
|
||||
|
||||
|
||||
- (void) applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStopPDP8:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPreferencesChanged:) name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
[self notifyPreferencesChanged:nil];
|
||||
[breakpoints loadFromPrefs:@"Breakpoints"];
|
||||
[breakopcodes loadFromPrefs:@"BreakOpcodes"];
|
||||
[[cpuWindow toolbar] validateVisibleItems]; // revalidate because of the HALT/SINGSTEP console key
|
||||
[cpuWindow orderFrontFromDefaults:self];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStopPDP8:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPreferencesChanged:) name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
[self notifyPreferencesChanged:nil];
|
||||
[breakpoints loadFromPrefs:@"Breakpoints"];
|
||||
[breakopcodes loadFromPrefs:@"BreakOpcodes"];
|
||||
[[cpuWindow toolbar] validateVisibleItems]; // revalidate because of the HALT/SINGSTEP console key
|
||||
[cpuWindow orderFrontFromDefaults:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) applicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) performZoomAll:(id)sender // don't know how to archieve this automatically
|
||||
- (IBAction) performZoomAll:(id)sender // don't know how to archieve this automatically
|
||||
{
|
||||
NSWindow *window;
|
||||
NSEnumerator *enumerator = [[NSApp windows] objectEnumerator];
|
||||
while ((window = [enumerator nextObject])) {
|
||||
if ([window level] == NSNormalWindowLevel && [window isZoomable] && [window isVisible])
|
||||
[window performZoom:sender];
|
||||
}
|
||||
NSWindow *window;
|
||||
NSEnumerator *enumerator = [[NSApp windows] objectEnumerator];
|
||||
while ((window = [enumerator nextObject])) {
|
||||
if ([window level] == NSNormalWindowLevel && [window isZoomable] && [window isVisible])
|
||||
[window performZoom:sender];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* MemoryInspectorController.m - Controller for the Memory Inspectors Drawer
|
||||
* MemoryInspectorController.m - Controller for the Memory Inspectors Drawer
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -35,18 +35,18 @@
|
|||
#import "PDP8.h"
|
||||
|
||||
|
||||
#define ADDR_COLUMN 0
|
||||
#define OCTAL_COLUMN 1
|
||||
#define CONTENT_COLUMN 2
|
||||
#define ADDR_COLUMN 0
|
||||
#define OCTAL_COLUMN 1
|
||||
#define CONTENT_COLUMN 2
|
||||
|
||||
#define ADDR_COLUMN_ID @"0"
|
||||
#define OCTAL_COLUMN_ID @"1"
|
||||
#define CONTENT_COLUMN_ID @"2"
|
||||
#define ADDR_COLUMN_ID @"0"
|
||||
#define OCTAL_COLUMN_ID @"1"
|
||||
#define CONTENT_COLUMN_ID @"2"
|
||||
|
||||
#define CURRENT_INSPECTOR_CLASS_PREFS_KEY @"MemInspectorClass"
|
||||
#define TOP_ROW_PREFS_KEY @"MemInspectorTopRow"
|
||||
#define ALIGNMENT_PREFS_KEY @"MemInspectorAlign"
|
||||
#define INSPECTOR_OPEN_PREFS_KEY @"MemInspectorOpen"
|
||||
#define CURRENT_INSPECTOR_CLASS_PREFS_KEY @"MemInspectorClass"
|
||||
#define TOP_ROW_PREFS_KEY @"MemInspectorTopRow"
|
||||
#define ALIGNMENT_PREFS_KEY @"MemInspectorAlign"
|
||||
#define INSPECTOR_OPEN_PREFS_KEY @"MemInspectorOpen"
|
||||
|
||||
|
||||
@implementation NSFormatter (OrderInMemoryInspectorMenu)
|
||||
|
@ -54,8 +54,8 @@
|
|||
|
||||
- (NSComparisonResult) compareOrderInMemoryInspectorMenu:(id <MemoryInspector>)inspector
|
||||
{
|
||||
return [[(id <MemoryInspector>) self orderInMemoryInspectorMenu]
|
||||
compare:[inspector orderInMemoryInspectorMenu]];
|
||||
return [[(id <MemoryInspector>) self orderInMemoryInspectorMenu]
|
||||
compare:[inspector orderInMemoryInspectorMenu]];
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,14 +71,14 @@
|
|||
This methods calculates the scroll view height from the drawer height and the initial,
|
||||
correct height delta between drawer and scroll view height. */
|
||||
{
|
||||
static float delta = (float) 0.0;
|
||||
|
||||
if (delta == 0.0) {
|
||||
if ([self window])
|
||||
delta = [[self window] frame].size.height - frameRect.size.height;
|
||||
} else
|
||||
frameRect.size.height = [[self window] frame].size.height - delta;
|
||||
[super setFrame:frameRect];
|
||||
static float delta = (float) 0.0;
|
||||
|
||||
if (delta == 0.0) {
|
||||
if ([self window])
|
||||
delta = [[self window] frame].size.height - frameRect.size.height;
|
||||
} else
|
||||
frameRect.size.height = [[self window] frame].size.height - delta;
|
||||
[super setFrame:frameRect];
|
||||
}
|
||||
|
||||
|
||||
|
@ -90,15 +90,15 @@
|
|||
|
||||
- (void) cancelEditingInInspector
|
||||
{
|
||||
NSResponder *first, *next;
|
||||
|
||||
for (first = next = [[NSApp keyWindow] firstResponder]; next; next = [next nextResponder]) {
|
||||
if (next == [memoryInspectorDrawer contentView] &&
|
||||
[[first class] isSubclassOfClass:[NSTextView class]]) {
|
||||
[first doCommandBySelector:@selector(cancelOperation:)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSResponder *first, *next;
|
||||
|
||||
for (first = next = [[NSApp keyWindow] firstResponder]; next; next = [next nextResponder]) {
|
||||
if (next == [memoryInspectorDrawer contentView] &&
|
||||
[[first class] isSubclassOfClass:[NSTextView class]]) {
|
||||
[first doCommandBySelector:@selector(cancelOperation:)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,267 +106,266 @@
|
|||
{
|
||||
NSMutableArray *inspectors = [NSMutableArray array];
|
||||
#if !__OBJC2__
|
||||
int i;
|
||||
|
||||
int numClasses = 0;
|
||||
int newNumClasses = objc_getClassList(NULL, 0);
|
||||
|
||||
Class *allClasses = NULL;
|
||||
while (numClasses < newNumClasses) {
|
||||
numClasses = newNumClasses;
|
||||
allClasses = realloc(allClasses, sizeof(Class) * numClasses);
|
||||
newNumClasses = objc_getClassList(allClasses, numClasses);
|
||||
}
|
||||
for (i = 0; i < numClasses; i++) {
|
||||
Class currentClass = allClasses[i];
|
||||
while (currentClass) {
|
||||
int i;
|
||||
|
||||
int numClasses = 0;
|
||||
int newNumClasses = objc_getClassList(NULL, 0);
|
||||
|
||||
Class *allClasses = NULL;
|
||||
while (numClasses < newNumClasses) {
|
||||
numClasses = newNumClasses;
|
||||
allClasses = realloc(allClasses, sizeof(Class) * numClasses);
|
||||
newNumClasses = objc_getClassList(allClasses, numClasses);
|
||||
}
|
||||
for (i = 0; i < numClasses; i++) {
|
||||
Class currentClass = allClasses[i];
|
||||
while (currentClass) {
|
||||
if ([currentClass superclass] == [NSFormatter class] &&
|
||||
[currentClass conformsToProtocol:@protocol(MemoryInspector)]) {
|
||||
[inspectors addObject:[[[allClasses[i] alloc] init] autorelease]];
|
||||
break;
|
||||
}
|
||||
currentClass = [currentClass superclass];
|
||||
}
|
||||
[currentClass conformsToProtocol:@protocol(MemoryInspector)]) {
|
||||
[inspectors addObject:[[[allClasses[i] alloc] init] autorelease]];
|
||||
break;
|
||||
}
|
||||
currentClass = [currentClass superclass];
|
||||
}
|
||||
}
|
||||
free (allClasses);
|
||||
}
|
||||
}
|
||||
free (allClasses);
|
||||
#else
|
||||
{
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspector6BitASCII") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspector8BitASCII") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorOS8Packed8BitASCII") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorSignedInteger") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorUnsignedInteger") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorDWSignedInteger") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorDWUnsignedInteger") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorFPP8AFPFloatingPoint") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorFPP8AEPFloatingPoint") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorFortranIIFloatingPoint") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[[NSClassFromString(@"MemoryInspectorPascalSFloatingPoint") alloc] init] autorelease]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspector6BitASCII") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspector8BitASCII") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorOS8Packed8BitASCII") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorSignedInteger") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorUnsignedInteger") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorDWSignedInteger") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorDWUnsignedInteger") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorFPP8AFPFloatingPoint") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorFPP8AEPFloatingPoint") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorFortranIIFloatingPoint") alloc] init]];
|
||||
[inspectors addObject:[[NSClassFromString(@"MemoryInspectorPascalSFloatingPoint") alloc] init]];
|
||||
}
|
||||
#endif
|
||||
[inspectors sortUsingSelector:@selector(compareOrderInMemoryInspectorMenu:)];
|
||||
return inspectors;
|
||||
[inspectors sortUsingSelector:@selector(compareOrderInMemoryInspectorMenu:)];
|
||||
return inspectors;
|
||||
}
|
||||
|
||||
|
||||
- (NSRange) visibleRange
|
||||
{
|
||||
// see also [CPUMemoryViewController updateVisibleMemoryRange] and [NSTableView(Scrolling) scrollRowToTop:]
|
||||
NSRange range;
|
||||
range.location = range.length = 0;
|
||||
NSRect rect = [memoryView visibleRect];
|
||||
if (rect.size.height > 0) { // zero immediately after "Stop" when the window is not yet enlarged
|
||||
if (runningOnElCapitanOrNewer())
|
||||
rect.origin.y += [memoryView rectOfRow:0].size.height;
|
||||
unsigned pixelPerRow = (unsigned) ([memoryView rowHeight] + [memoryView intercellSpacing].height);
|
||||
range.location = [memoryView rowsInRect:rect].location;
|
||||
range.length = rect.size.height / pixelPerRow;
|
||||
}
|
||||
return range;
|
||||
// see also [CPUMemoryViewController updateVisibleMemoryRange] and [NSTableView(Scrolling) scrollRowToTop:]
|
||||
NSRange range;
|
||||
range.location = range.length = 0;
|
||||
NSRect rect = [memoryView visibleRect];
|
||||
if (rect.size.height > 0) { // zero immediately after "Stop" when the window is not yet enlarged
|
||||
if (runningOnElCapitanOrNewer())
|
||||
rect.origin.y += [memoryView rectOfRow:0].size.height;
|
||||
unsigned pixelPerRow = (unsigned) ([memoryView rowHeight] + [memoryView intercellSpacing].height);
|
||||
range.location = [memoryView rowsInRect:rect].location;
|
||||
range.length = rect.size.height / pixelPerRow;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) selectMemoryInspector:(id)sender
|
||||
{
|
||||
NSSize drawerSize;
|
||||
NSSize drawerSize;
|
||||
|
||||
// get the new inspector
|
||||
NSFormatter <MemoryInspector> *newInspector = [memoryInspectors objectAtIndex:[sender indexOfSelectedItem]];
|
||||
if ([currentInspector isEqual:newInspector])
|
||||
return;
|
||||
|
||||
// stop editing in the old inspector
|
||||
[self cancelEditingInInspector];
|
||||
|
||||
NSTableColumn *addrColumn = [memoryView tableColumnWithIdentifier:ADDR_COLUMN_ID];
|
||||
NSTableColumn *octalColumn = [memoryView tableColumnWithIdentifier:OCTAL_COLUMN_ID];
|
||||
NSTableColumn *contentColumn = [memoryView tableColumnWithIdentifier:CONTENT_COLUMN_ID];
|
||||
|
||||
// set octal column width
|
||||
drawerSize.width = [addrColumn width];
|
||||
float width = [newInspector wordsPerRow] * 35;
|
||||
drawerSize.width += width;
|
||||
[octalColumn setMinWidth:width];
|
||||
[octalColumn setMaxWidth:width];
|
||||
[octalColumn setWidth:width];
|
||||
|
||||
// set content column width
|
||||
width = [newInspector contentWidthInCharacters] * 7 + 4;
|
||||
drawerSize.width += width;
|
||||
[contentColumn setMinWidth:width];
|
||||
[contentColumn setMaxWidth:width];
|
||||
[contentColumn setWidth:width];
|
||||
|
||||
// resize drawer
|
||||
drawerSize.width += 42;
|
||||
drawerSize.height = 0;
|
||||
[memoryInspectorDrawer setMaxContentSize:drawerSize];
|
||||
[memoryInspectorDrawer setMinContentSize:drawerSize];
|
||||
[memoryInspectorDrawer setContentSize:drawerSize];
|
||||
|
||||
// scroll to a reasonable location
|
||||
NSInteger newTopRow = 0;
|
||||
NSInteger newSelectedRow = -1;
|
||||
if (currentInspector) {
|
||||
NSRange visibleRange = [self visibleRange];
|
||||
NSInteger selectedRow = [memoryView selectedRow];
|
||||
if (NSLocationInRange(selectedRow, visibleRange)) {
|
||||
newTopRow = selectedRow * [currentInspector wordsPerRow] /
|
||||
[newInspector wordsPerRow] - (selectedRow - visibleRange.location);
|
||||
newSelectedRow = newTopRow + (selectedRow - visibleRange.location);
|
||||
} else
|
||||
newTopRow = visibleRange.location * [currentInspector wordsPerRow] /
|
||||
[newInspector wordsPerRow];
|
||||
NSInteger lastAddress = (newTopRow + visibleRange.length) * [newInspector wordsPerRow];
|
||||
if (lastAddress >= PDP8_MEMSIZE) // don't show white space at the end of the table view
|
||||
newTopRow -= (lastAddress - PDP8_MEMSIZE) / [newInspector wordsPerRow] + 1;
|
||||
}
|
||||
|
||||
// switch to the new inspector, set the formatter and reload data
|
||||
alignment = 0;
|
||||
currentInspector = newInspector;
|
||||
[[octalColumn dataCell] setObjectValue:nil]; // remove old value with wrong number of words
|
||||
[[[octalColumn dataCell] formatter] setNumberOfWords:[currentInspector wordsPerRow]];
|
||||
[[contentColumn dataCell] setObjectValue:nil]; // remove old value with wrong number of words
|
||||
[[contentColumn dataCell] setFormatter:currentInspector];
|
||||
[memoryView reloadData];
|
||||
// get the new inspector
|
||||
NSFormatter <MemoryInspector> *newInspector = [memoryInspectors objectAtIndex:[sender indexOfSelectedItem]];
|
||||
if ([currentInspector isEqual:newInspector])
|
||||
return;
|
||||
|
||||
// stop editing in the old inspector
|
||||
[self cancelEditingInInspector];
|
||||
|
||||
NSTableColumn *addrColumn = [memoryView tableColumnWithIdentifier:ADDR_COLUMN_ID];
|
||||
NSTableColumn *octalColumn = [memoryView tableColumnWithIdentifier:OCTAL_COLUMN_ID];
|
||||
NSTableColumn *contentColumn = [memoryView tableColumnWithIdentifier:CONTENT_COLUMN_ID];
|
||||
|
||||
// set octal column width
|
||||
drawerSize.width = [addrColumn width];
|
||||
float width = [newInspector wordsPerRow] * 35;
|
||||
drawerSize.width += width;
|
||||
[octalColumn setMinWidth:width];
|
||||
[octalColumn setMaxWidth:width];
|
||||
[octalColumn setWidth:width];
|
||||
|
||||
// set content column width
|
||||
width = [newInspector contentWidthInCharacters] * 7 + 4;
|
||||
drawerSize.width += width;
|
||||
[contentColumn setMinWidth:width];
|
||||
[contentColumn setMaxWidth:width];
|
||||
[contentColumn setWidth:width];
|
||||
|
||||
// resize drawer
|
||||
drawerSize.width += 42;
|
||||
drawerSize.height = 0;
|
||||
[memoryInspectorDrawer setMaxContentSize:drawerSize];
|
||||
[memoryInspectorDrawer setMinContentSize:drawerSize];
|
||||
[memoryInspectorDrawer setContentSize:drawerSize];
|
||||
|
||||
// scroll to a reasonable location
|
||||
NSInteger newTopRow = 0;
|
||||
NSInteger newSelectedRow = -1;
|
||||
if (currentInspector) {
|
||||
NSRange visibleRange = [self visibleRange];
|
||||
NSInteger selectedRow = [memoryView selectedRow];
|
||||
if (NSLocationInRange(selectedRow, visibleRange)) {
|
||||
newTopRow = selectedRow * [currentInspector wordsPerRow] /
|
||||
[newInspector wordsPerRow] - (selectedRow - visibleRange.location);
|
||||
newSelectedRow = newTopRow + (selectedRow - visibleRange.location);
|
||||
} else
|
||||
newTopRow = visibleRange.location * [currentInspector wordsPerRow] /
|
||||
[newInspector wordsPerRow];
|
||||
NSInteger lastAddress = (newTopRow + visibleRange.length) * [newInspector wordsPerRow];
|
||||
if (lastAddress >= PDP8_MEMSIZE) // don't show white space at the end of the table view
|
||||
newTopRow -= (lastAddress - PDP8_MEMSIZE) / [newInspector wordsPerRow] + 1;
|
||||
}
|
||||
|
||||
// switch to the new inspector, set the formatter and reload data
|
||||
alignment = 0;
|
||||
currentInspector = newInspector;
|
||||
[[octalColumn dataCell] setObjectValue:nil]; // remove old value with wrong number of words
|
||||
[[[octalColumn dataCell] formatter] setNumberOfWords:[currentInspector wordsPerRow]];
|
||||
[[contentColumn dataCell] setObjectValue:nil]; // remove old value with wrong number of words
|
||||
[[contentColumn dataCell] setFormatter:currentInspector];
|
||||
[memoryView reloadData];
|
||||
|
||||
// set selected row
|
||||
[memoryView scrollRowToTop:newTopRow];
|
||||
if (newSelectedRow >= 0)
|
||||
[memoryView selectRowIndexes:[NSIndexSet indexSetWithIndex:newSelectedRow]
|
||||
byExtendingSelection:NO];
|
||||
else
|
||||
[memoryView deselectAll:self];
|
||||
// set selected row
|
||||
[memoryView scrollRowToTop:newTopRow];
|
||||
if (newSelectedRow >= 0)
|
||||
[memoryView selectRowIndexes:[NSIndexSet indexSetWithIndex:newSelectedRow]
|
||||
byExtendingSelection:NO];
|
||||
else
|
||||
[memoryView deselectAll:self];
|
||||
|
||||
// enable or disable corner view for memory alignment
|
||||
if ([currentInspector needsMemoryAlignment]) {
|
||||
[cornerView setImageNamed:@"alignMemoryArrow" toolTip:
|
||||
NSLocalizedString(@"Click or option-click to align multiword formats", @"")];
|
||||
[cornerView setClickable:YES];
|
||||
} else {
|
||||
[cornerView setImageNamed:nil toolTip:nil];
|
||||
[cornerView setClickable:NO];
|
||||
}
|
||||
// enable or disable corner view for memory alignment
|
||||
if ([currentInspector needsMemoryAlignment]) {
|
||||
[cornerView setImageNamed:@"alignMemoryArrow" toolTip:
|
||||
NSLocalizedString(@"Click or option-click to align multiword formats", @"")];
|
||||
[cornerView setClickable:YES];
|
||||
} else {
|
||||
[cornerView setImageNamed:nil toolTip:nil];
|
||||
[cornerView setClickable:NO];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) alignMemory:(id)sender
|
||||
{
|
||||
if ([currentInspector needsMemoryAlignment]) {
|
||||
[self cancelEditingInInspector];
|
||||
int wordsPerRow = [currentInspector wordsPerRow];
|
||||
alignment = (alignment + wordsPerRow +
|
||||
if ([currentInspector needsMemoryAlignment]) {
|
||||
[self cancelEditingInInspector];
|
||||
int wordsPerRow = [currentInspector wordsPerRow];
|
||||
alignment = (alignment + wordsPerRow +
|
||||
(([[NSApp currentEvent] modifierFlags] & NSEventModifierFlagOption) ? -1 : 1)) % wordsPerRow;
|
||||
[memoryView reloadData];
|
||||
}
|
||||
[memoryView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyMemoryChanged:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"MemoryInspectorController notifyMemoryChanged");
|
||||
[memoryView reloadData];
|
||||
// NSLog (@"MemoryInspectorController notifyMemoryChanged");
|
||||
[memoryView reloadData];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) tableView:(NSTableView *)tableView shouldEditTableColumn:(NSTableColumn *)column row:(int)row
|
||||
{
|
||||
return [currentInspector wordsPerRow] * (row + 1) + alignment <= [pdp8 memorySize]
|
||||
&& ([[column identifier] intValue] != CONTENT_COLUMN || [currentInspector allowsEditing]);
|
||||
return [currentInspector wordsPerRow] * (row + 1) + alignment <= [pdp8 memorySize]
|
||||
&& ([[column identifier] intValue] != CONTENT_COLUMN || [currentInspector allowsEditing]);
|
||||
}
|
||||
|
||||
|
||||
- (int) numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
int wordsPerRow = [currentInspector wordsPerRow];
|
||||
return wordsPerRow ? (PDP8_MEMSIZE + wordsPerRow - alignment - 1) / wordsPerRow : 0;
|
||||
int wordsPerRow = [currentInspector wordsPerRow];
|
||||
return wordsPerRow ? (PDP8_MEMSIZE + wordsPerRow - alignment - 1) / wordsPerRow : 0;
|
||||
}
|
||||
|
||||
|
||||
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)column row:(int)row
|
||||
{
|
||||
int i;
|
||||
NSMutableArray *value;
|
||||
|
||||
int wordsPerRow = [currentInspector wordsPerRow];
|
||||
switch ([[column identifier] intValue]) {
|
||||
case ADDR_COLUMN :
|
||||
return [NSString stringWithFormat:@"%5.5o", wordsPerRow * row + alignment];
|
||||
case OCTAL_COLUMN :
|
||||
value = [NSMutableArray arrayWithCapacity:wordsPerRow];
|
||||
for (i = 0; i < wordsPerRow && wordsPerRow * row + alignment + i < PDP8_MEMSIZE; i++)
|
||||
[value addObject:[NSNumber numberWithInt:
|
||||
[pdp8 memoryAt:wordsPerRow * row + alignment + i]]];
|
||||
return value;
|
||||
case CONTENT_COLUMN :
|
||||
if (wordsPerRow * (row + 1) /* + alignment */ > [pdp8 memorySize])
|
||||
return NSLocalizedString(@"n/a", @"");
|
||||
value = [NSMutableArray arrayWithCapacity:wordsPerRow];
|
||||
for (i = 0; i < wordsPerRow; i++)
|
||||
[value addObject:[NSNumber numberWithInt:
|
||||
(wordsPerRow * row + alignment + i < PDP8_MEMSIZE) ?
|
||||
[pdp8 memoryAt:wordsPerRow * row + alignment + i] : 0]];
|
||||
return value;
|
||||
}
|
||||
return nil;
|
||||
int i;
|
||||
NSMutableArray *value;
|
||||
|
||||
int wordsPerRow = [currentInspector wordsPerRow];
|
||||
switch ([[column identifier] intValue]) {
|
||||
case ADDR_COLUMN :
|
||||
return [NSString stringWithFormat:@"%5.5o", wordsPerRow * row + alignment];
|
||||
case OCTAL_COLUMN :
|
||||
value = [NSMutableArray arrayWithCapacity:wordsPerRow];
|
||||
for (i = 0; i < wordsPerRow && wordsPerRow * row + alignment + i < PDP8_MEMSIZE; i++)
|
||||
[value addObject:[NSNumber numberWithInt:
|
||||
[pdp8 memoryAt:wordsPerRow * row + alignment + i]]];
|
||||
return value;
|
||||
case CONTENT_COLUMN :
|
||||
if (wordsPerRow * (row + 1) /* + alignment */ > [pdp8 memorySize])
|
||||
return NSLocalizedString(@"n/a", @"");
|
||||
value = [NSMutableArray arrayWithCapacity:wordsPerRow];
|
||||
for (i = 0; i < wordsPerRow; i++)
|
||||
[value addObject:[NSNumber numberWithInt:
|
||||
(wordsPerRow * row + alignment + i < PDP8_MEMSIZE) ?
|
||||
[pdp8 memoryAt:wordsPerRow * row + alignment + i] : 0]];
|
||||
return value;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) tableView:(NSTableView *)tableView toolTipForCell:(NSCell *)cell
|
||||
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
||||
mouseLocation:(NSPoint)mouseLocation
|
||||
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
||||
mouseLocation:(NSPoint)mouseLocation
|
||||
{
|
||||
switch ([[column identifier] intValue]) {
|
||||
case ADDR_COLUMN :
|
||||
return NSLocalizedString(@"This column displays the memory adresses.", @"");
|
||||
case OCTAL_COLUMN :
|
||||
return NSLocalizedString(@"This column displays the octal memory content.", @"");
|
||||
case CONTENT_COLUMN :
|
||||
return [currentInspector toolTipForContentColumn];
|
||||
}
|
||||
return nil;
|
||||
switch ([[column identifier] intValue]) {
|
||||
case ADDR_COLUMN :
|
||||
return NSLocalizedString(@"This column displays the memory adresses.", @"");
|
||||
case OCTAL_COLUMN :
|
||||
return NSLocalizedString(@"This column displays the octal memory content.", @"");
|
||||
case CONTENT_COLUMN :
|
||||
return [currentInspector toolTipForContentColumn];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (void) tableView:(NSTableView *)tableView setObjectValue:(NSArray *)values
|
||||
forTableColumn:(NSTableColumn *)column row:(int)row
|
||||
forTableColumn:(NSTableColumn *)column row:(int)row
|
||||
{
|
||||
/* value == nil when the user tabs (without editing) over cells with
|
||||
output strings that are not valid input strings, e. g. "(IEEE overflow)".
|
||||
In this case, the formatter is called with error == nil, returns the
|
||||
value nil for the invalid input string, but Cocoa does not call
|
||||
control:didFailToFormatString:errorDescription: */
|
||||
if (values)
|
||||
[pdp8 setMemoryAtAddress:row * [currentInspector wordsPerRow] + alignment
|
||||
toValues:values withMask:[[column identifier] intValue] == CONTENT_COLUMN];
|
||||
/* value == nil when the user tabs (without editing) over cells with
|
||||
output strings that are not valid input strings, e. g. "(IEEE overflow)".
|
||||
In this case, the formatter is called with error == nil, returns the
|
||||
value nil for the invalid input string, but Cocoa does not call
|
||||
control:didFailToFormatString:errorDescription: */
|
||||
if (values)
|
||||
[pdp8 setMemoryAtAddress:row * [currentInspector wordsPerRow] + alignment
|
||||
toValues:values withMask:[[column identifier] intValue] == CONTENT_COLUMN];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) control:(NSControl *)control didFailToFormatString:(NSString *)string
|
||||
errorDescription:(NSString *)error
|
||||
errorDescription:(NSString *)error
|
||||
{
|
||||
NSRange range;
|
||||
range.location = 0;
|
||||
range.length = -1;
|
||||
[[control currentEditor] setSelectedRange:range];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:error];
|
||||
[alert beginSheetModalForWindow:[memoryInspectorDrawer parentWindow] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
[alert release];
|
||||
return NO;
|
||||
NSRange range;
|
||||
range.location = 0;
|
||||
range.length = -1;
|
||||
[[control currentEditor] setSelectedRange:range];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:error];
|
||||
[alert beginSheetModalForWindow:[memoryInspectorDrawer parentWindow] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
|
||||
{
|
||||
if (command == @selector(cancelOperation:)) {
|
||||
// ESC aborts editing of the cell
|
||||
[control abortEditing];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
if (command == @selector(cancelOperation:)) {
|
||||
// ESC aborts editing of the cell
|
||||
[control abortEditing];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
|
@ -375,37 +374,37 @@
|
|||
|
||||
- (void) drawerWillClose:(NSNotification *)notification
|
||||
{
|
||||
[self cancelEditingInInspector];
|
||||
lastTopRow = (unsigned)([self visibleRange].location);
|
||||
[self cancelEditingInInspector];
|
||||
lastTopRow = (unsigned)([self visibleRange].location);
|
||||
}
|
||||
|
||||
|
||||
- (void) scrollDrawerToLastTopRow
|
||||
{
|
||||
[memoryView scrollRowToTop:lastTopRow];
|
||||
[memoryView scrollRowToTop:lastTopRow];
|
||||
}
|
||||
|
||||
|
||||
- (void) drawerDidOpen:(NSNotification *)notification
|
||||
{
|
||||
// When the PDP-8 runs, the CPU window shrinks to the title bar, so the memory view scrolls to row 0
|
||||
// We can't scroll in drawerWillOpen:; even when this method runs, often the CPU window is still shrunk,
|
||||
// so a direct [memoryView scrollRowToTop:lastTopRow] has no effect, and the memory view stays at location 0.
|
||||
// So we delay the scrolling via performSelector:, accepting the side effect that the scrolling is visible.
|
||||
[self performSelector:@selector(scrollDrawerToLastTopRow) withObject:nil afterDelay:0];
|
||||
// When the PDP-8 runs, the CPU window shrinks to the title bar, so the memory view scrolls to row 0
|
||||
// We can't scroll in drawerWillOpen:; even when this method runs, often the CPU window is still shrunk,
|
||||
// so a direct [memoryView scrollRowToTop:lastTopRow] has no effect, and the memory view stays at location 0.
|
||||
// So we delay the scrolling via performSelector:, accepting the side effect that the scrolling is visible.
|
||||
[self performSelector:@selector(scrollDrawerToLastTopRow) withObject:nil afterDelay:0];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"MemoryInspectorController notifyApplicationWillTerminate");
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setObject:[currentInspector className] forKey:CURRENT_INSPECTOR_CLASS_PREFS_KEY];
|
||||
[defaults setObject:[NSNumber numberWithInt:(int)([self visibleRange].location)] forKey:TOP_ROW_PREFS_KEY];
|
||||
[defaults setObject:[NSNumber numberWithInt:alignment] forKey:ALIGNMENT_PREFS_KEY];
|
||||
NSInteger s = [memoryInspectorDrawer state];
|
||||
[defaults setBool:s == NSDrawerOpenState || s == NSDrawerOpeningState
|
||||
forKey:INSPECTOR_OPEN_PREFS_KEY];
|
||||
// NSLog (@"MemoryInspectorController notifyApplicationWillTerminate");
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setObject:[currentInspector className] forKey:CURRENT_INSPECTOR_CLASS_PREFS_KEY];
|
||||
[defaults setObject:[NSNumber numberWithInt:(int)([self visibleRange].location)] forKey:TOP_ROW_PREFS_KEY];
|
||||
[defaults setObject:[NSNumber numberWithInt:alignment] forKey:ALIGNMENT_PREFS_KEY];
|
||||
NSInteger s = [memoryInspectorDrawer state];
|
||||
[defaults setBool:s == NSDrawerOpenState || s == NSDrawerOpeningState
|
||||
forKey:INSPECTOR_OPEN_PREFS_KEY];
|
||||
}
|
||||
|
||||
|
||||
|
@ -413,51 +412,51 @@
|
|||
/* Look for memory inspector classes at "did finish launching", after plugins have been loaded at
|
||||
"will finish launching", so we find inspector classes of plugins, too. */
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
memoryInspectors = [[self allMemoryInspectors] retain];
|
||||
[popupButton removeAllItems];
|
||||
for (i = 0; i < [memoryInspectors count]; i++)
|
||||
[popupButton addItemWithTitle:[[memoryInspectors objectAtIndex:i] menuTitle]];
|
||||
NSFont *font = [NSFont userFixedPitchFontOfSize:11];
|
||||
[[[[memoryView tableColumns] objectAtIndex:ADDR_COLUMN] dataCell] setFont:font];
|
||||
[[[[memoryView tableColumns] objectAtIndex:OCTAL_COLUMN] dataCell] setFont:font];
|
||||
[[[[memoryView tableColumns] objectAtIndex:CONTENT_COLUMN] dataCell] setFont:font];
|
||||
[[[[memoryView tableColumns] objectAtIndex:OCTAL_COLUMN] dataCell]
|
||||
setFormatter:[OctalFormatter formatterWithBitMask:07777 wildcardAllowed:NO]];
|
||||
// restore preferences
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSString *currentInspectorClass = [defaults stringForKey:CURRENT_INSPECTOR_CLASS_PREFS_KEY];
|
||||
alignment = 0;
|
||||
lastTopRow = 0;
|
||||
for (i = 0; i < [memoryInspectors count]; i++) {
|
||||
if ([[[memoryInspectors objectAtIndex:i] className] isEqualToString:currentInspectorClass]) {
|
||||
[popupButton selectItemAtIndex:i];
|
||||
alignment = (int)([defaults integerForKey:ALIGNMENT_PREFS_KEY]);
|
||||
lastTopRow = (int)([defaults integerForKey:TOP_ROW_PREFS_KEY]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self selectMemoryInspector:popupButton];
|
||||
[memoryView scrollRowToTop:lastTopRow];
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:INSPECTOR_OPEN_PREFS_KEY]
|
||||
&& [[memoryInspectorDrawer parentWindow] isVisible])
|
||||
[memoryInspectorDrawer open];
|
||||
unsigned i;
|
||||
|
||||
memoryInspectors = [self allMemoryInspectors];
|
||||
[popupButton removeAllItems];
|
||||
for (i = 0; i < [memoryInspectors count]; i++)
|
||||
[popupButton addItemWithTitle:[[memoryInspectors objectAtIndex:i] menuTitle]];
|
||||
NSFont *font = [NSFont userFixedPitchFontOfSize:11];
|
||||
[[[[memoryView tableColumns] objectAtIndex:ADDR_COLUMN] dataCell] setFont:font];
|
||||
[[[[memoryView tableColumns] objectAtIndex:OCTAL_COLUMN] dataCell] setFont:font];
|
||||
[[[[memoryView tableColumns] objectAtIndex:CONTENT_COLUMN] dataCell] setFont:font];
|
||||
[[[[memoryView tableColumns] objectAtIndex:OCTAL_COLUMN] dataCell]
|
||||
setFormatter:[OctalFormatter formatterWithBitMask:07777 wildcardAllowed:NO]];
|
||||
// restore preferences
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSString *currentInspectorClass = [defaults stringForKey:CURRENT_INSPECTOR_CLASS_PREFS_KEY];
|
||||
alignment = 0;
|
||||
lastTopRow = 0;
|
||||
for (i = 0; i < [memoryInspectors count]; i++) {
|
||||
if ([[[memoryInspectors objectAtIndex:i] className] isEqualToString:currentInspectorClass]) {
|
||||
[popupButton selectItemAtIndex:i];
|
||||
alignment = (int)([defaults integerForKey:ALIGNMENT_PREFS_KEY]);
|
||||
lastTopRow = (int)([defaults integerForKey:TOP_ROW_PREFS_KEY]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
[self selectMemoryInspector:popupButton];
|
||||
[memoryView scrollRowToTop:lastTopRow];
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:INSPECTOR_OPEN_PREFS_KEY]
|
||||
&& [[memoryInspectorDrawer parentWindow] isVisible])
|
||||
[memoryInspectorDrawer open];
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
adjustTableHeaderForElCapitan (memoryView);
|
||||
// set notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationDidFinishLaunching:)
|
||||
name:NSApplicationDidFinishLaunchingNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyMemoryChanged:)
|
||||
name:MEMORY_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
adjustTableHeaderForElCapitan (memoryView);
|
||||
// set notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationDidFinishLaunching:)
|
||||
name:NSApplicationDidFinishLaunchingNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyMemoryChanged:)
|
||||
name:MEMORY_CHANGED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
}
|
||||
|
||||
|
||||
|
|
425
PC8E/PC8E.m
425
PC8E/PC8E.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* PC8E.m - PC8-E Paper Tape Reader and Punch for the PDP-8/E Simulator
|
||||
* PC8E.m - PC8-E Paper Tape Reader and Punch for the PDP-8/E Simulator
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -40,22 +40,22 @@
|
|||
#import "PC8Eiot.h"
|
||||
|
||||
|
||||
#define CODER_KEY_RBF @"rbf"
|
||||
#define CODER_KEY_PBF @"pbf"
|
||||
#define CODER_KEY_INFLAG @"inflag"
|
||||
#define CODER_KEY_INMASK @"inmask"
|
||||
#define CODER_KEY_OUTFLAG @"outflag"
|
||||
#define CODER_KEY_OUTMASK @"outmask"
|
||||
#define CODER_KEY_RBF @"rbf"
|
||||
#define CODER_KEY_PBF @"pbf"
|
||||
#define CODER_KEY_INFLAG @"inflag"
|
||||
#define CODER_KEY_INMASK @"inmask"
|
||||
#define CODER_KEY_OUTFLAG @"outflag"
|
||||
#define CODER_KEY_OUTMASK @"outmask"
|
||||
|
||||
#define NO_OUTPUT 0
|
||||
#define OUTPUT 1
|
||||
#define NO_INPUT 0
|
||||
#define INPUT 1
|
||||
#define NO_OUTPUT 0
|
||||
#define OUTPUT 1
|
||||
#define NO_INPUT 0
|
||||
#define INPUT 1
|
||||
|
||||
#define READER_CONTINUOUS_DELAY 3333333ull // nanosec. * 300 = 1 sec. => delay for 300 char/sec.
|
||||
#define READER_STARTSTOP_DELAY 40000000ull // nanosec. * 25 = 1 sec. => delay for 25 char/sec.
|
||||
#define PUNCH_DELAY 20000000ull // nanosec. * 50 = 1 sec. => delay for 50 char/sec.
|
||||
#define STOP_DELAY 6000000ull // "stop delay" occurs 6 ms after RFC
|
||||
#define READER_CONTINUOUS_DELAY 3333333ull // nanosec. * 300 = 1 sec. => delay for 300 char/sec.
|
||||
#define READER_STARTSTOP_DELAY 40000000ull // nanosec. * 25 = 1 sec. => delay for 25 char/sec.
|
||||
#define PUNCH_DELAY 20000000ull // nanosec. * 50 = 1 sec. => delay for 50 char/sec.
|
||||
#define STOP_DELAY 6000000ull // "stop delay" occurs 6 ms after RFC
|
||||
|
||||
|
||||
@implementation PC8E
|
||||
|
@ -69,89 +69,89 @@ API_VERSION
|
|||
|
||||
- (NSArray *) iotsForAddress:(int)ioAddress
|
||||
{
|
||||
return ioAddress == 01 ?
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6010],
|
||||
[NSValue valueWithPointer:i6011],
|
||||
[NSValue valueWithPointer:i6012],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6014],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6016],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil] :
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6020],
|
||||
[NSValue valueWithPointer:i6021],
|
||||
[NSValue valueWithPointer:i6022],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6024],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6026],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
return ioAddress == 01 ?
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6010],
|
||||
[NSValue valueWithPointer:i6011],
|
||||
[NSValue valueWithPointer:i6012],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6014],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6016],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil] :
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6020],
|
||||
[NSValue valueWithPointer:i6021],
|
||||
[NSValue valueWithPointer:i6022],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6024],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6026],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) skiptestsForAddress:(int)ioAddress
|
||||
{
|
||||
return ioAddress == 01 ?
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6011],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil] :
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6021],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
return ioAddress == 01 ?
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6011],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil] :
|
||||
[NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6021],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) setIOFlag:(unsigned long)flag forIOFlagName:(NSString *)name;
|
||||
{
|
||||
if (inflag)
|
||||
outflag = flag;
|
||||
else
|
||||
inflag = flag;
|
||||
if (inflag)
|
||||
outflag = flag;
|
||||
else
|
||||
inflag = flag;
|
||||
}
|
||||
|
||||
|
||||
- (void) CAF:(int)ioAddress
|
||||
{
|
||||
if (ioAddress == 01) { // CAF is called twice, ignore second call (01 == reader I/O address)
|
||||
RBF = 0;
|
||||
PBF = 0;
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
if (ioAddress == 01) { // CAF is called twice, ignore second call (01 == reader I/O address)
|
||||
RBF = 0;
|
||||
PBF = 0;
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) clearAllFlags:(int)ioAddress
|
||||
{
|
||||
if (ioAddress == 01) // CAF is called twice, ignore second call (01 == reader I/O address)
|
||||
[self resetDevice];
|
||||
if (ioAddress == 01) // CAF is called twice, ignore second call (01 == reader I/O address)
|
||||
[self resetDevice];
|
||||
}
|
||||
|
||||
|
||||
- (void) resetDevice
|
||||
{
|
||||
[self setRBF:0];
|
||||
[self setPBF:0];
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
[self setRBF:0];
|
||||
[self setPBF:0];
|
||||
[pdp8 setInterruptMaskBits:inflag | outflag];
|
||||
[pdp8 clearIOFlagBits:inflag | outflag];
|
||||
}
|
||||
|
||||
|
||||
|
@ -160,84 +160,84 @@ API_VERSION
|
|||
|
||||
- (void) realtimeDelay:(uint64_t)matStartTime lastStart:(uint64_t)matLastStartTime
|
||||
{
|
||||
int speed = [pdp8 getGoSpeed];
|
||||
if (speed != GO_AS_FAST_AS_POSSIBLE) {
|
||||
uint64_t delay;
|
||||
if (matLastStartTime == 0) // punch with 50 cps
|
||||
delay = PUNCH_DELAY;
|
||||
else { // reader
|
||||
uint64_t delta = absolute2nanoseconds(matStartTime - matLastStartTime);
|
||||
if (delta > READER_STARTSTOP_DELAY) // next char already buffered
|
||||
delay = 0;
|
||||
else
|
||||
if (delta > STOP_DELAY) // start stop mode with 25 cps
|
||||
delay = READER_STARTSTOP_DELAY;
|
||||
else // continuous read with 300 cps
|
||||
delay = READER_CONTINUOUS_DELAY;
|
||||
}
|
||||
if (speed == GO_WITH_PDP8_SPEED)
|
||||
mach_wait_until (matStartTime + nanoseconds2absolute(delay));
|
||||
else {
|
||||
while (mach_absolute_time() < matStartTime + nanoseconds2absolute(delay))
|
||||
;
|
||||
}
|
||||
}
|
||||
int speed = [pdp8 getGoSpeed];
|
||||
if (speed != GO_AS_FAST_AS_POSSIBLE) {
|
||||
uint64_t delay;
|
||||
if (matLastStartTime == 0) // punch with 50 cps
|
||||
delay = PUNCH_DELAY;
|
||||
else { // reader
|
||||
uint64_t delta = absolute2nanoseconds(matStartTime - matLastStartTime);
|
||||
if (delta > READER_STARTSTOP_DELAY) // next char already buffered
|
||||
delay = 0;
|
||||
else
|
||||
if (delta > STOP_DELAY) // start stop mode with 25 cps
|
||||
delay = READER_STARTSTOP_DELAY;
|
||||
else // continuous read with 300 cps
|
||||
delay = READER_CONTINUOUS_DELAY;
|
||||
}
|
||||
if (speed == GO_WITH_PDP8_SPEED)
|
||||
mach_wait_until (matStartTime + nanoseconds2absolute(delay));
|
||||
else {
|
||||
while (mach_absolute_time() < matStartTime + nanoseconds2absolute(delay))
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) canContinueInput
|
||||
{
|
||||
if ([inputLock tryLockWhenCondition:NO_INPUT])
|
||||
[inputLock unlockWithCondition:INPUT];
|
||||
if ([inputLock tryLockWhenCondition:NO_INPUT])
|
||||
[inputLock unlockWithCondition:INPUT];
|
||||
#if ! defined(NS_BLOCK_ASSERTIONS)
|
||||
else
|
||||
NSLog (@"PDP-8 software bug: RFC or RCC executed before preceding tape read finished");
|
||||
else
|
||||
NSLog (@"PDP-8 software bug: RFC or RCC executed before preceding tape read finished");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void) canContinueOutput
|
||||
{
|
||||
if ([outputLock tryLockWhenCondition:NO_OUTPUT])
|
||||
[outputLock unlockWithCondition:OUTPUT];
|
||||
if ([outputLock tryLockWhenCondition:NO_OUTPUT])
|
||||
[outputLock unlockWithCondition:OUTPUT];
|
||||
#if ! defined(NS_BLOCK_ASSERTIONS)
|
||||
else
|
||||
NSLog (@"PDP-8 software bug: PPC or PLS executed before preceding tape punch finished");
|
||||
else
|
||||
NSLog (@"PDP-8 software bug: PPC or PLS executed before preceding tape punch finished");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void) pc8eReaderThread:(id)object
|
||||
{
|
||||
uint64_t matStartTime = mach_absolute_time();
|
||||
uint64_t matLastStartTime;
|
||||
for (;;) {
|
||||
[inputLock lockWhenCondition:INPUT];
|
||||
matLastStartTime = matStartTime;
|
||||
matStartTime = mach_absolute_time();
|
||||
input = [reader getChar];
|
||||
if (input != EOF)
|
||||
[self setRBF:input & 0377]; // strip off Unicode characters etc.
|
||||
[inputLock unlockWithCondition:NO_INPUT];
|
||||
[self realtimeDelay:matStartTime lastStart:matLastStartTime];
|
||||
if (input != EOF)
|
||||
[pdp8 setIOFlagBits:inflag];
|
||||
}
|
||||
uint64_t matStartTime = mach_absolute_time();
|
||||
uint64_t matLastStartTime;
|
||||
for (;;) {
|
||||
[inputLock lockWhenCondition:INPUT];
|
||||
matLastStartTime = matStartTime;
|
||||
matStartTime = mach_absolute_time();
|
||||
input = [reader getChar];
|
||||
if (input != EOF)
|
||||
[self setRBF:input & 0377]; // strip off Unicode characters etc.
|
||||
[inputLock unlockWithCondition:NO_INPUT];
|
||||
[self realtimeDelay:matStartTime lastStart:matLastStartTime];
|
||||
if (input != EOF)
|
||||
[pdp8 setIOFlagBits:inflag];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) pc8ePunchThread:(id)object
|
||||
{
|
||||
for (;;) {
|
||||
[outputLock lockWhenCondition:OUTPUT];
|
||||
uint64_t matStart = mach_absolute_time();
|
||||
[self setPBF:output];
|
||||
BOOL done = [punch putChar:output handleBackspace:NO];
|
||||
[outputLock unlockWithCondition:NO_OUTPUT];
|
||||
[self realtimeDelay:matStart lastStart:0];
|
||||
if (done)
|
||||
[pdp8 setIOFlagBits:outflag];
|
||||
}
|
||||
for (;;) {
|
||||
[outputLock lockWhenCondition:OUTPUT];
|
||||
uint64_t matStart = mach_absolute_time();
|
||||
[self setPBF:output];
|
||||
BOOL done = [punch putChar:output handleBackspace:NO];
|
||||
[outputLock unlockWithCondition:NO_OUTPUT];
|
||||
[self realtimeDelay:matStart lastStart:0];
|
||||
if (done)
|
||||
[pdp8 setIOFlagBits:outflag];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -246,53 +246,53 @@ API_VERSION
|
|||
|
||||
- (unsigned short) getRBF
|
||||
{
|
||||
return RBF;
|
||||
return RBF;
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyRBF
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RBF_CHANGED_NOTIFICATION object:self];
|
||||
|
||||
NSAssertRunningOnMainThread ();
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:RBF_CHANGED_NOTIFICATION object:self];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) setRBF:(unsigned short)rbf
|
||||
{
|
||||
NSAssert1 ((rbf & ~0377) == 0, @"Bad RBF: 0%o", rbf);
|
||||
RBF = rbf;
|
||||
if ([NSThread isMainThread])
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:RBF_CHANGED_NOTIFICATION object:self];
|
||||
else
|
||||
[self performSelectorOnMainThread:@selector(notifyRBF) withObject:self waitUntilDone:NO];
|
||||
NSAssert1 ((rbf & ~0377) == 0, @"Bad RBF: 0%o", rbf);
|
||||
RBF = rbf;
|
||||
if ([NSThread isMainThread])
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:RBF_CHANGED_NOTIFICATION object:self];
|
||||
else
|
||||
[self performSelectorOnMainThread:@selector(notifyRBF) withObject:self waitUntilDone:NO];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getPBF
|
||||
{
|
||||
return PBF;
|
||||
return PBF;
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPBF
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:PBF_CHANGED_NOTIFICATION object:self];
|
||||
|
||||
NSAssertRunningOnMainThread ();
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:PBF_CHANGED_NOTIFICATION object:self];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) setPBF:(unsigned short)pbf
|
||||
{
|
||||
NSAssert1 ((pbf & ~0377) == 0, @"Bad PBF: 0%o", pbf);
|
||||
PBF = pbf;
|
||||
if ([NSThread isMainThread])
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:PBF_CHANGED_NOTIFICATION object:self];
|
||||
else
|
||||
[self performSelectorOnMainThread:@selector(notifyPBF) withObject:self waitUntilDone:NO];
|
||||
NSAssert1 ((pbf & ~0377) == 0, @"Bad PBF: 0%o", pbf);
|
||||
PBF = pbf;
|
||||
if ([NSThread isMainThread])
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:PBF_CHANGED_NOTIFICATION object:self];
|
||||
else
|
||||
[self performSelectorOnMainThread:@selector(notifyPBF) withObject:self waitUntilDone:NO];
|
||||
}
|
||||
|
||||
|
||||
|
@ -301,22 +301,21 @@ API_VERSION
|
|||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"PC8E notifyApplicationWillTerminate");
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[archiver release];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
// NSLog (@"PC8E notifyApplicationWillTerminate");
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification
|
||||
object:nil];
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPluginsLoaded:(NSNotification *)notification
|
||||
{
|
||||
[window orderBackFromDefaults:self];
|
||||
[window makeFirstResponder:window];
|
||||
[window orderBackFromDefaults:self];
|
||||
[window makeFirstResponder:window];
|
||||
}
|
||||
|
||||
|
||||
|
@ -325,55 +324,57 @@ API_VERSION
|
|||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
[self setRBF:[coder decodeIntForKey:CODER_KEY_RBF]];
|
||||
[self setPBF:[coder decodeIntForKey:CODER_KEY_PBF]];
|
||||
[coder decodeBoolForKey:CODER_KEY_INFLAG] ?
|
||||
[pdp8 setIOFlagBits:inflag] : [pdp8 clearIOFlagBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_INMASK] ?
|
||||
[pdp8 setInterruptMaskBits:inflag] : [pdp8 clearInterruptMaskBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTFLAG] ?
|
||||
[pdp8 setIOFlagBits:outflag] : [pdp8 clearIOFlagBits:outflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTMASK] ?
|
||||
[pdp8 setInterruptMaskBits:outflag] : [pdp8 clearInterruptMaskBits:outflag];
|
||||
return self;
|
||||
self = [super init];
|
||||
[self loadCoder: coder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadCoder:(NSCoder *)coder {
|
||||
[self setRBF:[coder decodeIntForKey:CODER_KEY_RBF]];
|
||||
[self setPBF:[coder decodeIntForKey:CODER_KEY_PBF]];
|
||||
[coder decodeBoolForKey:CODER_KEY_INFLAG] ?
|
||||
[pdp8 setIOFlagBits:inflag] : [pdp8 clearIOFlagBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_INMASK] ?
|
||||
[pdp8 setInterruptMaskBits:inflag] : [pdp8 clearInterruptMaskBits:inflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTFLAG] ?
|
||||
[pdp8 setIOFlagBits:outflag] : [pdp8 clearIOFlagBits:outflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_OUTMASK] ?
|
||||
[pdp8 setInterruptMaskBits:outflag] : [pdp8 clearInterruptMaskBits:outflag];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeInt:[self getRBF] forKey:CODER_KEY_RBF];
|
||||
[coder encodeInt:[self getPBF] forKey:CODER_KEY_PBF];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:inflag] ? YES : NO forKey:CODER_KEY_INFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:inflag] ? YES : NO forKey:CODER_KEY_INMASK];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:outflag] ? YES : NO forKey:CODER_KEY_OUTFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:outflag] ? YES : NO forKey:CODER_KEY_OUTMASK];
|
||||
[coder encodeInt:[self getRBF] forKey:CODER_KEY_RBF];
|
||||
[coder encodeInt:[self getPBF] forKey:CODER_KEY_PBF];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:inflag] ? YES : NO forKey:CODER_KEY_INFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:inflag] ? YES : NO forKey:CODER_KEY_INMASK];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:outflag] ? YES : NO forKey:CODER_KEY_OUTFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:outflag] ? YES : NO forKey:CODER_KEY_OUTMASK];
|
||||
}
|
||||
|
||||
|
||||
- (void) pluginDidLoad
|
||||
{
|
||||
[rbfCell setupRegisterFor:self getRegisterValue:@selector(getRBF) setRegisterValue:@selector(setRBF:)
|
||||
changedNotificationName:RBF_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
[pbfCell setupRegisterFor:self getRegisterValue:@selector(getPBF) setRegisterValue:@selector(setPBF:)
|
||||
changedNotificationName:PBF_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self initWithCoder:unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
[unarchiver release];
|
||||
}
|
||||
inputLock = [[NSConditionLock alloc] initWithCondition:NO_INPUT];
|
||||
outputLock = [[NSConditionLock alloc] initWithCondition:NO_OUTPUT];
|
||||
[NSThread detachNewThreadSelector:@selector(pc8eReaderThread:) toTarget:self withObject:nil];
|
||||
[NSThread detachNewThreadSelector:@selector(pc8ePunchThread:) toTarget:self withObject:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
[rbfCell setupRegisterFor:self getRegisterValue:@selector(getRBF) setRegisterValue:@selector(setRBF:)
|
||||
changedNotificationName:RBF_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
[pbfCell setupRegisterFor:self getRegisterValue:@selector(getPBF) setRegisterValue:@selector(setPBF:)
|
||||
changedNotificationName:PBF_CHANGED_NOTIFICATION mask:0377 base:8];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self loadCoder:unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
inputLock = [[NSConditionLock alloc] initWithCondition:NO_INPUT];
|
||||
outputLock = [[NSConditionLock alloc] initWithCondition:NO_OUTPUT];
|
||||
[NSThread detachNewThreadSelector:@selector(pc8eReaderThread:) toTarget:self withObject:nil];
|
||||
[NSThread detachNewThreadSelector:@selector(pc8ePunchThread:) toTarget:self withObject:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* BootstrapPanelController.h - Controller for the bootstrap panel
|
||||
* BootstrapPanelController.h - Controller for the bootstrap panel
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -31,90 +31,99 @@
|
|||
@implementation BootstrapPanelController
|
||||
|
||||
|
||||
#define LOW_SPEED_RIM_TAG 0
|
||||
#define HIGH_SPEED_RIM_TAG 1
|
||||
#define BIN_LOADER_TAG 2
|
||||
#define RK8E_BOOTCODE_TAG 3
|
||||
#define LOW_SPEED_RIM_TAG 0
|
||||
#define HIGH_SPEED_RIM_TAG 1
|
||||
#define BIN_LOADER_TAG 2
|
||||
#define RK8E_BOOTCODE_TAG 3
|
||||
|
||||
#define LOW_SPEED_RIM_TAPE @"lowspeedRIM.bin"
|
||||
#define HIGH_SPEED_RIM_TAPE @"highspeedRIM.bin"
|
||||
#define BIN_LOADER_TAPE @"binLoader.rim"
|
||||
#define RK8E_BOOTCODE_TAPE @"rk8eBootcode.bin"
|
||||
#define LOW_SPEED_RIM_TAPE @"lowspeedRIM.bin"
|
||||
#define HIGH_SPEED_RIM_TAPE @"highspeedRIM.bin"
|
||||
#define BIN_LOADER_TAPE @"binLoader.rim"
|
||||
#define RK8E_BOOTCODE_TAPE @"rk8eBootcode.bin"
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyMemorySizeChanged:)
|
||||
name:KM8E_MOUNT_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyMemorySizeChanged:)
|
||||
name:KM8E_MOUNT_NOTIFICATION object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) validateMenuItem:(NSMenuItem *)menuItem // only the Load Bootstrap Loader menu item
|
||||
- (BOOL) validateMenuItem:(NSMenuItem *)menuItem // only the Load Bootstrap Loader menu item
|
||||
{
|
||||
return ! [pdp8 isGoing];
|
||||
return ! [pdp8 isGoing];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyMemorySizeChanged:(NSNotification *)notification
|
||||
{
|
||||
[ifStepper setMaxValue:([pdp8 memorySize] >> 12) - 1];
|
||||
[[ifStepper target] performSelector:[ifStepper action] withObject:ifStepper];
|
||||
[ifStepper setMaxValue:([pdp8 memorySize] >> 12) - 1];
|
||||
id targ = [ifStepper target];
|
||||
SEL act = [ifStepper action];
|
||||
if ([targ respondsToSelector:act])
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[targ performSelector:act withObject:ifStepper];
|
||||
#pragma clang diagnostic pop
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:%s", sel_getName(act));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) loadBootstrapLoader:(id)sender
|
||||
{
|
||||
unsigned addr, field;
|
||||
NSString *error, *path, *file;
|
||||
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
unsigned addr, field;
|
||||
NSString *error, *path, *file;
|
||||
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
|
||||
switch ([[loaderRadioButtons selectedCell] tag]) {
|
||||
case LOW_SPEED_RIM_TAG :
|
||||
path = [mainBundle pathForResource:LOW_SPEED_RIM_TAPE ofType:nil];
|
||||
file = LOW_SPEED_RIM_TAPE;
|
||||
field = [ifStepper intValue];
|
||||
addr = 07756;
|
||||
break;
|
||||
case HIGH_SPEED_RIM_TAG :
|
||||
path = [mainBundle pathForResource:HIGH_SPEED_RIM_TAPE ofType:nil];
|
||||
file = HIGH_SPEED_RIM_TAPE;
|
||||
field = [ifStepper intValue];
|
||||
addr = 07756;
|
||||
break;
|
||||
case BIN_LOADER_TAG :
|
||||
path = [mainBundle pathForResource:BIN_LOADER_TAPE ofType:nil];
|
||||
file = BIN_LOADER_TAPE;
|
||||
field = [ifStepper intValue];
|
||||
addr = 07777;
|
||||
break;
|
||||
case RK8E_BOOTCODE_TAG :
|
||||
path = [mainBundle pathForResource:RK8E_BOOTCODE_TAPE ofType:nil];
|
||||
file = RK8E_BOOTCODE_TAPE;
|
||||
field = 0;
|
||||
addr = 00027;
|
||||
break;
|
||||
default : /* to avoid compiler "used uninitialized" warning */
|
||||
path = file = nil;
|
||||
field = addr = 0;
|
||||
break;
|
||||
}
|
||||
error = [pdp8 loadPaperTape:path toField:field];
|
||||
if (error) {
|
||||
if (! path)
|
||||
path = [NSString stringWithFormat:NSLocalizedString(
|
||||
@"The resource file %@ is missing in the application bundle.", @""), file];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSAlertStyleWarning];
|
||||
[alert setMessageText:error];
|
||||
[alert setInformativeText:path];
|
||||
[alert runModal];
|
||||
[alert release];
|
||||
} else if ([adjustPCCheckbox intValue]) {
|
||||
[pdp8 setPC:addr];
|
||||
[pdp8 setIF:field];
|
||||
[pdp8 setIB:field];
|
||||
}
|
||||
switch ([[loaderRadioButtons selectedCell] tag]) {
|
||||
case LOW_SPEED_RIM_TAG :
|
||||
path = [mainBundle pathForResource:LOW_SPEED_RIM_TAPE ofType:nil];
|
||||
file = LOW_SPEED_RIM_TAPE;
|
||||
field = [ifStepper intValue];
|
||||
addr = 07756;
|
||||
break;
|
||||
case HIGH_SPEED_RIM_TAG :
|
||||
path = [mainBundle pathForResource:HIGH_SPEED_RIM_TAPE ofType:nil];
|
||||
file = HIGH_SPEED_RIM_TAPE;
|
||||
field = [ifStepper intValue];
|
||||
addr = 07756;
|
||||
break;
|
||||
case BIN_LOADER_TAG :
|
||||
path = [mainBundle pathForResource:BIN_LOADER_TAPE ofType:nil];
|
||||
file = BIN_LOADER_TAPE;
|
||||
field = [ifStepper intValue];
|
||||
addr = 07777;
|
||||
break;
|
||||
case RK8E_BOOTCODE_TAG :
|
||||
path = [mainBundle pathForResource:RK8E_BOOTCODE_TAPE ofType:nil];
|
||||
file = RK8E_BOOTCODE_TAPE;
|
||||
field = 0;
|
||||
addr = 00027;
|
||||
break;
|
||||
default : /* to avoid compiler "used uninitialized" warning */
|
||||
path = file = nil;
|
||||
field = addr = 0;
|
||||
break;
|
||||
}
|
||||
error = [pdp8 loadPaperTape:path toField:field];
|
||||
if (error) {
|
||||
if (! path)
|
||||
path = [NSString stringWithFormat:NSLocalizedString(
|
||||
@"The resource file %@ is missing in the application bundle.", @""), file];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSAlertStyleWarning];
|
||||
[alert setMessageText:error];
|
||||
[alert setInformativeText:path];
|
||||
[alert runModal];
|
||||
} else if ([adjustPCCheckbox intValue]) {
|
||||
[pdp8 setPC:addr];
|
||||
[pdp8 setIF:field];
|
||||
[pdp8 setIB:field];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* BreakpointController.m - Class for maintaining breakpoints
|
||||
* BreakpointController.m - Class for maintaining breakpoints
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -38,187 +38,186 @@
|
|||
enabled bit in the breakpoints enable bit mask, i. e. 1, 2, 4, 8,...
|
||||
Then ALL_BREAKPOINTS is the mask for "all columns enabled". */
|
||||
|
||||
#define ADDRESS_COLUMN 0
|
||||
#define ALL_BREAKPOINTS ((1 << ([tableView numberOfColumns] - 1)) - 1)
|
||||
#define ADDRESS_COLUMN 0
|
||||
#define ALL_BREAKPOINTS ((1 << ([tableView numberOfColumns] - 1)) - 1)
|
||||
|
||||
|
||||
/* #defines for the cases where the instance must know if it is the
|
||||
breakpoints or break opcodes controller */
|
||||
|
||||
#define IS_BREAKPOINT_CONTROLLER ([tableView numberOfColumns] == 2)
|
||||
#define IS_BREAKOPCODE_CONTROLLER ([tableView numberOfColumns] == 3)
|
||||
#define IS_BREAKPOINT_CONTROLLER ([tableView numberOfColumns] == 2)
|
||||
#define IS_BREAKOPCODE_CONTROLLER ([tableView numberOfColumns] == 3)
|
||||
|
||||
#define MAX_ADDRESS (IS_BREAKPOINT_CONTROLLER ? 077777 : 07777)
|
||||
#define MAX_ADDRESS (IS_BREAKPOINT_CONTROLLER ? 077777 : 07777)
|
||||
|
||||
#define BREAKPOINT_COLUMN 1
|
||||
#define USER_BREAKOPCODE_COLUMN 1
|
||||
#define SYSTEM_BREAKOPCODE_COLUMN 2
|
||||
#define BREAKPOINT_COLUMN 1
|
||||
#define USER_BREAKOPCODE_COLUMN 1
|
||||
#define SYSTEM_BREAKOPCODE_COLUMN 2
|
||||
|
||||
|
||||
- (void) notifyUpdateBreakpointView:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"BreakpointController notifyUpdateBreakpointView");
|
||||
[enableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:ALL_BREAKPOINTS]];
|
||||
[disableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:0]];
|
||||
[tableView reloadData];
|
||||
// NSLog (@"BreakpointController notifyUpdateBreakpointView");
|
||||
[enableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:ALL_BREAKPOINTS]];
|
||||
[disableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:0]];
|
||||
[tableView reloadData];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) addBreakpoint:(id)sender
|
||||
{
|
||||
[[sender window] makeKeyWindow];
|
||||
[breakpoints setBreakpointWithIdentifier:0 value:ALL_BREAKPOINTS];
|
||||
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
||||
[tableView editColumn:[tableView columnWithIdentifier:
|
||||
[NSString stringWithFormat:@"%d", ADDRESS_COLUMN]]
|
||||
row:0 withEvent:nil select:YES];
|
||||
[[sender window] makeKeyWindow];
|
||||
[breakpoints setBreakpointWithIdentifier:0 value:ALL_BREAKPOINTS];
|
||||
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO];
|
||||
[tableView editColumn:[tableView columnWithIdentifier:
|
||||
[NSString stringWithFormat:@"%d", ADDRESS_COLUMN]]
|
||||
row:0 withEvent:nil select:YES];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) deleteBreakpoint:(id)sender
|
||||
{
|
||||
NSInteger selectedRow = [tableView selectedRow];
|
||||
[tableView reloadData]; // when editing, this saves the edited cell that will be deleted
|
||||
[breakpoints deleteBreakpointsAtIndexes:[tableView selectedRowIndexes]];
|
||||
// reselect old row, otherwise selection jumps to the position of the edited but deleted breakpoint
|
||||
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO];
|
||||
NSInteger selectedRow = [tableView selectedRow];
|
||||
[tableView reloadData]; // when editing, this saves the edited cell that will be deleted
|
||||
[breakpoints deleteBreakpointsAtIndexes:[tableView selectedRowIndexes]];
|
||||
// reselect old row, otherwise selection jumps to the position of the edited but deleted breakpoint
|
||||
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) enableAllBreakpoints:(id)sender
|
||||
{
|
||||
[breakpoints setAllValues:ALL_BREAKPOINTS];
|
||||
[breakpoints setAllValues:ALL_BREAKPOINTS];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) disableAllBreakpoints:(id)sender
|
||||
{
|
||||
[breakpoints setAllValues:0];
|
||||
[breakpoints setAllValues:0];
|
||||
}
|
||||
|
||||
|
||||
- (void) tableViewSelectionDidChange:(NSNotification *)notification
|
||||
{
|
||||
[deleteButton setEnabled:[tableView numberOfSelectedRows] != 0];
|
||||
[deleteButton setEnabled:[tableView numberOfSelectedRows] != 0];
|
||||
}
|
||||
|
||||
|
||||
- (int) numberOfRowsInTableView:(NSTableView *)tableView
|
||||
{
|
||||
return [breakpoints numberOfBreakpoints];
|
||||
return [breakpoints numberOfBreakpoints];
|
||||
}
|
||||
|
||||
|
||||
- (id) tableView:(NSTableView *)tableView
|
||||
objectValueForTableColumn:(NSTableColumn *)column row:(int)row
|
||||
objectValueForTableColumn:(NSTableColumn *)column row:(int)row
|
||||
{
|
||||
int columnID = [[column identifier] intValue];
|
||||
return columnID == ADDRESS_COLUMN ?
|
||||
[NSNumber numberWithInt:[breakpoints identifierAtIndex:row]] :
|
||||
[NSNumber numberWithBool:[breakpoints valueAtIndex:row] & columnID];
|
||||
int columnID = [[column identifier] intValue];
|
||||
return columnID == ADDRESS_COLUMN ?
|
||||
[NSNumber numberWithInt:[breakpoints identifierAtIndex:row]] :
|
||||
[NSNumber numberWithBool:[breakpoints valueAtIndex:row] & columnID];
|
||||
}
|
||||
|
||||
|
||||
- (void) tableView:(NSTableView *)tabView setObjectValue:(id)object
|
||||
forTableColumn:(NSTableColumn *)column row:(NSUInteger)row
|
||||
forTableColumn:(NSTableColumn *)column row:(NSUInteger)row
|
||||
{
|
||||
int columnID = [[column identifier] intValue];
|
||||
if (columnID == ADDRESS_COLUMN) {
|
||||
[breakpoints deleteBreakpointAtIndex:(uint)row];
|
||||
if ([object isKindOfClass:[NSNumber class]])
|
||||
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:
|
||||
[breakpoints setBreakpointWithIdentifier:[object intValue]
|
||||
value:ALL_BREAKPOINTS]]
|
||||
byExtendingSelection:NO];
|
||||
else {
|
||||
NSIndexSet *index = [breakpoints setBreakpointsWithIdentifierArray:object
|
||||
value:ALL_BREAKPOINTS];
|
||||
[tableView selectRowIndexes:index byExtendingSelection:NO];
|
||||
row = [index firstIndex];
|
||||
}
|
||||
[tableView editColumn:0 row:0 withEvent:nil select:NO];
|
||||
// [tableView abortEditing] does not work, so edit an invalid cell
|
||||
[tableView scrollRowToVisible:row];
|
||||
[tableView reloadData];
|
||||
[enableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:ALL_BREAKPOINTS]];
|
||||
[disableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:0]];
|
||||
} else {
|
||||
unsigned value = [breakpoints valueAtIndex:(uint)row];
|
||||
if ([[NSApp currentEvent] modifierFlags] & NSEventModifierFlagOption)
|
||||
value = value ? 0 : ALL_BREAKPOINTS;
|
||||
else
|
||||
value = (value & columnID) ? (value & ~columnID) : (value | columnID);
|
||||
[breakpoints setBreakpointWithIdentifier:[breakpoints identifierAtIndex:(uint)row] value:value];
|
||||
}
|
||||
int columnID = [[column identifier] intValue];
|
||||
if (columnID == ADDRESS_COLUMN) {
|
||||
[breakpoints deleteBreakpointAtIndex:(uint)row];
|
||||
if ([object isKindOfClass:[NSNumber class]])
|
||||
[tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:
|
||||
[breakpoints setBreakpointWithIdentifier:[object intValue]
|
||||
value:ALL_BREAKPOINTS]]
|
||||
byExtendingSelection:NO];
|
||||
else {
|
||||
NSIndexSet *index = [breakpoints setBreakpointsWithIdentifierArray:object
|
||||
value:ALL_BREAKPOINTS];
|
||||
[tableView selectRowIndexes:index byExtendingSelection:NO];
|
||||
row = [index firstIndex];
|
||||
}
|
||||
[tableView editColumn:0 row:0 withEvent:nil select:NO];
|
||||
// [tableView abortEditing] does not work, so edit an invalid cell
|
||||
[tableView scrollRowToVisible:row];
|
||||
[tableView reloadData];
|
||||
[enableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:ALL_BREAKPOINTS]];
|
||||
[disableAllButton setEnabled:[breakpoints hasBreakpointWithValueNotEqualTo:0]];
|
||||
} else {
|
||||
unsigned value = [breakpoints valueAtIndex:(uint)row];
|
||||
if ([[NSApp currentEvent] modifierFlags] & NSEventModifierFlagOption)
|
||||
value = value ? 0 : ALL_BREAKPOINTS;
|
||||
else
|
||||
value = (value & columnID) ? (value & ~columnID) : (value | columnID);
|
||||
[breakpoints setBreakpointWithIdentifier:[breakpoints identifierAtIndex:(uint)row] value:value];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) tableView:(NSTableView *)tabView toolTipForCell:(NSCell *)cell
|
||||
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
||||
mouseLocation:(NSPoint)mouseLocation
|
||||
rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)column row:(int)row
|
||||
mouseLocation:(NSPoint)mouseLocation
|
||||
{
|
||||
switch ([[column identifier] intValue]) {
|
||||
case ADDRESS_COLUMN :
|
||||
return IS_BREAKPOINT_CONTROLLER ?
|
||||
NSLocalizedString(
|
||||
@"Address where the PDP-8 halts when the breakpoint is enabled", @"") :
|
||||
NSLocalizedString(
|
||||
@"Opcode that causes the PDP-8 to halt when enabled for the current mode", @"");
|
||||
case BREAKPOINT_COLUMN | USER_BREAKOPCODE_COLUMN :
|
||||
return IS_BREAKPOINT_CONTROLLER ?
|
||||
NSLocalizedString(@"Enables or disables this breakpoint", @"") :
|
||||
NSLocalizedString(@"Enables or disables this break opcode for PDP-8 user mode "
|
||||
@"(option-click to set user and system mode simultaneously)", @"");
|
||||
case SYSTEM_BREAKOPCODE_COLUMN :
|
||||
return NSLocalizedString(@"Enables or disables this break opcode for PDP-8 system mode "
|
||||
@"(option-click to set user and system mode simultaneously)", @"");
|
||||
switch ([[column identifier] intValue]) {
|
||||
case ADDRESS_COLUMN :
|
||||
return IS_BREAKPOINT_CONTROLLER ?
|
||||
NSLocalizedString(
|
||||
@"Address where the PDP-8 halts when the breakpoint is enabled", @"") :
|
||||
NSLocalizedString(
|
||||
@"Opcode that causes the PDP-8 to halt when enabled for the current mode", @"");
|
||||
case BREAKPOINT_COLUMN | USER_BREAKOPCODE_COLUMN :
|
||||
return IS_BREAKPOINT_CONTROLLER ?
|
||||
NSLocalizedString(@"Enables or disables this breakpoint", @"") :
|
||||
NSLocalizedString(@"Enables or disables this break opcode for PDP-8 user mode "
|
||||
@"(option-click to set user and system mode simultaneously)", @"");
|
||||
case SYSTEM_BREAKOPCODE_COLUMN :
|
||||
return NSLocalizedString(@"Enables or disables this break opcode for PDP-8 system mode "
|
||||
@"(option-click to set user and system mode simultaneously)", @"");
|
||||
|
||||
default :
|
||||
NSAssert (FALSE, @"Unknown column in BreakpointControllers table view");
|
||||
break;
|
||||
}
|
||||
return nil;
|
||||
default :
|
||||
NSAssert (FALSE, @"Unknown column in BreakpointControllers table view");
|
||||
break;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) control:(NSControl *)control didFailToFormatString:(NSString *)string
|
||||
errorDescription:(NSString *)error
|
||||
errorDescription:(NSString *)error
|
||||
{
|
||||
[control abortEditing];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:error];
|
||||
[alert beginSheetModalForWindow:[control window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
[alert release];
|
||||
return NO;
|
||||
[control abortEditing];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:error];
|
||||
[alert beginSheetModalForWindow:[control window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
NSCell *dataCell = [[tableView tableColumnWithIdentifier:
|
||||
[NSString stringWithFormat:@"%d", ADDRESS_COLUMN]] dataCell];
|
||||
[dataCell setFormatter:[OctalFormatter formatterWithBitMask:MAX_ADDRESS wildcardAllowed:YES]];
|
||||
[dataCell setFont:[NSFont userFixedPitchFontOfSize:11]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyUpdateBreakpointView:)
|
||||
name:BREAKPOINTS_CHANGED_NOTIFICATION object:breakpoints];
|
||||
/* set max width = min width of the panel: IB only allows max width one pixel more
|
||||
than min width, so the user can resize the width for one pixel - bug in IB? */
|
||||
NSSize size = [[tableView window] minSize];
|
||||
size.height = [[tableView window] maxSize].height;
|
||||
[[tableView window] setMaxSize:size];
|
||||
if (runningOnLionOrNewer()) { // move the + and - button title one pixel up
|
||||
NSMutableParagraphStyle *style= [[[NSMutableParagraphStyle alloc] init] autorelease];
|
||||
NSCell *dataCell = [[tableView tableColumnWithIdentifier:
|
||||
[NSString stringWithFormat:@"%d", ADDRESS_COLUMN]] dataCell];
|
||||
[dataCell setFormatter:[OctalFormatter formatterWithBitMask:MAX_ADDRESS wildcardAllowed:YES]];
|
||||
[dataCell setFont:[NSFont userFixedPitchFontOfSize:11]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyUpdateBreakpointView:)
|
||||
name:BREAKPOINTS_CHANGED_NOTIFICATION object:breakpoints];
|
||||
/* set max width = min width of the panel: IB only allows max width one pixel more
|
||||
than min width, so the user can resize the width for one pixel - bug in IB? */
|
||||
NSSize size = [[tableView window] minSize];
|
||||
size.height = [[tableView window] maxSize].height;
|
||||
[[tableView window] setMaxSize:size];
|
||||
if (runningOnLionOrNewer()) { // move the + and - button title one pixel up
|
||||
NSMutableParagraphStyle *style= [[NSMutableParagraphStyle alloc] init];
|
||||
[style setAlignment:NSTextAlignmentCenter];
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithFloat:1], NSBaselineOffsetAttributeName,
|
||||
style, NSParagraphStyleAttributeName, nil];
|
||||
[addButton setAttributedTitle:
|
||||
[[[NSAttributedString alloc] initWithString:[addButton title] attributes:dict] autorelease]];
|
||||
[deleteButton setAttributedTitle:
|
||||
[[[NSAttributedString alloc] initWithString:[deleteButton title] attributes:dict] autorelease]];
|
||||
}
|
||||
adjustTableHeaderForElCapitan (tableView);
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithFloat:1], NSBaselineOffsetAttributeName,
|
||||
style, NSParagraphStyleAttributeName, nil];
|
||||
[addButton setAttributedTitle:
|
||||
[[NSAttributedString alloc] initWithString:[addButton title] attributes:dict]];
|
||||
[deleteButton setAttributedTitle:
|
||||
[[NSAttributedString alloc] initWithString:[deleteButton title] attributes:dict]];
|
||||
}
|
||||
adjustTableHeaderForElCapitan (tableView);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#define PREF_PANE_EXTENSION @"prefPane"
|
||||
|
||||
|
||||
@interface PreferencesController : NSObject
|
||||
@interface PreferencesController : NSObject <NSToolbarDelegate>
|
||||
{
|
||||
@private
|
||||
IBOutlet NSPanel *prefPanel;
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* PreferencesController.m - Controller for the preferences panel
|
||||
* PreferencesController.m - Controller for the preferences panel
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@
|
|||
#import "NSMutableArray+BinarySearch.h"
|
||||
|
||||
|
||||
#define PREFS_PANEL_TOPLEFT_KEY @"PrefsPanel TopLeft"
|
||||
#define PREFS_PANEL_TOPLEFT_KEY @"PrefsPanel TopLeft"
|
||||
|
||||
|
||||
@implementation NSBundle (OrderInPreferencesPanelToolbar)
|
||||
|
@ -37,8 +37,8 @@
|
|||
|
||||
- (NSComparisonResult) compareOrderInPreferencesPanelToolbarInfoPlistKey:(NSBundle *)bundle
|
||||
{
|
||||
return [[self objectForInfoDictionaryKey:@"OrderInPreferencesPanelToolbar"]
|
||||
compare:[bundle objectForInfoDictionaryKey:@"OrderInPreferencesPanelToolbar"]];
|
||||
return [[self objectForInfoDictionaryKey:@"OrderInPreferencesPanelToolbar"]
|
||||
compare:[bundle objectForInfoDictionaryKey:@"OrderInPreferencesPanelToolbar"]];
|
||||
}
|
||||
|
||||
|
||||
|
@ -53,12 +53,12 @@
|
|||
|
||||
- (void) setupToolbar
|
||||
{
|
||||
NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier:@"PrefsPanelToolbar"] autorelease];
|
||||
[toolbar setAllowsUserCustomization:NO];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setDelegate:self];
|
||||
[prefPanel setToolbar:toolbar];
|
||||
[prefPanel setShowsToolbarButton:YES];
|
||||
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"PrefsPanelToolbar"];
|
||||
[toolbar setAllowsUserCustomization:NO];
|
||||
[toolbar setAutosavesConfiguration:YES];
|
||||
[toolbar setDelegate:self];
|
||||
[prefPanel setToolbar:toolbar];
|
||||
[prefPanel setShowsToolbarButton:YES];
|
||||
if ([prefPaneIdentifiers count] > 0) {
|
||||
[toolbar setSelectedItemIdentifier:[prefPaneIdentifiers objectAtIndex:0]];
|
||||
}
|
||||
|
@ -66,35 +66,35 @@
|
|||
|
||||
|
||||
- (NSToolbarItem *) toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)identifier
|
||||
willBeInsertedIntoToolbar:(BOOL)willBeInserted
|
||||
willBeInsertedIntoToolbar:(BOOL)willBeInserted
|
||||
{
|
||||
NSToolbarItem *toolbarItem =
|
||||
[[[NSToolbarItem alloc] initWithItemIdentifier:identifier] autorelease];
|
||||
NSBundle *bundle = [NSBundle bundleWithIdentifier:identifier];
|
||||
[toolbarItem setLabel:[bundle objectForInfoDictionaryKey:@"NSPrefPaneIconLabel"]];
|
||||
[toolbarItem setImage:[[[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:
|
||||
[bundle objectForInfoDictionaryKey:@"NSPrefPaneIconFile"] ofType:nil]] autorelease]];
|
||||
[toolbarItem setTarget:self];
|
||||
[toolbarItem setAction:@selector(selectPreferencePane:)];
|
||||
return toolbarItem;
|
||||
NSToolbarItem *toolbarItem =
|
||||
[[NSToolbarItem alloc] initWithItemIdentifier:identifier];
|
||||
NSBundle *bundle = [NSBundle bundleWithIdentifier:identifier];
|
||||
[toolbarItem setLabel:[bundle objectForInfoDictionaryKey:@"NSPrefPaneIconLabel"]];
|
||||
[toolbarItem setImage:[[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:
|
||||
[bundle objectForInfoDictionaryKey:@"NSPrefPaneIconFile"] ofType:nil]]];
|
||||
[toolbarItem setTarget:self];
|
||||
[toolbarItem setAction:@selector(selectPreferencePane:)];
|
||||
return toolbarItem;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return prefPaneIdentifiers;
|
||||
return prefPaneIdentifiers;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return prefPaneIdentifiers;
|
||||
return prefPaneIdentifiers;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
|
||||
{
|
||||
return prefPaneIdentifiers;
|
||||
return prefPaneIdentifiers;
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,39 +103,39 @@
|
|||
|
||||
- (void) findPrefPanesAtPath:(NSString *)path addToArray:(NSMutableArray *)array
|
||||
{
|
||||
NSString *bundleName;
|
||||
NSBundle *bundle;
|
||||
|
||||
NSDirectoryEnumerator *bundlePathEnum = [[NSFileManager defaultManager] enumeratorAtPath:path];
|
||||
while ((bundleName = [bundlePathEnum nextObject])) {
|
||||
if ([[bundleName pathExtension] isEqualToString:PREF_PANE_EXTENSION]) {
|
||||
[bundlePathEnum skipDescendents];
|
||||
bundle = [NSBundle bundleWithPath:[path stringByAppendingPathComponent:bundleName]];
|
||||
if (bundle)
|
||||
[array addObject:bundle toArraySortedBy:
|
||||
@selector(compareOrderInPreferencesPanelToolbarInfoPlistKey:)
|
||||
replaceExistingObject:YES];
|
||||
}
|
||||
}
|
||||
NSString *bundleName;
|
||||
NSBundle *bundle;
|
||||
|
||||
NSDirectoryEnumerator *bundlePathEnum = [[NSFileManager defaultManager] enumeratorAtPath:path];
|
||||
while ((bundleName = [bundlePathEnum nextObject])) {
|
||||
if ([[bundleName pathExtension] isEqualToString:PREF_PANE_EXTENSION]) {
|
||||
[bundlePathEnum skipDescendents];
|
||||
bundle = [NSBundle bundleWithPath:[path stringByAppendingPathComponent:bundleName]];
|
||||
if (bundle)
|
||||
[array addObject:bundle toArraySortedBy:
|
||||
@selector(compareOrderInPreferencesPanelToolbarInfoPlistKey:)
|
||||
replaceExistingObject:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) findPrefPanes
|
||||
{
|
||||
NSEnumerator *enumerator;
|
||||
NSBundle *bundle;
|
||||
|
||||
NSMutableArray *prefPaneBundles = [NSMutableArray array];
|
||||
[self findPrefPanesAtPath:[[NSBundle mainBundle] sharedSupportPath] addToArray:prefPaneBundles];
|
||||
[self findPrefPanesAtPath:[[NSBundle mainBundle] builtInPlugInsPath] addToArray:prefPaneBundles];
|
||||
NSMutableArray *prefPaneIdents = [NSMutableArray array];
|
||||
enumerator = [prefPaneBundles objectEnumerator];
|
||||
NSEnumerator *enumerator;
|
||||
NSBundle *bundle;
|
||||
|
||||
NSMutableArray *prefPaneBundles = [NSMutableArray array];
|
||||
[self findPrefPanesAtPath:[[NSBundle mainBundle] sharedSupportPath] addToArray:prefPaneBundles];
|
||||
[self findPrefPanesAtPath:[[NSBundle mainBundle] builtInPlugInsPath] addToArray:prefPaneBundles];
|
||||
NSMutableArray *prefPaneIdents = [NSMutableArray array];
|
||||
enumerator = [prefPaneBundles objectEnumerator];
|
||||
while ((bundle = [enumerator nextObject])) {
|
||||
if ([bundle bundleIdentifier] != nil) {
|
||||
[prefPaneIdents addObject:[bundle bundleIdentifier]];
|
||||
}
|
||||
}
|
||||
return prefPaneIdents;
|
||||
return prefPaneIdents;
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,91 +144,90 @@
|
|||
|
||||
- (void) resizeWindowForContentView:(NSView *)view
|
||||
{
|
||||
NSRect windowFrame =
|
||||
[NSPanel contentRectForFrameRect:[prefPanel frame] styleMask:[prefPanel styleMask]];
|
||||
float newWindowHeight = NSHeight([view frame]);
|
||||
if ([[prefPanel toolbar] isVisible])
|
||||
newWindowHeight += NSHeight(windowFrame) - NSHeight([[prefPanel contentView] frame]);
|
||||
NSRect newWindowFrame = [NSPanel frameRectForContentRect:
|
||||
NSMakeRect(NSMinX(windowFrame), NSMaxY(windowFrame) - newWindowHeight,
|
||||
NSWidth(windowFrame), newWindowHeight) styleMask:[prefPanel styleMask]];
|
||||
[prefPanel setFrame:newWindowFrame display:YES animate:[prefPanel isVisible]];
|
||||
NSRect windowFrame =
|
||||
[NSPanel contentRectForFrameRect:[prefPanel frame] styleMask:[prefPanel styleMask]];
|
||||
float newWindowHeight = NSHeight([view frame]);
|
||||
if ([[prefPanel toolbar] isVisible])
|
||||
newWindowHeight += NSHeight(windowFrame) - NSHeight([[prefPanel contentView] frame]);
|
||||
NSRect newWindowFrame = [NSPanel frameRectForContentRect:
|
||||
NSMakeRect(NSMinX(windowFrame), NSMaxY(windowFrame) - newWindowHeight,
|
||||
NSWidth(windowFrame), newWindowHeight) styleMask:[prefPanel styleMask]];
|
||||
[prefPanel setFrame:newWindowFrame display:YES animate:[prefPanel isVisible]];
|
||||
}
|
||||
|
||||
|
||||
- (void) selectPreferencePaneWithIdentifier:(NSString *)identifier
|
||||
{
|
||||
if (currentPrefPane) {
|
||||
if ([currentPrefPane shouldUnselect] != NSUnselectNow) {
|
||||
NSLog (@"Handle pref pane unwilling to unselect");
|
||||
return;
|
||||
}
|
||||
[currentPrefPane willUnselect];
|
||||
[[currentPrefPane mainView] removeFromSuperview];
|
||||
[currentPrefPane didUnselect];
|
||||
[currentPrefPane release];
|
||||
currentPrefPane = nil;
|
||||
}
|
||||
NSBundle *prefBundle = [NSBundle bundleWithIdentifier:identifier];
|
||||
currentPrefPane = [[[prefBundle principalClass] alloc] initWithBundle:prefBundle];
|
||||
if ([currentPrefPane loadMainView]) {
|
||||
[currentPrefPane willSelect];
|
||||
[self resizeWindowForContentView:[currentPrefPane mainView]];
|
||||
[prefPanel setContentView:[currentPrefPane mainView]];
|
||||
[prefPanel setTitle:[prefBundle objectForInfoDictionaryKey:@"PrefPaneWindowTitle"]];
|
||||
[currentPrefPane didSelect];
|
||||
[prefPanel setInitialFirstResponder:[currentPrefPane initialKeyView]];
|
||||
} else
|
||||
NSLog (@"Pref pane loadMainView failed");
|
||||
if (currentPrefPane) {
|
||||
if ([currentPrefPane shouldUnselect] != NSUnselectNow) {
|
||||
NSLog (@"Handle pref pane unwilling to unselect");
|
||||
return;
|
||||
}
|
||||
[currentPrefPane willUnselect];
|
||||
[[currentPrefPane mainView] removeFromSuperview];
|
||||
[currentPrefPane didUnselect];
|
||||
currentPrefPane = nil;
|
||||
}
|
||||
NSBundle *prefBundle = [NSBundle bundleWithIdentifier:identifier];
|
||||
currentPrefPane = [[[prefBundle principalClass] alloc] initWithBundle:prefBundle];
|
||||
if ([currentPrefPane loadMainView]) {
|
||||
[currentPrefPane willSelect];
|
||||
[self resizeWindowForContentView:[currentPrefPane mainView]];
|
||||
[prefPanel setContentView:[currentPrefPane mainView]];
|
||||
[prefPanel setTitle:[prefBundle objectForInfoDictionaryKey:@"PrefPaneWindowTitle"]];
|
||||
[currentPrefPane didSelect];
|
||||
[prefPanel setInitialFirstResponder:[currentPrefPane initialKeyView]];
|
||||
} else
|
||||
NSLog (@"Pref pane loadMainView failed");
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) selectPreferencePane:(id)sender
|
||||
{
|
||||
[[prefPanel toolbar] setSelectedItemIdentifier:[sender itemIdentifier]];
|
||||
[self selectPreferencePaneWithIdentifier:[sender itemIdentifier]];
|
||||
[[prefPanel toolbar] setSelectedItemIdentifier:[sender itemIdentifier]];
|
||||
[self selectPreferencePaneWithIdentifier:[sender itemIdentifier]];
|
||||
}
|
||||
|
||||
|
||||
- (void) windowWillClose:(NSNotification *)notification
|
||||
{
|
||||
[currentPrefPane willUnselect];
|
||||
[currentPrefPane didUnselect];
|
||||
[currentPrefPane willUnselect];
|
||||
[currentPrefPane didUnselect];
|
||||
}
|
||||
|
||||
|
||||
- (void) windowDidMove:(NSNotification *)notificatin
|
||||
{
|
||||
/* because of the panel resizing, we can't use the auto frame save feature */
|
||||
NSRect frame = [prefPanel frame];
|
||||
NSPoint topLeft = frame.origin; // bottom left
|
||||
topLeft.y += NSHeight(frame); // top left
|
||||
[[NSUserDefaults standardUserDefaults] setObject:
|
||||
[NSString stringWithFormat:@"%f %f", topLeft.x, topLeft.y] forKey:PREFS_PANEL_TOPLEFT_KEY];
|
||||
/* because of the panel resizing, we can't use the auto frame save feature */
|
||||
NSRect frame = [prefPanel frame];
|
||||
NSPoint topLeft = frame.origin; // bottom left
|
||||
topLeft.y += NSHeight(frame); // top left
|
||||
[[NSUserDefaults standardUserDefaults] setObject:
|
||||
[NSString stringWithFormat:@"%f %f", topLeft.x, topLeft.y] forKey:PREFS_PANEL_TOPLEFT_KEY];
|
||||
}
|
||||
|
||||
|
||||
- (void) windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
if (prefPaneIdentifiers == nil) { // initialization
|
||||
prefPaneIdentifiers = [[self findPrefPanes] retain];
|
||||
[self setupToolbar];
|
||||
}
|
||||
if (currentPrefPane == nil) {
|
||||
if (prefPaneIdentifiers == nil) { // initialization
|
||||
prefPaneIdentifiers = [self findPrefPanes];
|
||||
[self setupToolbar];
|
||||
}
|
||||
if (currentPrefPane == nil) {
|
||||
if ([prefPaneIdentifiers count] > 0) {
|
||||
[self selectPreferencePaneWithIdentifier:[prefPaneIdentifiers objectAtIndex:0]];
|
||||
}
|
||||
NSString *str = [[NSUserDefaults standardUserDefaults] objectForKey:PREFS_PANEL_TOPLEFT_KEY];
|
||||
if (str) { // restore old panel position
|
||||
NSScanner *scanner = [NSScanner scannerWithString:str];
|
||||
NSPoint topLeft;
|
||||
if ([scanner scanFloat:(float *)(&topLeft.x)] && [scanner scanFloat:(float *)(&topLeft.y)])
|
||||
[prefPanel setFrameTopLeftPoint:topLeft];
|
||||
else
|
||||
[prefPanel center];
|
||||
} else
|
||||
[prefPanel center];
|
||||
}
|
||||
NSString *str = [[NSUserDefaults standardUserDefaults] objectForKey:PREFS_PANEL_TOPLEFT_KEY];
|
||||
if (str) { // restore old panel position
|
||||
NSScanner *scanner = [NSScanner scannerWithString:str];
|
||||
NSPoint topLeft;
|
||||
if ([scanner scanFloat:(float *)(&topLeft.x)] && [scanner scanFloat:(float *)(&topLeft.y)])
|
||||
[prefPanel setFrameTopLeftPoint:topLeft];
|
||||
else
|
||||
[prefPanel center];
|
||||
} else
|
||||
[prefPanel center];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* HelpMenuManager.m - Manager for Help menu items of plugins
|
||||
* HelpMenuManager.m - Manager for Help menu items of plugins
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -34,43 +34,43 @@
|
|||
|
||||
+ (HelpMenuManager *) sharedHelpMenuManager
|
||||
{
|
||||
static HelpMenuManager *sharedHelpMenuManager;
|
||||
static HelpMenuManager *sharedHelpMenuManager;
|
||||
|
||||
if (! sharedHelpMenuManager)
|
||||
sharedHelpMenuManager = [[self alloc] init];
|
||||
return sharedHelpMenuManager;
|
||||
if (! sharedHelpMenuManager)
|
||||
sharedHelpMenuManager = [[self alloc] init];
|
||||
return sharedHelpMenuManager;
|
||||
}
|
||||
|
||||
|
||||
- (HelpMenuManager *) init
|
||||
{
|
||||
self = [super init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
registeredHelpBookDomains = [[NSMutableArray alloc] initWithCapacity:10];
|
||||
return self;
|
||||
self = [super init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
registeredHelpBookDomains = [[NSMutableArray alloc] initWithCapacity:10];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void) unregisterHelpBookForDomain:(NSString *)domain
|
||||
// see http://lists.apple.com/archives/carbon-development/2003/Nov/msg00090.html
|
||||
{
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:
|
||||
[defaults persistentDomainForName:@"com.apple.help"]];
|
||||
[dict removeObjectForKey:domain];
|
||||
[defaults setPersistentDomain:dict forName:@"com.apple.help"];
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:
|
||||
[defaults persistentDomainForName:@"com.apple.help"]];
|
||||
[dict removeObjectForKey:domain];
|
||||
[defaults setPersistentDomain:dict forName:@"com.apple.help"];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
NSString *domain;
|
||||
|
||||
NSEnumerator *enumerator = [registeredHelpBookDomains objectEnumerator];
|
||||
while ((domain = [enumerator nextObject]))
|
||||
[self unregisterHelpBookForDomain:domain];
|
||||
NSString *domain;
|
||||
|
||||
NSEnumerator *enumerator = [registeredHelpBookDomains objectEnumerator];
|
||||
while ((domain = [enumerator nextObject]))
|
||||
[self unregisterHelpBookForDomain:domain];
|
||||
}
|
||||
|
||||
|
||||
|
@ -79,88 +79,88 @@
|
|||
// for Lion and Mountain Lion, the ID is the title of the help book
|
||||
// for Mavericks, the ID is the bundle identifier of the plugin containing the help book
|
||||
{
|
||||
NSArray *array;
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary *dict = [defaults persistentDomainForName:@"com.apple.help"];
|
||||
|
||||
dict = [dict valueForKey:@"RegisteredBooks"];
|
||||
NSEnumerator *enumerator = [dict objectEnumerator];
|
||||
while ((array = [enumerator nextObject])) {
|
||||
dict = [array objectAtIndex:0];
|
||||
if ([id isEqualToString:[dict objectForKey:@"id"]])
|
||||
return [NSString stringWithFormat:@"%@index.html", [dict objectForKey:@"url"]];
|
||||
}
|
||||
return nil;
|
||||
NSArray *array;
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary *dict = [defaults persistentDomainForName:@"com.apple.help"];
|
||||
|
||||
dict = [dict valueForKey:@"RegisteredBooks"];
|
||||
NSEnumerator *enumerator = [dict objectEnumerator];
|
||||
while ((array = [enumerator nextObject])) {
|
||||
dict = [array objectAtIndex:0];
|
||||
if ([id isEqualToString:[dict objectForKey:@"id"]])
|
||||
return [NSString stringWithFormat:@"file://%@/index.html", [dict objectForKey:@"url"]];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (void) openHelpUrl:(NSString *)url
|
||||
// open the HelpViewer.app via AppleScript with the "handle URL" command (Lion only)
|
||||
{
|
||||
NSString *source = [NSString stringWithFormat:
|
||||
@"tell app \"HelpViewer\"\nactivate\nhandle URL \"%@\"\nend tell", url];
|
||||
NSAppleScript *script = [[[NSAppleScript alloc] initWithSource:source] autorelease];
|
||||
NSDictionary *error = nil;
|
||||
[script executeAndReturnError:&error];
|
||||
if (error)
|
||||
NSLog (@"AppleScript error while opening HelpViewer: %@", error);
|
||||
NSString *source = [NSString stringWithFormat:
|
||||
@"tell app \"HelpViewer\"\nactivate\nhandle URL \"%@\"\nend tell", url];
|
||||
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:source];
|
||||
NSDictionary *error = nil;
|
||||
[script executeAndReturnError:&error];
|
||||
if (error)
|
||||
NSLog (@"AppleScript error while opening HelpViewer: %@", error);
|
||||
}
|
||||
|
||||
|
||||
- (void) showHelp:(id)sender
|
||||
{
|
||||
NSString *title = [sender title];
|
||||
NSString *title = [sender title];
|
||||
|
||||
if (runningOnLionOrNewer())
|
||||
// Help book lookup does not work as before, don't know why.
|
||||
// We now use AppleScript to open HelpViewer with the URL of the help page.
|
||||
[self openHelpUrl:[self helpUrlForId:(runningOnMavericksOrNewer() ?
|
||||
[sender representedObject] : title)]];
|
||||
else
|
||||
AHGotoPage ((__bridge CFStringRef)title, NULL, NULL);
|
||||
if (runningOnLionOrNewer())
|
||||
// Help book lookup does not work as before, don't know why.
|
||||
// We now use AppleScript to open HelpViewer with the URL of the help page.
|
||||
[self openHelpUrl:[self helpUrlForId:(runningOnMavericksOrNewer() ?
|
||||
[sender representedObject] : title)]];
|
||||
else
|
||||
AHGotoPage ((__bridge CFStringRef)title, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
- (void) addHelpMenuItem:(NSString *)title id:(NSString *)id
|
||||
{
|
||||
NSMenu *helpMenu = [[[NSApp mainMenu] itemWithTitle:NSLocalizedString(@"Help", @"")] submenu];
|
||||
NSInteger n = [helpMenu numberOfItems];
|
||||
NSInteger i;
|
||||
for (i = 1; i < n; i++) {
|
||||
switch ([[[helpMenu itemAtIndex:i] title] compare:title]) {
|
||||
case NSOrderedSame :
|
||||
n = -1;
|
||||
break;
|
||||
case NSOrderedDescending :
|
||||
n = i;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
NSMenuItem *item = [helpMenu insertItemWithTitle:title action:@selector(showHelp:)
|
||||
keyEquivalent:@"" atIndex:n];
|
||||
[item setTarget:self];
|
||||
[item setRepresentedObject:id];
|
||||
}
|
||||
NSMenu *helpMenu = [[[NSApp mainMenu] itemWithTitle:NSLocalizedString(@"Help", @"")] submenu];
|
||||
NSInteger n = [helpMenu numberOfItems];
|
||||
NSInteger i;
|
||||
for (i = 1; i < n; i++) {
|
||||
switch ([[[helpMenu itemAtIndex:i] title] compare:title]) {
|
||||
case NSOrderedSame :
|
||||
n = -1;
|
||||
break;
|
||||
case NSOrderedDescending :
|
||||
n = i;
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (n > 0) {
|
||||
NSMenuItem *item = [helpMenu insertItemWithTitle:title action:@selector(showHelp:)
|
||||
keyEquivalent:@"" atIndex:n];
|
||||
[item setTarget:self];
|
||||
[item setRepresentedObject:id];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) addBundleHelp:(NSBundle *)bundle
|
||||
{
|
||||
CFURLRef urlRef;
|
||||
|
||||
if ([[NSFileManager defaultManager] urlRef:&urlRef forPath:[bundle bundlePath]]) {
|
||||
[self unregisterHelpBookForDomain:[bundle bundleIdentifier]];
|
||||
if (AHRegisterHelpBookWithURL(urlRef) == noErr) {
|
||||
[registeredHelpBookDomains addObject:[bundle bundleIdentifier]];
|
||||
NSString *bookTitle = [[bundle infoDictionary] objectForKey:@"CFBundleHelpBookName"];
|
||||
if (bookTitle)
|
||||
[self addHelpMenuItem:bookTitle id:[bundle bundleIdentifier]];
|
||||
}
|
||||
}
|
||||
CFURLRef urlRef;
|
||||
|
||||
if ([[NSFileManager defaultManager] urlRef:&urlRef forPath:[bundle bundlePath]]) {
|
||||
[self unregisterHelpBookForDomain:[bundle bundleIdentifier]];
|
||||
if (AHRegisterHelpBookWithURL(urlRef) == noErr) {
|
||||
[registeredHelpBookDomains addObject:[bundle bundleIdentifier]];
|
||||
NSString *bookTitle = [[bundle infoDictionary] objectForKey:@"CFBundleHelpBookName"];
|
||||
if (bookTitle)
|
||||
[self addHelpMenuItem:bookTitle id:[bundle bundleIdentifier]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@
|
|||
NSBundle *bundle;
|
||||
@protected
|
||||
PDP8 *pdp8;
|
||||
NSArray *topLevelObjects;
|
||||
|
||||
}
|
||||
|
||||
- (void) setPDP8:(PDP8 *)p8; // gives the plugin a pointer to the global PDP-8 object
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* PluginAPI.m - Plugin API Definitions for PDP-8/E I/O Device Plugins
|
||||
* PluginAPI.m - Plugin API Definitions for PDP-8/E I/O Device Plugins
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -31,81 +31,81 @@
|
|||
@implementation PDP8Plugin
|
||||
|
||||
|
||||
PDP8 *pdp8; // plugin local pdp8 variable for the IOT functions
|
||||
PDP8 *pdp8; // plugin local pdp8 variable for the IOT functions
|
||||
|
||||
//NSArray *topLevelObjects;
|
||||
NSArray *topLevelObjects;
|
||||
|
||||
static void setPDP8 (PDP8 *p8)
|
||||
{
|
||||
pdp8 = p8; // set the plugin local pdp8 variable for the IOT function
|
||||
pdp8 = p8; // set the plugin local pdp8 variable for the IOT function
|
||||
}
|
||||
|
||||
|
||||
- (void) setPDP8:(PDP8 *)p8
|
||||
{
|
||||
pdp8 = p8; // set the class variable pdp8
|
||||
setPDP8 (p8);
|
||||
pdp8 = p8; // set the class variable pdp8
|
||||
setPDP8 (p8);
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) apiVersion
|
||||
{
|
||||
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd
|
||||
[[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd
|
||||
object:self
|
||||
file:[NSString stringWithCString:__FILE__
|
||||
encoding: NSUTF8StringEncoding]
|
||||
lineNumber:__LINE__
|
||||
description:NSLocalizedString(@"Your plugin must override the apiVersion method using the API_VERSION macro.", @"")];
|
||||
return CURRENT_PLUGIN_API_VERSION;
|
||||
return CURRENT_PLUGIN_API_VERSION;
|
||||
}
|
||||
|
||||
|
||||
- (NSBundle *) bundle
|
||||
{
|
||||
return bundle;
|
||||
return bundle;
|
||||
}
|
||||
|
||||
|
||||
- (void) setBundle:(NSBundle *)bndl
|
||||
{
|
||||
bundle = bndl;
|
||||
bundle = bndl;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) pluginName
|
||||
{
|
||||
return [[bundle bundlePath] lastPathComponent];
|
||||
return [[bundle bundlePath] lastPathComponent];
|
||||
}
|
||||
|
||||
|
||||
- (void *) pluginPointer
|
||||
{
|
||||
return (void *) self;
|
||||
return (__bridge void *) self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) ioInformationPlistName
|
||||
{
|
||||
return DEFAULT_IO_INFO_FILENAME;
|
||||
return DEFAULT_IO_INFO_FILENAME;
|
||||
}
|
||||
|
||||
|
||||
- (NSDictionary *) ioInformation
|
||||
{
|
||||
return [NSDictionary dictionaryWithContentsOfFile:
|
||||
[bundle pathForResource:[self ioInformationPlistName] ofType:@"plist"]];
|
||||
return [NSDictionary dictionaryWithContentsOfFile:
|
||||
[bundle pathForResource:[self ioInformationPlistName] ofType:@"plist"]];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) iotsForAddress:(int)ioAddress
|
||||
{
|
||||
return nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) skiptestsForAddress:(int)ioAddress
|
||||
{
|
||||
return nil;
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,23 +116,22 @@ static void setPDP8 (PDP8 *p8)
|
|||
|
||||
- (void) loadNibs
|
||||
{
|
||||
NSString *resourceName;
|
||||
NSString *resourceName;
|
||||
NSBundle *thisBundle;
|
||||
|
||||
|
||||
thisBundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *resourcePath = [thisBundle resourcePath];
|
||||
NSDirectoryEnumerator *resourcePathEnum =
|
||||
[[NSFileManager defaultManager] enumeratorAtPath:resourcePath];
|
||||
while (resourcePathEnum && (resourceName = [resourcePathEnum nextObject])) {
|
||||
NSString *resourcePath = [thisBundle resourcePath];
|
||||
NSDirectoryEnumerator *resourcePathEnum =
|
||||
[[NSFileManager defaultManager] enumeratorAtPath:resourcePath];
|
||||
while (resourcePathEnum && (resourceName = [resourcePathEnum nextObject])) {
|
||||
if ([[resourceName pathExtension] isEqualToString:@"nib"]) {
|
||||
[NSBundle loadNibNamed:[resourceName lastPathComponent] owner:self];
|
||||
// topLevelObjects = [[NSArray alloc] init];
|
||||
// NSString *name = [[resourceName lastPathComponent] stringByDeletingPathExtension];
|
||||
// if (![bundle loadNibNamed:name owner:self topLevelObjects:&topLevelObjects]) {
|
||||
// NSLog(@"Failed to load NIB %@", name);
|
||||
// }
|
||||
NSArray *objects = [[NSArray alloc] init];
|
||||
NSString *name = [[resourceName lastPathComponent] stringByDeletingPathExtension];
|
||||
if ([thisBundle loadNibNamed:name owner:self topLevelObjects:&objects]) {
|
||||
topLevelObjects = [NSArray arrayWithArray:objects];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
|
||||
- (void) noLoadAlertWithMessage:(NSString *)message okText:(NSString *)okText
|
||||
{
|
||||
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.messageText = okText;
|
||||
alert.informativeText = message;
|
||||
[alert runModal];
|
||||
|
@ -104,7 +104,7 @@
|
|||
[[OctalFormatter formatterWithBitMask:077 wildcardAllowed:NO] getObjectValue:&number
|
||||
forString:ioAddress errorDescription:nil];
|
||||
int addr = [number intValue];
|
||||
[pdp8 setPluginPointer:plugin forIOAddress:addr];
|
||||
[pdp8 setPluginPointer:(__bridge void *)(plugin) forIOAddress:addr];
|
||||
NSArray *iots = [plugin iotsForAddress:addr];
|
||||
if (iots) {
|
||||
NSArray *skiptests = [plugin skiptestsForAddress:addr];
|
||||
|
@ -192,7 +192,6 @@
|
|||
[plugin pluginDidLoad];
|
||||
[[HelpMenuManager sharedHelpMenuManager] addBundleHelp:bundle];
|
||||
} else {
|
||||
[plugin release];
|
||||
// unload is a 10.5 method (does nothing on 10.4), but we use the 10.4 SDK
|
||||
// so use performSelector: to avoid unknown message warning
|
||||
[bundle performSelector:@selector(unload)];
|
||||
|
@ -208,7 +207,7 @@
|
|||
NSLocalizedString(@"Cannot determine the principal class of the plug-in.", @"")
|
||||
okText:[self noLoadMessage:[[bundle bundlePath] lastPathComponent]]];
|
||||
}
|
||||
return [plugin autorelease];
|
||||
return plugin;
|
||||
}
|
||||
|
||||
|
||||
|
@ -254,7 +253,7 @@
|
|||
|
||||
- (void) notifyApplicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
pluginInstances = [[self loadAllPlugins] retain];
|
||||
pluginInstances = [self loadAllPlugins];
|
||||
}
|
||||
|
||||
|
||||
|
|
694
RK8E/RK05.m
694
RK8E/RK05.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* RK05.m - Class implementing a RK05 DECpack drive
|
||||
* RK05.m - Class implementing a RK05 DECpack drive
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -38,473 +38,473 @@
|
|||
|
||||
|
||||
/* "commands" for a RK05 drive to be performed asynchroniously, bit coded in self.cmd */
|
||||
#define RK05_RECALIBRATE 0400
|
||||
#define RK05_SET_CRC_STATE 0200
|
||||
#define RK05_DELAY 0100
|
||||
#define RK05_SEEK 0040
|
||||
#define RK05_FLUSH_CYL 0020
|
||||
#define RK05_READ_CYL 0010
|
||||
#define RK05_INPUT_BLOCK 0004
|
||||
#define RK05_OUTPUT_BLOCK 0002
|
||||
#define RK05_RAISE_FLAG 0001
|
||||
#define RK05_RECALIBRATE 0400
|
||||
#define RK05_SET_CRC_STATE 0200
|
||||
#define RK05_DELAY 0100
|
||||
#define RK05_SEEK 0040
|
||||
#define RK05_FLUSH_CYL 0020
|
||||
#define RK05_READ_CYL 0010
|
||||
#define RK05_INPUT_BLOCK 0004
|
||||
#define RK05_OUTPUT_BLOCK 0002
|
||||
#define RK05_RAISE_FLAG 0001
|
||||
|
||||
#define NO_COMMANDS_AVAILABLE 0
|
||||
#define COMMANDS_AVAILABLE 1
|
||||
#define NO_COMMANDS_AVAILABLE 0
|
||||
#define COMMANDS_AVAILABLE 1
|
||||
|
||||
|
||||
- (int) driveNumber
|
||||
{
|
||||
return driveNumber;
|
||||
return driveNumber;
|
||||
}
|
||||
|
||||
|
||||
- (void) setDriveNumber:(short)drvNum
|
||||
{
|
||||
driveNumber = drvNum;
|
||||
driveNumber = drvNum;
|
||||
}
|
||||
|
||||
|
||||
- (void) setPDP8:(PDP8 *)p8
|
||||
{
|
||||
pdp8 = p8;
|
||||
pdp8 = p8;
|
||||
}
|
||||
|
||||
|
||||
- (void) setWriteProtected:(BOOL)writeProtected
|
||||
{
|
||||
locked = writeProtected;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:WRITEPROTECT_CHANGED_NOTIFICATION
|
||||
object:self];
|
||||
locked = writeProtected;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:WRITEPROTECT_CHANGED_NOTIFICATION
|
||||
object:self];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isWriteProtected
|
||||
{
|
||||
return locked;
|
||||
return locked;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) flush
|
||||
{
|
||||
BOOL error = NO;
|
||||
if (decpack && dirty) {
|
||||
if (fseek(decpack, cyl * RK05_BUFSIZE, SEEK_SET) < 0)
|
||||
error = YES;
|
||||
else if (fwrite(buffer, 1, RK05_BUFSIZE, decpack) != RK05_BUFSIZE)
|
||||
error = YES;
|
||||
dirty = NO;
|
||||
}
|
||||
return error;
|
||||
BOOL error = NO;
|
||||
if (decpack && dirty) {
|
||||
if (fseek(decpack, cyl * RK05_BUFSIZE, SEEK_SET) < 0)
|
||||
error = YES;
|
||||
else if (fwrite(buffer, 1, RK05_BUFSIZE, decpack) != RK05_BUFSIZE)
|
||||
error = YES;
|
||||
dirty = NO;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) canMount:(NSString *)path
|
||||
{
|
||||
NSAssert (decpack == NULL, @"A DECpack is already mounted");
|
||||
FILE *handle = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "r+");
|
||||
if (handle) {
|
||||
if (flock(fileno(handle), LOCK_EX | LOCK_NB)) {
|
||||
fclose (handle);
|
||||
return NO;
|
||||
}
|
||||
flock (fileno(handle), LOCK_UN);
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
NSAssert (decpack == NULL, @"A DECpack is already mounted");
|
||||
FILE *handle = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "r+");
|
||||
if (handle) {
|
||||
if (flock(fileno(handle), LOCK_EX | LOCK_NB)) {
|
||||
fclose (handle);
|
||||
return NO;
|
||||
}
|
||||
flock (fileno(handle), LOCK_UN);
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (int) mount:(NSString *)path create:(BOOL)create
|
||||
{
|
||||
NSAssert (decpack == NULL, @"A DECpack is already mounted");
|
||||
int err = 0;
|
||||
decpack = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], create ? "w+" : "r+");
|
||||
if (decpack) {
|
||||
if (flock(fileno(decpack), LOCK_EX | LOCK_NB)) {
|
||||
fclose (decpack);
|
||||
decpack = NULL;
|
||||
err = -2;
|
||||
}
|
||||
} else
|
||||
err = -1;
|
||||
cyl = -1;
|
||||
dirty = NO;
|
||||
memset (crcstate, 0, sizeof(crcstate));
|
||||
[rk8e updateStatusMountFlags];
|
||||
return err;
|
||||
NSAssert (decpack == NULL, @"A DECpack is already mounted");
|
||||
int err = 0;
|
||||
decpack = fopen([path cStringUsingEncoding:NSUTF8StringEncoding], create ? "w+" : "r+");
|
||||
if (decpack) {
|
||||
if (flock(fileno(decpack), LOCK_EX | LOCK_NB)) {
|
||||
fclose (decpack);
|
||||
decpack = NULL;
|
||||
err = -2;
|
||||
}
|
||||
} else
|
||||
err = -1;
|
||||
cyl = -1;
|
||||
dirty = NO;
|
||||
memset (crcstate, 0, sizeof(crcstate));
|
||||
[rk8e updateStatusMountFlags];
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) unmount
|
||||
{
|
||||
NSAssert (decpack != NULL, @"Cannot unmount without mounted DECpack");
|
||||
BOOL error = [self flush];
|
||||
flock (fileno(decpack), LOCK_UN);
|
||||
fclose (decpack);
|
||||
decpack = NULL;
|
||||
[rk8e updateStatusMountFlags];
|
||||
return error;
|
||||
NSAssert (decpack != NULL, @"Cannot unmount without mounted DECpack");
|
||||
BOOL error = [self flush];
|
||||
flock (fileno(decpack), LOCK_UN);
|
||||
fclose (decpack);
|
||||
decpack = NULL;
|
||||
[rk8e updateStatusMountFlags];
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isMounted
|
||||
{
|
||||
return decpack != NULL;
|
||||
return decpack != NULL;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isBusy
|
||||
{
|
||||
return cmd != 0;
|
||||
return cmd != 0;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isCalibrating
|
||||
{
|
||||
return (cmd & RK05_RECALIBRATE) ? YES : NO;
|
||||
return (cmd & RK05_RECALIBRATE) ? YES : NO;
|
||||
}
|
||||
|
||||
|
||||
- (void) stopCalibrating
|
||||
{
|
||||
cmd &= ~RK05_RECALIBRATE;
|
||||
cmd &= ~RK05_RECALIBRATE;
|
||||
}
|
||||
|
||||
|
||||
- (void) abortAllCommands
|
||||
{
|
||||
cmd = 0;
|
||||
cmd = 0;
|
||||
}
|
||||
|
||||
|
||||
- (void) setStatusAndAbortAllCommands
|
||||
{
|
||||
if (cmd) {
|
||||
unsigned short set = 0;
|
||||
if (cmd & RK05_RECALIBRATE)
|
||||
set |= STATUS_CONTROL_BUSY;
|
||||
else
|
||||
set |= (STATUS_DONE | STATUS_ERROR);
|
||||
if (cmd & RK05_SEEK)
|
||||
set |= STATUS_HEAD_IN_MOTION;
|
||||
cmd = 0;
|
||||
[rk8e setStatusBits:set clearStatusBits:0];
|
||||
}
|
||||
if (cmd) {
|
||||
unsigned short set = 0;
|
||||
if (cmd & RK05_RECALIBRATE)
|
||||
set |= STATUS_CONTROL_BUSY;
|
||||
else
|
||||
set |= (STATUS_DONE | STATUS_ERROR);
|
||||
if (cmd & RK05_SEEK)
|
||||
set |= STATUS_HEAD_IN_MOTION;
|
||||
cmd = 0;
|
||||
[rk8e setStatusBits:set clearStatusBits:0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) setRecalibrating
|
||||
{
|
||||
durationMicroSeconds = 85000; // 85 ms == 200 track movement
|
||||
cmd |= RK05_RECALIBRATE | RK05_DELAY;
|
||||
durationMicroSeconds = 85000; // 85 ms == 200 track movement
|
||||
cmd |= RK05_RECALIBRATE | RK05_DELAY;
|
||||
}
|
||||
|
||||
|
||||
- (void) setFlushCylinder
|
||||
{
|
||||
if (dirty)
|
||||
cmd |= RK05_FLUSH_CYL;
|
||||
if (dirty)
|
||||
cmd |= RK05_FLUSH_CYL;
|
||||
}
|
||||
|
||||
|
||||
- (void) setReadCylinder:(unsigned short)cylinder
|
||||
{
|
||||
if (cyl != cylinder) {
|
||||
newcyl = cylinder;
|
||||
cmd |= RK05_READ_CYL;
|
||||
}
|
||||
if (cyl != cylinder) {
|
||||
newcyl = cylinder;
|
||||
cmd |= RK05_READ_CYL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) setRaiseFlag
|
||||
{
|
||||
cmd |= RK05_RAISE_FLAG;
|
||||
cmd |= RK05_RAISE_FLAG;
|
||||
}
|
||||
|
||||
|
||||
- (void) clearRaiseFlag
|
||||
{
|
||||
cmd &= ~RK05_RAISE_FLAG;
|
||||
cmd &= ~RK05_RAISE_FLAG;
|
||||
}
|
||||
|
||||
|
||||
- (void) setRead:(BOOL)read write:(BOOL)write all:(BOOL)all newBlock:(unsigned short)newBlock
|
||||
{
|
||||
long d;
|
||||
long d;
|
||||
|
||||
if (write && locked) {
|
||||
[rk8e setStatusBits:STATUS_WRITE_LOCK_ERROR | STATUS_ERROR clearStatusBits:0];
|
||||
return;
|
||||
}
|
||||
if (newBlock > 014537) {
|
||||
[rk8e setStatusBits:STATUS_DONE | STATUS_ERROR clearStatusBits:0];
|
||||
return;
|
||||
}
|
||||
if (! read && ! write && [self isMounted]) { // seek only
|
||||
/* set on DISK ADDRESS ACKNOWLAGE; it is set again
|
||||
on seek complete when command bit 4 is on */
|
||||
[rk8e setStatusBits:STATUS_DONE clearStatusBits:0];
|
||||
cmd |= RK05_SEEK;
|
||||
}
|
||||
if (cyl != (newBlock >> 5)) {
|
||||
if (dirty)
|
||||
cmd |= RK05_FLUSH_CYL;
|
||||
newcyl = newBlock >> 5;
|
||||
cmd |= RK05_READ_CYL;
|
||||
d = newcyl - cyl;
|
||||
if (d < 0)
|
||||
d = -d;
|
||||
d = 9621l + 379l * d;
|
||||
/* 9.621 ms for seek start/stop, 0.379 ms per track */
|
||||
} else if (read || write) {
|
||||
d = ((long) (newBlock & 017)) - ((long) (blk & 017));
|
||||
if (d < 0)
|
||||
d += 16;
|
||||
/* d == # sectors between the last accessed sector and the new sector */
|
||||
if (d <= 1) { /* correctly, this must be "if (d == 1)", but
|
||||
MAINDEC-08-DHRKB-E-PB test 28 (consecutive sector read all test)
|
||||
seems to have a little bug: it starts with WRITE ALL sector 36,
|
||||
then READ ALL sector 0 (two sectors distance) and often fails
|
||||
immediately with Transfer Done not set. The test should start
|
||||
with sector 37. */
|
||||
if (all) { /* read or write ALL can read consecutive sectors */
|
||||
d = 1;
|
||||
} else { /* normal read can't read consecutive sectors */
|
||||
if (d == 1)
|
||||
d = 16;
|
||||
}
|
||||
}
|
||||
d *= 2500; /* 2.5 ms per sector, 40 ms per revolution */
|
||||
} else
|
||||
d = 0;
|
||||
durationMicroSeconds = d;
|
||||
cmd |= RK05_DELAY;
|
||||
blk = newBlock; /* DMAN may destroy rk8e.block */
|
||||
if (read)
|
||||
cmd |= RK05_INPUT_BLOCK | RK05_RAISE_FLAG;
|
||||
if (write)
|
||||
cmd |= RK05_OUTPUT_BLOCK | RK05_RAISE_FLAG;
|
||||
if (write && locked) {
|
||||
[rk8e setStatusBits:STATUS_WRITE_LOCK_ERROR | STATUS_ERROR clearStatusBits:0];
|
||||
return;
|
||||
}
|
||||
if (newBlock > 014537) {
|
||||
[rk8e setStatusBits:STATUS_DONE | STATUS_ERROR clearStatusBits:0];
|
||||
return;
|
||||
}
|
||||
if (! read && ! write && [self isMounted]) { // seek only
|
||||
/* set on DISK ADDRESS ACKNOWLAGE; it is set again
|
||||
on seek complete when command bit 4 is on */
|
||||
[rk8e setStatusBits:STATUS_DONE clearStatusBits:0];
|
||||
cmd |= RK05_SEEK;
|
||||
}
|
||||
if (cyl != (newBlock >> 5)) {
|
||||
if (dirty)
|
||||
cmd |= RK05_FLUSH_CYL;
|
||||
newcyl = newBlock >> 5;
|
||||
cmd |= RK05_READ_CYL;
|
||||
d = newcyl - cyl;
|
||||
if (d < 0)
|
||||
d = -d;
|
||||
d = 9621l + 379l * d;
|
||||
/* 9.621 ms for seek start/stop, 0.379 ms per track */
|
||||
} else if (read || write) {
|
||||
d = ((long) (newBlock & 017)) - ((long) (blk & 017));
|
||||
if (d < 0)
|
||||
d += 16;
|
||||
/* d == # sectors between the last accessed sector and the new sector */
|
||||
if (d <= 1) { /* correctly, this must be "if (d == 1)", but
|
||||
MAINDEC-08-DHRKB-E-PB test 28 (consecutive sector read all test)
|
||||
seems to have a little bug: it starts with WRITE ALL sector 36,
|
||||
then READ ALL sector 0 (two sectors distance) and often fails
|
||||
immediately with Transfer Done not set. The test should start
|
||||
with sector 37. */
|
||||
if (all) { /* read or write ALL can read consecutive sectors */
|
||||
d = 1;
|
||||
} else { /* normal read can't read consecutive sectors */
|
||||
if (d == 1)
|
||||
d = 16;
|
||||
}
|
||||
}
|
||||
d *= 2500; /* 2.5 ms per sector, 40 ms per revolution */
|
||||
} else
|
||||
d = 0;
|
||||
durationMicroSeconds = d;
|
||||
cmd |= RK05_DELAY;
|
||||
blk = newBlock; /* DMAN may destroy rk8e.block */
|
||||
if (read)
|
||||
cmd |= RK05_INPUT_BLOCK | RK05_RAISE_FLAG;
|
||||
if (write)
|
||||
cmd |= RK05_OUTPUT_BLOCK | RK05_RAISE_FLAG;
|
||||
}
|
||||
|
||||
|
||||
- (void) start
|
||||
{
|
||||
NSDate *delayUntil = [[NSDate alloc] initWithTimeIntervalSinceNow:0.005]; // 5 ms
|
||||
startAtMachAbsolute = mach_absolute_time();
|
||||
if ([commandsLock lockWhenCondition:NO_COMMANDS_AVAILABLE beforeDate:delayUntil]) {
|
||||
[commandsLock unlockWithCondition:COMMANDS_AVAILABLE];
|
||||
}
|
||||
[delayUntil release]; // don't use autorelease, this floods the PDP-8 run thread autorelease pool
|
||||
NSDate *delayUntil = [[NSDate alloc] initWithTimeIntervalSinceNow:0.005]; // 5 ms
|
||||
startAtMachAbsolute = mach_absolute_time();
|
||||
if ([commandsLock lockWhenCondition:NO_COMMANDS_AVAILABLE beforeDate:delayUntil]) {
|
||||
[commandsLock unlockWithCondition:COMMANDS_AVAILABLE];
|
||||
}
|
||||
// don't use autorelease, this floods the PDP-8 run thread autorelease pool
|
||||
}
|
||||
|
||||
|
||||
static ushort CRC (const unsigned char *p) /* CRC with polygon x^16 + x^15 + x^2 + 1 */
|
||||
static ushort CRC (const unsigned char *p) /* CRC with polygon x^16 + x^15 + x^2 + 1 */
|
||||
{
|
||||
register short i, j;
|
||||
register unsigned long data;
|
||||
register ushort crc;
|
||||
register short i, j;
|
||||
register unsigned long data;
|
||||
register ushort crc;
|
||||
|
||||
crc = i = 0;
|
||||
while (i < 384) {
|
||||
data = p[i++] << 4;
|
||||
data |= p[i] >> 4;
|
||||
data |= p[i++] << 20;
|
||||
data |= p[i++] << 12;
|
||||
for (j = 0; j < 24; j++) {
|
||||
if ((data ^ crc) & 0x1)
|
||||
crc = (crc >> 1) ^ 0xa001;
|
||||
else
|
||||
crc >>= 1;
|
||||
data >>= 1;
|
||||
}
|
||||
}
|
||||
return (crc);
|
||||
crc = i = 0;
|
||||
while (i < 384) {
|
||||
data = p[i++] << 4;
|
||||
data |= p[i] >> 4;
|
||||
data |= p[i++] << 20;
|
||||
data |= p[i++] << 12;
|
||||
for (j = 0; j < 24; j++) {
|
||||
if ((data ^ crc) & 0x1)
|
||||
crc = (crc >> 1) ^ 0xa001;
|
||||
else
|
||||
crc >>= 1;
|
||||
data >>= 1;
|
||||
}
|
||||
}
|
||||
return (crc);
|
||||
}
|
||||
|
||||
|
||||
- (void) processCommand
|
||||
{
|
||||
register ushort *field;
|
||||
register unsigned char *bp;
|
||||
register ushort i;
|
||||
register ushort words;
|
||||
unsigned short rk8eBlock;
|
||||
unsigned short rk8eCommand;
|
||||
unsigned short clear, set;
|
||||
register ushort *field;
|
||||
register unsigned char *bp;
|
||||
register ushort i;
|
||||
register ushort words;
|
||||
unsigned short rk8eBlock;
|
||||
unsigned short rk8eCommand;
|
||||
unsigned short clear, set;
|
||||
|
||||
/* after processing a command, return, so that the next call can process higher priority
|
||||
commands that may have been added in the meantime by the RK8-E control */
|
||||
if (cmd & RK05_FLUSH_CYL) {
|
||||
[rk8e lockControl];
|
||||
cmd &= ~RK05_FLUSH_CYL;
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber])
|
||||
[rk8e setStatusBits:STATUS_HEAD_IN_MOTION clearStatusBits:0];
|
||||
cmd |= RK05_SEEK;
|
||||
if (fseek(decpack, cyl * RK05_BUFSIZE, SEEK_SET) < 0)
|
||||
[rk8e setStatusBits:STATUS_SEEK_FAILED clearStatusBits:0];
|
||||
else if (fwrite(buffer, 1, RK05_BUFSIZE, decpack) != RK05_BUFSIZE)
|
||||
[rk8e setStatusBits:STATUS_ERROR clearStatusBits:0];
|
||||
else
|
||||
dirty = 0;
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_READ_CYL) {
|
||||
[rk8e lockControl];
|
||||
cmd &= ~RK05_READ_CYL;
|
||||
if (cyl != newcyl) {
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber])
|
||||
[rk8e setStatusBits:STATUS_HEAD_IN_MOTION clearStatusBits:0];
|
||||
cmd |= RK05_SEEK;
|
||||
cyl = newcyl;
|
||||
if (fseek(decpack, 0, SEEK_END) < 0)
|
||||
[rk8e setStatusBits:STATUS_SEEK_FAILED clearStatusBits:0];
|
||||
else if (ftell(decpack) < (cyl + 1) * RK05_BUFSIZE)
|
||||
bzero (buffer, RK05_BUFSIZE);
|
||||
else if (fseek(decpack, cyl * RK05_BUFSIZE, SEEK_SET) < 0)
|
||||
[rk8e setStatusBits:STATUS_SEEK_FAILED clearStatusBits:0];
|
||||
else if (fread(buffer, 1, RK05_BUFSIZE, decpack) != RK05_BUFSIZE)
|
||||
[rk8e setStatusBits:STATUS_ERROR clearStatusBits:0];
|
||||
}
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_INPUT_BLOCK) {
|
||||
[rk8e lockControl];
|
||||
if (! [rk8e isCRCOK])
|
||||
[rk8e setStatusBits:STATUS_CYLINDER_ADDRESS_ERROR clearStatusBits:0];
|
||||
/* after processing a command, return, so that the next call can process higher priority
|
||||
commands that may have been added in the meantime by the RK8-E control */
|
||||
if (cmd & RK05_FLUSH_CYL) {
|
||||
[rk8e lockControl];
|
||||
cmd &= ~RK05_FLUSH_CYL;
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber])
|
||||
[rk8e setStatusBits:STATUS_HEAD_IN_MOTION clearStatusBits:0];
|
||||
cmd |= RK05_SEEK;
|
||||
if (fseek(decpack, cyl * RK05_BUFSIZE, SEEK_SET) < 0)
|
||||
[rk8e setStatusBits:STATUS_SEEK_FAILED clearStatusBits:0];
|
||||
else if (fwrite(buffer, 1, RK05_BUFSIZE, decpack) != RK05_BUFSIZE)
|
||||
[rk8e setStatusBits:STATUS_ERROR clearStatusBits:0];
|
||||
else
|
||||
dirty = 0;
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_READ_CYL) {
|
||||
[rk8e lockControl];
|
||||
cmd &= ~RK05_READ_CYL;
|
||||
if (cyl != newcyl) {
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber])
|
||||
[rk8e setStatusBits:STATUS_HEAD_IN_MOTION clearStatusBits:0];
|
||||
cmd |= RK05_SEEK;
|
||||
cyl = newcyl;
|
||||
if (fseek(decpack, 0, SEEK_END) < 0)
|
||||
[rk8e setStatusBits:STATUS_SEEK_FAILED clearStatusBits:0];
|
||||
else if (ftell(decpack) < (cyl + 1) * RK05_BUFSIZE)
|
||||
bzero (buffer, RK05_BUFSIZE);
|
||||
else if (fseek(decpack, cyl * RK05_BUFSIZE, SEEK_SET) < 0)
|
||||
[rk8e setStatusBits:STATUS_SEEK_FAILED clearStatusBits:0];
|
||||
else if (fread(buffer, 1, RK05_BUFSIZE, decpack) != RK05_BUFSIZE)
|
||||
[rk8e setStatusBits:STATUS_ERROR clearStatusBits:0];
|
||||
}
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_INPUT_BLOCK) {
|
||||
[rk8e lockControl];
|
||||
if (! [rk8e isCRCOK])
|
||||
[rk8e setStatusBits:STATUS_CYLINDER_ADDRESS_ERROR clearStatusBits:0];
|
||||
/*
|
||||
* Read a sector from the RK8E disk file. The file packing scheme:
|
||||
* <- 8 bits->
|
||||
* +---------+ 0H => High order of pdp8 word 0
|
||||
* | 0H | 0L => Low order of pdp8 word 0
|
||||
* +----+----+ 1H => High order of pdp8 word 1
|
||||
* | 0L | 1H | 1L => Low order of pdp8 word 1
|
||||
* +----+----+
|
||||
* | 1L | In other words, pdp8 words are written
|
||||
* +----+----+ in bit order (high to low).
|
||||
* Read a sector from the RK8E disk file. The file packing scheme:
|
||||
* <- 8 bits->
|
||||
* +---------+ 0H => High order of pdp8 word 0
|
||||
* | 0H | 0L => Low order of pdp8 word 0
|
||||
* +----+----+ 1H => High order of pdp8 word 1
|
||||
* | 0L | 1H | 1L => Low order of pdp8 word 1
|
||||
* +----+----+
|
||||
* | 1L | In other words, pdp8 words are written
|
||||
* +----+----+ in bit order (high to low).
|
||||
*/
|
||||
rk8eBlock = [rk8e getBlockNumber];
|
||||
bp = buffer + (rk8eBlock & 037) * 384;
|
||||
[rk8e setCRC:CRC(bp)];
|
||||
rk8eCommand = [rk8e getCommand];
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 64 : 128; /* half of words to transfer */
|
||||
field = [pdp8 directMemoryAccess] + ((rk8eCommand & 070) << 9);
|
||||
i = [rk8e getCurrentAddress];
|
||||
if (field < [pdp8 directMemoryAccess] + [pdp8 memorySize]) {
|
||||
while (words--) { /* two words per loop */
|
||||
field[i & 07777] = *bp++ << 4;
|
||||
field[i++ & 07777] |= *bp >> 4;
|
||||
field[i & 07777] = (*bp++ & 017) << 8;
|
||||
field[i++ & 07777] |= *bp++;
|
||||
}
|
||||
[pdp8 directMemoryWriteFinished];
|
||||
}
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 128 : 256;
|
||||
[rk8e setCurrentAddress:([rk8e getCurrentAddress] + words) & 07777];
|
||||
cmd &= ~RK05_INPUT_BLOCK;
|
||||
if (crcstate[rk8eBlock >> 3] & (1 << (rk8eBlock & 7)))
|
||||
[rk8e setStatusBits:STATUS_CRC_ERROR clearStatusBits:0];
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_OUTPUT_BLOCK) {
|
||||
[rk8e lockControl];
|
||||
if (! [rk8e isCRCOK])
|
||||
[rk8e setStatusBits:STATUS_CYLINDER_ADDRESS_ERROR clearStatusBits:0];
|
||||
rk8eBlock = [rk8e getBlockNumber];
|
||||
bp = (unsigned char *) buffer + (rk8eBlock & 037) * 384;
|
||||
rk8eCommand = [rk8e getCommand];
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 64 : 128; /* half of words to transfer */
|
||||
field = [pdp8 directMemoryAccess] + ((rk8eCommand & 070) << 9);
|
||||
i = [rk8e getCurrentAddress];
|
||||
while (words--) { /* two words per loop */
|
||||
*bp++ = field[i & 07777] >> 4;
|
||||
*bp = field[i++ & 07777] << 4;
|
||||
*bp++ |= field[i & 07777] >> 8;
|
||||
*bp++ = field[i++ & 07777];
|
||||
}
|
||||
if (rk8eCommand & COMMAND_HALF_BLOCK) {
|
||||
for (i = 0; i < 192; i++)
|
||||
*bp++ = 0;
|
||||
}
|
||||
[rk8e setCRC:CRC(bp - 384)];
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 128 : 256;
|
||||
[rk8e setCurrentAddress:([rk8e getCurrentAddress] + words) & 07777];
|
||||
dirty = true;
|
||||
cmd &= ~RK05_OUTPUT_BLOCK;
|
||||
cmd |= RK05_SET_CRC_STATE;
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_DELAY) {
|
||||
// don't lock the control
|
||||
cmd &= ~RK05_DELAY;
|
||||
int speed = [pdp8 getGoSpeed];
|
||||
if (speed != GO_AS_FAST_AS_POSSIBLE) {
|
||||
uint64_t delayUntilAbsolute = startAtMachAbsolute +
|
||||
nanoseconds2absolute(durationMicroSeconds * 1000ll);
|
||||
if (speed == GO_WITH_PDP8_SPEED)
|
||||
mach_wait_until (delayUntilAbsolute);
|
||||
else {
|
||||
while (mach_absolute_time() < delayUntilAbsolute)
|
||||
;
|
||||
}
|
||||
}
|
||||
// don't unlock the control
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_SET_CRC_STATE) {
|
||||
[rk8e lockControl];
|
||||
cmd &= ~RK05_SET_CRC_STATE;
|
||||
words = 1 << (blk & 7);
|
||||
if ([rk8e isCRCOK])
|
||||
crcstate[blk >> 3] &= ~words;
|
||||
else
|
||||
crcstate[blk >> 3] |= words;
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & (RK05_RECALIBRATE | RK05_SEEK | RK05_RAISE_FLAG)) {
|
||||
[rk8e lockControl];
|
||||
set = clear = 0;
|
||||
if (cmd & RK05_RAISE_FLAG) {
|
||||
set = STATUS_DONE;
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber])
|
||||
clear |= STATUS_HEAD_IN_MOTION;
|
||||
if (! [rk8e isCRCOK])
|
||||
set |= STATUS_CYLINDER_ADDRESS_ERROR;
|
||||
}
|
||||
if (cmd & (RK05_RECALIBRATE | RK05_SEEK)) {
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber]) {
|
||||
if ([rk8e getCommand] & COMMAND_SET_DONE_ON_SEEK_DONE)
|
||||
set = STATUS_DONE;
|
||||
clear = STATUS_HEAD_IN_MOTION;
|
||||
}
|
||||
}
|
||||
[rk8e setStatusBits:set clearStatusBits:clear];
|
||||
cmd &= ~(RK05_RAISE_FLAG | RK05_RECALIBRATE | RK05_SEEK);
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
rk8eBlock = [rk8e getBlockNumber];
|
||||
bp = buffer + (rk8eBlock & 037) * 384;
|
||||
[rk8e setCRC:CRC(bp)];
|
||||
rk8eCommand = [rk8e getCommand];
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 64 : 128; /* half of words to transfer */
|
||||
field = [pdp8 directMemoryAccess] + ((rk8eCommand & 070) << 9);
|
||||
i = [rk8e getCurrentAddress];
|
||||
if (field < [pdp8 directMemoryAccess] + [pdp8 memorySize]) {
|
||||
while (words--) { /* two words per loop */
|
||||
field[i & 07777] = *bp++ << 4;
|
||||
field[i++ & 07777] |= *bp >> 4;
|
||||
field[i & 07777] = (*bp++ & 017) << 8;
|
||||
field[i++ & 07777] |= *bp++;
|
||||
}
|
||||
[pdp8 directMemoryWriteFinished];
|
||||
}
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 128 : 256;
|
||||
[rk8e setCurrentAddress:([rk8e getCurrentAddress] + words) & 07777];
|
||||
cmd &= ~RK05_INPUT_BLOCK;
|
||||
if (crcstate[rk8eBlock >> 3] & (1 << (rk8eBlock & 7)))
|
||||
[rk8e setStatusBits:STATUS_CRC_ERROR clearStatusBits:0];
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_OUTPUT_BLOCK) {
|
||||
[rk8e lockControl];
|
||||
if (! [rk8e isCRCOK])
|
||||
[rk8e setStatusBits:STATUS_CYLINDER_ADDRESS_ERROR clearStatusBits:0];
|
||||
rk8eBlock = [rk8e getBlockNumber];
|
||||
bp = (unsigned char *) buffer + (rk8eBlock & 037) * 384;
|
||||
rk8eCommand = [rk8e getCommand];
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 64 : 128; /* half of words to transfer */
|
||||
field = [pdp8 directMemoryAccess] + ((rk8eCommand & 070) << 9);
|
||||
i = [rk8e getCurrentAddress];
|
||||
while (words--) { /* two words per loop */
|
||||
*bp++ = field[i & 07777] >> 4;
|
||||
*bp = field[i++ & 07777] << 4;
|
||||
*bp++ |= field[i & 07777] >> 8;
|
||||
*bp++ = field[i++ & 07777];
|
||||
}
|
||||
if (rk8eCommand & COMMAND_HALF_BLOCK) {
|
||||
for (i = 0; i < 192; i++)
|
||||
*bp++ = 0;
|
||||
}
|
||||
[rk8e setCRC:CRC(bp - 384)];
|
||||
words = (rk8eCommand & COMMAND_HALF_BLOCK) ? 128 : 256;
|
||||
[rk8e setCurrentAddress:([rk8e getCurrentAddress] + words) & 07777];
|
||||
dirty = true;
|
||||
cmd &= ~RK05_OUTPUT_BLOCK;
|
||||
cmd |= RK05_SET_CRC_STATE;
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_DELAY) {
|
||||
// don't lock the control
|
||||
cmd &= ~RK05_DELAY;
|
||||
int speed = [pdp8 getGoSpeed];
|
||||
if (speed != GO_AS_FAST_AS_POSSIBLE) {
|
||||
uint64_t delayUntilAbsolute = startAtMachAbsolute +
|
||||
nanoseconds2absolute(durationMicroSeconds * 1000ll);
|
||||
if (speed == GO_WITH_PDP8_SPEED)
|
||||
mach_wait_until (delayUntilAbsolute);
|
||||
else {
|
||||
while (mach_absolute_time() < delayUntilAbsolute)
|
||||
;
|
||||
}
|
||||
}
|
||||
// don't unlock the control
|
||||
return;
|
||||
}
|
||||
if (cmd & RK05_SET_CRC_STATE) {
|
||||
[rk8e lockControl];
|
||||
cmd &= ~RK05_SET_CRC_STATE;
|
||||
words = 1 << (blk & 7);
|
||||
if ([rk8e isCRCOK])
|
||||
crcstate[blk >> 3] &= ~words;
|
||||
else
|
||||
crcstate[blk >> 3] |= words;
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
if (cmd & (RK05_RECALIBRATE | RK05_SEEK | RK05_RAISE_FLAG)) {
|
||||
[rk8e lockControl];
|
||||
set = clear = 0;
|
||||
if (cmd & RK05_RAISE_FLAG) {
|
||||
set = STATUS_DONE;
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber])
|
||||
clear |= STATUS_HEAD_IN_MOTION;
|
||||
if (! [rk8e isCRCOK])
|
||||
set |= STATUS_CYLINDER_ADDRESS_ERROR;
|
||||
}
|
||||
if (cmd & (RK05_RECALIBRATE | RK05_SEEK)) {
|
||||
if (driveNumber == [rk8e getCurrentDriveNumber]) {
|
||||
if ([rk8e getCommand] & COMMAND_SET_DONE_ON_SEEK_DONE)
|
||||
set = STATUS_DONE;
|
||||
clear = STATUS_HEAD_IN_MOTION;
|
||||
}
|
||||
}
|
||||
[rk8e setStatusBits:set clearStatusBits:clear];
|
||||
cmd &= ~(RK05_RAISE_FLAG | RK05_RECALIBRATE | RK05_SEEK);
|
||||
[rk8e unlockControl];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) rk05Thread:(id)object
|
||||
{
|
||||
for (;;) {
|
||||
[commandsLock lockWhenCondition:COMMANDS_AVAILABLE];
|
||||
while (cmd)
|
||||
[self processCommand];
|
||||
[commandsLock unlockWithCondition:NO_COMMANDS_AVAILABLE];
|
||||
}
|
||||
for (;;) {
|
||||
[commandsLock lockWhenCondition:COMMANDS_AVAILABLE];
|
||||
while (cmd)
|
||||
[self processCommand];
|
||||
[commandsLock unlockWithCondition:NO_COMMANDS_AVAILABLE];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
commandsLock = [[NSConditionLock alloc] initWithCondition:NO_COMMANDS_AVAILABLE];
|
||||
[NSThread detachNewThreadSelector:@selector(rk05Thread:) toTarget:self withObject:nil];
|
||||
commandsLock = [[NSConditionLock alloc] initWithCondition:NO_COMMANDS_AVAILABLE];
|
||||
[NSThread detachNewThreadSelector:@selector(rk05Thread:) toTarget:self withObject:nil];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -36,5 +36,6 @@
|
|||
|
||||
- (IBAction) mountUnmountClicked:(id)sender;
|
||||
- (IBAction) writeProtectClicked:(id)sender;
|
||||
- (void) loadCoder:(NSCoder *)coder;
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* RK05Controller.m - Controller for RK05 view
|
||||
* RK05Controller.m - Controller for RK05 view
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -34,12 +34,12 @@
|
|||
#import "RK05.h"
|
||||
|
||||
|
||||
#define DECPACK_HFS_TYPE_CODE 0x524b3845l // 'RK8E', for compatibility with the old simulator
|
||||
#define DECPACK_EXTENSION_RK05 @"rk05"
|
||||
#define DECPACK_EXTENSION_DECPACK @"decpack"
|
||||
#define DECPACK_HFS_TYPE_CODE 0x524b3845l // 'RK8E', for compatibility with the old simulator
|
||||
#define DECPACK_EXTENSION_RK05 @"rk05"
|
||||
#define DECPACK_EXTENSION_DECPACK @"decpack"
|
||||
|
||||
#define CODER_KEY_RK05_PATH_FMT @"rk05path%d"
|
||||
#define CODER_KEY_RK05_LOCK_FMT @"rk05lock%d"
|
||||
#define CODER_KEY_RK05_PATH_FMT @"rk05path%d"
|
||||
#define CODER_KEY_RK05_LOCK_FMT @"rk05lock%d"
|
||||
|
||||
|
||||
@implementation RK05Controller
|
||||
|
@ -47,95 +47,92 @@
|
|||
|
||||
- (IBAction) writeProtectClicked:(id)sender
|
||||
{
|
||||
[rk05 setWriteProtected:[sender intValue]];
|
||||
[rk05 setWriteProtected:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyWriteProtectChanged:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"RK05Controller notifyWriteProtectChanged");
|
||||
[writeProtectCheckbox setIntValue:[rk05 isWriteProtected]];
|
||||
// NSLog (@"RK05Controller notifyWriteProtectChanged");
|
||||
[writeProtectCheckbox setIntValue:[rk05 isWriteProtected]];
|
||||
}
|
||||
|
||||
|
||||
- (void) updateMountButton:(NSString *)path
|
||||
{
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
if (path) {
|
||||
decpackPath = [path retain];
|
||||
[filenameField setStringValue:[[NSFileManager defaultManager] displayNameAtPath:path]];
|
||||
[filenameField setHidden:NO];
|
||||
[mountUnmountButton setTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"Unmount", nil, bundle, @"")];
|
||||
[mountUnmountButton unregisterAsFileDropTarget];
|
||||
} else {
|
||||
[mountUnmountButton setTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"Mount", nil, bundle, @"")];
|
||||
[mountUnmountButton registerAsFileDropTarget];
|
||||
[filenameField setHidden:YES];
|
||||
[decpackPath release];
|
||||
decpackPath = nil;
|
||||
}
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
if (path) {
|
||||
decpackPath = path;
|
||||
[filenameField setStringValue:[[NSFileManager defaultManager] displayNameAtPath:path]];
|
||||
[filenameField setHidden:NO];
|
||||
[mountUnmountButton setTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"Unmount", nil, bundle, @"")];
|
||||
[mountUnmountButton unregisterAsFileDropTarget];
|
||||
} else {
|
||||
[mountUnmountButton setTitle:
|
||||
NSLocalizedStringFromTableInBundle(@"Mount", nil, bundle, @"")];
|
||||
[mountUnmountButton registerAsFileDropTarget];
|
||||
[filenameField setHidden:YES];
|
||||
decpackPath = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) mount:(NSString *)path create:(BOOL)create
|
||||
{
|
||||
int err = [rk05 mount:path create:create];
|
||||
if (err) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:err == -1 ?
|
||||
(create ?
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot create this DECpack.", nil, bundle, @"") :
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot mount this DECpack, maybe it is write protected.",
|
||||
nil, bundle, @"")) :
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"This DECpack is already mounted to another RK05 drive.", nil, bundle, @"")
|
||||
];
|
||||
[alert setInformativeText:path];
|
||||
[alert beginSheetModalForWindow:[mountUnmountButton window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
[alert release];
|
||||
} else
|
||||
[self updateMountButton:path];
|
||||
return err == 0;
|
||||
int err = [rk05 mount:path create:create];
|
||||
if (err) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:err == -1 ?
|
||||
(create ?
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot create this DECpack.", nil, bundle, @"") :
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot mount this DECpack, maybe it is write protected.",
|
||||
nil, bundle, @"")) :
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"This DECpack is already mounted to another RK05 drive.", nil, bundle, @"")
|
||||
];
|
||||
[alert setInformativeText:path];
|
||||
[alert beginSheetModalForWindow:[mountUnmountButton window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
} else
|
||||
[self updateMountButton:path];
|
||||
return err == 0;
|
||||
}
|
||||
|
||||
|
||||
- (void) panelDidEnd:(NSSavePanel *)panel result:(NSModalResponse)result
|
||||
{
|
||||
if (result == NSModalResponseOK) {
|
||||
[panel close];
|
||||
[self mount:[[panel URL] path] create:[panel isMemberOfClass:[NSSavePanel class]]];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
if (result == NSModalResponseOK) {
|
||||
[panel close];
|
||||
[self mount:[[panel URL] path] create:[panel isMemberOfClass:[NSSavePanel class]]];
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) openFileTypes
|
||||
{
|
||||
return [NSArray arrayWithObjects:DECPACK_EXTENSION_RK05, DECPACK_EXTENSION_DECPACK,
|
||||
NSFileTypeForHFSTypeCode(DECPACK_HFS_TYPE_CODE), nil];
|
||||
return [NSArray arrayWithObjects:DECPACK_EXTENSION_RK05, DECPACK_EXTENSION_DECPACK,
|
||||
NSFileTypeForHFSTypeCode(DECPACK_HFS_TYPE_CODE), nil];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) mountUnmountClicked:(id)sender
|
||||
{
|
||||
if ([rk05 isMounted]) {
|
||||
if ([rk05 unmount]) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedStringFromTableInBundle(
|
||||
@"An error occured while closing the DECpack. "
|
||||
"The data on that DECpack might be corrupt.", nil,
|
||||
[NSBundle bundleForClass:[self class]], @"")];
|
||||
[alert setInformativeText:[filenameField stringValue]];
|
||||
[alert beginSheetModalForWindow:[mountUnmountButton window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
[alert release];
|
||||
}
|
||||
[self updateMountButton:nil];
|
||||
} else {
|
||||
if ([rk05 isMounted]) {
|
||||
if ([rk05 unmount]) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:NSLocalizedStringFromTableInBundle(
|
||||
@"An error occured while closing the DECpack. "
|
||||
"The data on that DECpack might be corrupt.", nil,
|
||||
[NSBundle bundleForClass:[self class]], @"")];
|
||||
[alert setInformativeText:[filenameField stringValue]];
|
||||
[alert beginSheetModalForWindow:[mountUnmountButton window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
}
|
||||
[self updateMountButton:nil];
|
||||
} else {
|
||||
if ([[NSApp currentEvent] modifierFlags] & NSEventModifierFlagOption) {
|
||||
NSSavePanel *savePanel = [NSSavePanel savePanel];
|
||||
[savePanel setDirectoryURL: [NSURL fileURLWithPath: [[NSUserDefaults standardUserDefaults] stringForKey:LAST_FILE_PANEL_DIR_KEY] isDirectory: YES]];
|
||||
|
@ -154,43 +151,42 @@
|
|||
}];
|
||||
}
|
||||
// [nsUrl autorelease];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) setDecpackPathAndMountAtStartup:(NSString *)path
|
||||
{
|
||||
if (path == nil)
|
||||
return;
|
||||
if ([rk05 mount:path create:NO]) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(
|
||||
@"The following DECpack could not be found. It was mounted on RK05 drive %d. "
|
||||
"Do you want to locate it?", nil, bundle, @""), [rk05 driveNumber]]];
|
||||
[alert setInformativeText:path];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"Yes", nil, bundle, @"")]
|
||||
setKeyEquivalent:@"\r"];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"No", nil, bundle, @"")]
|
||||
setKeyEquivalent:@"\e"];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setTitle:[NSString stringWithFormat:
|
||||
NSLocalizedStringFromTableInBundle(@"Locate the DECpack %C%@%C",
|
||||
nil, bundle, @""),
|
||||
UNICODE_LEFT_DOUBLEQUOTE,
|
||||
[[NSFileManager defaultManager] displayNameAtPath:path],
|
||||
UNICODE_RIGHT_DOUBLEQUOTE]];
|
||||
if (path == nil)
|
||||
return;
|
||||
if ([rk05 mount:path create:NO]) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(
|
||||
@"The following DECpack could not be found. It was mounted on RK05 drive %d. "
|
||||
"Do you want to locate it?", nil, bundle, @""), [rk05 driveNumber]]];
|
||||
[alert setInformativeText:path];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"Yes", nil, bundle, @"")]
|
||||
setKeyEquivalent:@"\r"];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(@"No", nil, bundle, @"")]
|
||||
setKeyEquivalent:@"\e"];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn) {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setTitle:[NSString stringWithFormat:
|
||||
NSLocalizedStringFromTableInBundle(@"Locate the DECpack %C%@%C",
|
||||
nil, bundle, @""),
|
||||
UNICODE_LEFT_DOUBLEQUOTE,
|
||||
[[NSFileManager defaultManager] displayNameAtPath:path],
|
||||
UNICODE_RIGHT_DOUBLEQUOTE]];
|
||||
[panel setDirectoryURL: [NSURL fileURLWithPath:[[NSUserDefaults standardUserDefaults] stringForKey:LAST_FILE_PANEL_DIR_KEY] isDirectory: YES]];
|
||||
[panel setAllowedFileTypes: [self openFileTypes]];
|
||||
if ([panel runModal] == NSModalResponseOK)
|
||||
[self mount:[[panel URL] path] create:NO];
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
}
|
||||
[alert release];
|
||||
} else
|
||||
[self updateMountButton:path];
|
||||
if ([panel runModal] == NSModalResponseOK)
|
||||
[self mount:[[panel URL] path] create:NO];
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
}
|
||||
} else
|
||||
[self updateMountButton:path];
|
||||
}
|
||||
|
||||
|
||||
|
@ -199,19 +195,19 @@
|
|||
|
||||
- (BOOL) willAcceptFile:(NSString *)path
|
||||
{
|
||||
NSString *extension = [path pathExtension];
|
||||
if ([extension isEqualToString:DECPACK_EXTENSION_RK05] ||
|
||||
[extension isEqualToString:DECPACK_EXTENSION_DECPACK] ||
|
||||
[NSHFSTypeOfFile(path) isEqualToString:NSFileTypeForHFSTypeCode(DECPACK_HFS_TYPE_CODE)]) {
|
||||
return [rk05 canMount:path];
|
||||
}
|
||||
return NO;
|
||||
NSString *extension = [path pathExtension];
|
||||
if ([extension isEqualToString:DECPACK_EXTENSION_RK05] ||
|
||||
[extension isEqualToString:DECPACK_EXTENSION_DECPACK] ||
|
||||
[NSHFSTypeOfFile(path) isEqualToString:NSFileTypeForHFSTypeCode(DECPACK_HFS_TYPE_CODE)]) {
|
||||
return [rk05 canMount:path];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) acceptFile:(NSString *)path
|
||||
{
|
||||
return [self mount:path create:NO];
|
||||
return [self mount:path create:NO];
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,35 +216,39 @@
|
|||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyWriteProtectChanged:)
|
||||
name:WRITEPROTECT_CHANGED_NOTIFICATION object:nil];
|
||||
[mountUnmountButton registerAsFileDropTarget];
|
||||
if (runningOnLionOrNewer()) {
|
||||
// Make the textured button a normal push button of the same size, otherwise
|
||||
// the label is not centered vertically and aligned with the "Write Proctect" label
|
||||
NSRect rect = [mountUnmountButton frame];
|
||||
[mountUnmountButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[mountUnmountButton setFrame:NSInsetRect(NSOffsetRect(rect, 0, -1), -5, -2)];
|
||||
}
|
||||
int drive = (int)([mountUnmountButton tag]);
|
||||
[rk05 setDriveNumber:drive];
|
||||
[self setDecpackPathAndMountAtStartup:
|
||||
[coder decodeObjectForKey:[NSString stringWithFormat:CODER_KEY_RK05_PATH_FMT, drive]]];
|
||||
[rk05 setWriteProtected:
|
||||
[coder decodeBoolForKey:[NSString stringWithFormat:CODER_KEY_RK05_LOCK_FMT, drive]]];
|
||||
return self;
|
||||
self = [super init];
|
||||
[self loadCoder:coder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) loadCoder:(NSCoder *)coder
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyWriteProtectChanged:)
|
||||
name:WRITEPROTECT_CHANGED_NOTIFICATION object:nil];
|
||||
[mountUnmountButton registerAsFileDropTarget];
|
||||
if (runningOnLionOrNewer()) {
|
||||
// Make the textured button a normal push button of the same size, otherwise
|
||||
// the label is not centered vertically and aligned with the "Write Proctect" label
|
||||
NSRect rect = [mountUnmountButton frame];
|
||||
[mountUnmountButton setBezelStyle:NSRoundedBezelStyle];
|
||||
[mountUnmountButton setFrame:NSInsetRect(NSOffsetRect(rect, 0, -1), -5, -2)];
|
||||
}
|
||||
int drive = (int)([mountUnmountButton tag]);
|
||||
[rk05 setDriveNumber:drive];
|
||||
[self setDecpackPathAndMountAtStartup:
|
||||
[coder decodeObjectForKey:[NSString stringWithFormat:CODER_KEY_RK05_PATH_FMT, drive]]];
|
||||
[rk05 setWriteProtected:
|
||||
[coder decodeBoolForKey:[NSString stringWithFormat:CODER_KEY_RK05_LOCK_FMT, drive]]];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
int drive = [rk05 driveNumber];
|
||||
[coder encodeObject:decpackPath forKey:
|
||||
[NSString stringWithFormat:CODER_KEY_RK05_PATH_FMT, drive]];
|
||||
[coder encodeBool:[rk05 isWriteProtected] forKey:
|
||||
[NSString stringWithFormat:CODER_KEY_RK05_LOCK_FMT, drive]];
|
||||
[rk05 flush];
|
||||
int drive = [rk05 driveNumber];
|
||||
[coder encodeObject:decpackPath forKey:
|
||||
[NSString stringWithFormat:CODER_KEY_RK05_PATH_FMT, drive]];
|
||||
[coder encodeBool:[rk05 isWriteProtected] forKey:
|
||||
[NSString stringWithFormat:CODER_KEY_RK05_LOCK_FMT, drive]];
|
||||
[rk05 flush];
|
||||
}
|
||||
|
||||
|
||||
|
|
459
RK8E/RK8E.m
459
RK8E/RK8E.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* RK8E.m - RK8-E Disk Cartridge System for the PDP-8/E Simulator
|
||||
* RK8E.m - RK8-E Disk Cartridge System for the PDP-8/E Simulator
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -38,24 +38,24 @@
|
|||
#import "RK05Controller.h"
|
||||
|
||||
|
||||
#define CODER_KEY_COMMAND @"cmd"
|
||||
#define CODER_KEY_STATUS @"status"
|
||||
#define CODER_KEY_BLOCK @"block"
|
||||
#define CODER_KEY_CURADDR @"curaddr"
|
||||
#define CODER_KEY_IOFLAG @"ioflag"
|
||||
#define CODER_KEY_IOMASK @"iomask"
|
||||
#define CODER_KEY_MAINT @"maint"
|
||||
#define CODER_KEY_LDB0 @"ldb0"
|
||||
#define CODER_KEY_LDB1 @"ldb1"
|
||||
#define CODER_KEY_LDB2 @"ldb2"
|
||||
#define CODER_KEY_LDB3 @"ldb3"
|
||||
#define CODER_KEY_LDBFILL @"ldbfill"
|
||||
#define CODER_KEY_UDB @"udb"
|
||||
#define CODER_KEY_CRC @"crc"
|
||||
#define CODER_KEY_CHECKCRC @"checkcrc"
|
||||
#define CODER_KEY_SHIFTS @"shifts"
|
||||
#define CODER_KEY_WORDCOUNT @"wordcount"
|
||||
#define CODER_KEY_SHIFT_ENABLE @"shiftena"
|
||||
#define CODER_KEY_COMMAND @"cmd"
|
||||
#define CODER_KEY_STATUS @"status"
|
||||
#define CODER_KEY_BLOCK @"block"
|
||||
#define CODER_KEY_CURADDR @"curaddr"
|
||||
#define CODER_KEY_IOFLAG @"ioflag"
|
||||
#define CODER_KEY_IOMASK @"iomask"
|
||||
#define CODER_KEY_MAINT @"maint"
|
||||
#define CODER_KEY_LDB0 @"ldb0"
|
||||
#define CODER_KEY_LDB1 @"ldb1"
|
||||
#define CODER_KEY_LDB2 @"ldb2"
|
||||
#define CODER_KEY_LDB3 @"ldb3"
|
||||
#define CODER_KEY_LDBFILL @"ldbfill"
|
||||
#define CODER_KEY_UDB @"udb"
|
||||
#define CODER_KEY_CRC @"crc"
|
||||
#define CODER_KEY_CHECKCRC @"checkcrc"
|
||||
#define CODER_KEY_SHIFTS @"shifts"
|
||||
#define CODER_KEY_WORDCOUNT @"wordcount"
|
||||
#define CODER_KEY_SHIFT_ENABLE @"shiftena"
|
||||
|
||||
|
||||
@implementation RK8E
|
||||
|
@ -69,95 +69,95 @@ API_VERSION
|
|||
|
||||
- (NSArray *) iotsForAddress:(int)ioAddress
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6741],
|
||||
[NSValue valueWithPointer:i6742],
|
||||
[NSValue valueWithPointer:i6743],
|
||||
[NSValue valueWithPointer:i6744],
|
||||
[NSValue valueWithPointer:i6745],
|
||||
[NSValue valueWithPointer:i6746],
|
||||
[NSValue valueWithPointer:i6747],
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:i6741],
|
||||
[NSValue valueWithPointer:i6742],
|
||||
[NSValue valueWithPointer:i6743],
|
||||
[NSValue valueWithPointer:i6744],
|
||||
[NSValue valueWithPointer:i6745],
|
||||
[NSValue valueWithPointer:i6746],
|
||||
[NSValue valueWithPointer:i6747],
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) skiptestsForAddress:(int)ioAddress
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6741],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6741],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) setIOFlag:(unsigned long)flag forIOFlagName:(NSString *)name;
|
||||
{
|
||||
ioflag = flag;
|
||||
ioflag = flag;
|
||||
}
|
||||
|
||||
|
||||
- (void) resetInternalRegisters
|
||||
{
|
||||
maint = NO;
|
||||
ldb[0] = ldb[1] = ldb[2] = ldb[3] = 0;
|
||||
ldbfill = 0;
|
||||
udb = 0;
|
||||
crc = 0;
|
||||
checkcrc = 0;
|
||||
shifts = 0;
|
||||
wordcount = 0;
|
||||
shiftEnabled = NO;
|
||||
maint = NO;
|
||||
ldb[0] = ldb[1] = ldb[2] = ldb[3] = 0;
|
||||
ldbfill = 0;
|
||||
udb = 0;
|
||||
crc = 0;
|
||||
checkcrc = 0;
|
||||
shifts = 0;
|
||||
wordcount = 0;
|
||||
shiftEnabled = NO;
|
||||
}
|
||||
|
||||
|
||||
- (void) CAF:(int)ioAddress
|
||||
{
|
||||
command = 0;
|
||||
block = 0;
|
||||
status = [rk05[0] isMounted] ? 0 : STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
|
||||
curaddr = 0;
|
||||
[self resetInternalRegisters];
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[rk05[0] abortAllCommands];
|
||||
[rk05[1] abortAllCommands];
|
||||
[rk05[2] abortAllCommands];
|
||||
[rk05[3] abortAllCommands];
|
||||
command = 0;
|
||||
block = 0;
|
||||
status = [rk05[0] isMounted] ? 0 : STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
|
||||
curaddr = 0;
|
||||
[self resetInternalRegisters];
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[rk05[0] abortAllCommands];
|
||||
[rk05[1] abortAllCommands];
|
||||
[rk05[2] abortAllCommands];
|
||||
[rk05[3] abortAllCommands];
|
||||
}
|
||||
|
||||
|
||||
- (void) clearAllFlags:(int)ioAddress
|
||||
{
|
||||
[self setCommand:0];
|
||||
[self setBlockNumber:0];
|
||||
[self setStatus:0];
|
||||
[self updateStatusMountFlags];
|
||||
[self setMemoryAddress:0];
|
||||
[self resetInternalRegisters];
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[rk05[0] abortAllCommands];
|
||||
[rk05[1] abortAllCommands];
|
||||
[rk05[2] abortAllCommands];
|
||||
[rk05[3] abortAllCommands];
|
||||
[self setCommand:0];
|
||||
[self setBlockNumber:0];
|
||||
[self setStatus:0];
|
||||
[self updateStatusMountFlags];
|
||||
[self setMemoryAddress:0];
|
||||
[self resetInternalRegisters];
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[rk05[0] abortAllCommands];
|
||||
[rk05[1] abortAllCommands];
|
||||
[rk05[2] abortAllCommands];
|
||||
[rk05[3] abortAllCommands];
|
||||
}
|
||||
|
||||
|
||||
- (void) resetDevice
|
||||
{
|
||||
[self clearAllFlags:0];
|
||||
[rk05[0] setWriteProtected:NO];
|
||||
[rk05[1] setWriteProtected:NO];
|
||||
[rk05[2] setWriteProtected:NO];
|
||||
[rk05[3] setWriteProtected:NO];
|
||||
[self clearAllFlags:0];
|
||||
[rk05[0] setWriteProtected:NO];
|
||||
[rk05[1] setWriteProtected:NO];
|
||||
[rk05[2] setWriteProtected:NO];
|
||||
[rk05[3] setWriteProtected:NO];
|
||||
}
|
||||
|
||||
|
||||
|
@ -166,166 +166,166 @@ API_VERSION
|
|||
|
||||
- (unsigned short) getCommand
|
||||
{
|
||||
return command;
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
- (void) setCommand:(unsigned short)cmd
|
||||
{
|
||||
NSAssert1 ((cmd & ~07777) == 0, @"Bad RK8-E Command: 0%o", cmd);
|
||||
command = cmd;
|
||||
if (command & COMMAND_INTERRUPT_ON_DONE)
|
||||
[pdp8 setInterruptMaskBits:ioflag];
|
||||
else
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[self updateStatusMountFlags];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter postNotificationName:COMMAND_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:MEMORYADDRESS_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:BLOCKNUMBER_CHANGED_NOTIFICATION object:self];
|
||||
NSAssert1 ((cmd & ~07777) == 0, @"Bad RK8-E Command: 0%o", cmd);
|
||||
command = cmd;
|
||||
if (command & COMMAND_INTERRUPT_ON_DONE)
|
||||
[pdp8 setInterruptMaskBits:ioflag];
|
||||
else
|
||||
[pdp8 clearInterruptMaskBits:ioflag];
|
||||
[self updateStatusMountFlags];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter postNotificationName:COMMAND_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:MEMORYADDRESS_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:BLOCKNUMBER_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPDP8IOFlagsChanged:(NSNotification *)notification
|
||||
{
|
||||
//NSLog (@"RK8E notifyPDP8IOFlagsChanged");
|
||||
if ([pdp8 getInterruptMaskBits:ioflag])
|
||||
command |= COMMAND_INTERRUPT_ON_DONE;
|
||||
else
|
||||
command &= ~COMMAND_INTERRUPT_ON_DONE;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:COMMAND_CHANGED_NOTIFICATION object:self];
|
||||
if ([pdp8 getIOFlagBits:ioflag]) {
|
||||
if (! (status & STATUS_RAISE_FLAG_MASK))
|
||||
status |= STATUS_DONE;
|
||||
} else
|
||||
status &= ~STATUS_RAISE_FLAG_MASK;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
//NSLog (@"RK8E notifyPDP8IOFlagsChanged");
|
||||
if ([pdp8 getInterruptMaskBits:ioflag])
|
||||
command |= COMMAND_INTERRUPT_ON_DONE;
|
||||
else
|
||||
command &= ~COMMAND_INTERRUPT_ON_DONE;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:COMMAND_CHANGED_NOTIFICATION object:self];
|
||||
if ([pdp8 getIOFlagBits:ioflag]) {
|
||||
if (! (status & STATUS_RAISE_FLAG_MASK))
|
||||
status |= STATUS_DONE;
|
||||
} else
|
||||
status &= ~STATUS_RAISE_FLAG_MASK;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getStatus
|
||||
{
|
||||
return status;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
- (void) setStatus:(unsigned short)stat
|
||||
{
|
||||
NSAssert1 ((stat & ~07777) == 0, @"Bad RK8-E Status: 0%o", stat);
|
||||
status = stat;
|
||||
if (status & STATUS_RAISE_FLAG_MASK)
|
||||
[pdp8 setIOFlagBits:ioflag];
|
||||
else
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
NSAssert1 ((stat & ~07777) == 0, @"Bad RK8-E Status: 0%o", stat);
|
||||
status = stat;
|
||||
if (status & STATUS_RAISE_FLAG_MASK)
|
||||
[pdp8 setIOFlagBits:ioflag];
|
||||
else
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) updateStatusMountFlags
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
if ([rk05[(command >> 1) & 3] isMounted])
|
||||
status &= ~(STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY);
|
||||
else
|
||||
status |= STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
NSAssertRunningOnMainThread ();
|
||||
if ([rk05[(command >> 1) & 3] isMounted])
|
||||
status &= ~(STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY);
|
||||
else
|
||||
status |= STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyStatusChangedWhenNotRunning
|
||||
{
|
||||
NSAssertRunningOnMainThread ();
|
||||
NSAssert (! [pdp8 isGoing], @"PDP-8 is running");
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
NSAssertRunningOnMainThread ();
|
||||
NSAssert (! [pdp8 isGoing], @"PDP-8 is running");
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:STATUS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) setStatusBits:(unsigned)set clearStatusBits:(unsigned)clear
|
||||
{
|
||||
status |= set;
|
||||
status &= ~clear;
|
||||
if (status & STATUS_RAISE_FLAG_MASK)
|
||||
[pdp8 setIOFlagBits:ioflag];
|
||||
else
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
if (! [pdp8 isGoing])
|
||||
[self performSelectorOnMainThread:@selector(notifyStatusChangedWhenNotRunning)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
status |= set;
|
||||
status &= ~clear;
|
||||
if (status & STATUS_RAISE_FLAG_MASK)
|
||||
[pdp8 setIOFlagBits:ioflag];
|
||||
else
|
||||
[pdp8 clearIOFlagBits:ioflag];
|
||||
if (! [pdp8 isGoing])
|
||||
[self performSelectorOnMainThread:@selector(notifyStatusChangedWhenNotRunning)
|
||||
withObject:nil waitUntilDone:YES];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getBlockNumber
|
||||
{
|
||||
return ((command & 1) << 12) | block;
|
||||
return ((command & 1) << 12) | block;
|
||||
}
|
||||
|
||||
|
||||
- (void) setBlockNumber:(unsigned short)blk
|
||||
{
|
||||
NSAssert1 ((blk & ~017777) == 0, @"Bad RK8-E Block Number: 0%o", blk);
|
||||
block = blk & 07777;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:BLOCKNUMBER_CHANGED_NOTIFICATION
|
||||
object:self];
|
||||
[self setCommand:([self getCommand] & 07776) | (blk >> 12)];
|
||||
NSAssert1 ((blk & ~017777) == 0, @"Bad RK8-E Block Number: 0%o", blk);
|
||||
block = blk & 07777;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:BLOCKNUMBER_CHANGED_NOTIFICATION
|
||||
object:self];
|
||||
[self setCommand:([self getCommand] & 07776) | (blk >> 12)];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getMemoryAddress
|
||||
{
|
||||
return ((command & 070) << 9) | curaddr;
|
||||
return ((command & 070) << 9) | curaddr;
|
||||
}
|
||||
|
||||
|
||||
- (void) setMemoryAddress:(unsigned short)addr
|
||||
{
|
||||
NSAssert1 ((addr & ~077777) == 0, @"Bad RK8-E Memory Address: 0%o", addr);
|
||||
curaddr = addr & 07777;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MEMORYADDRESS_CHANGED_NOTIFICATION
|
||||
object:self];
|
||||
[self setCommand:([self getCommand] & 07707) | ((addr >> 9) & 070)];
|
||||
NSAssert1 ((addr & ~077777) == 0, @"Bad RK8-E Memory Address: 0%o", addr);
|
||||
curaddr = addr & 07777;
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:MEMORYADDRESS_CHANGED_NOTIFICATION
|
||||
object:self];
|
||||
[self setCommand:([self getCommand] & 07707) | ((addr >> 9) & 070)];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getCurrentAddress
|
||||
{
|
||||
return curaddr;
|
||||
return curaddr;
|
||||
}
|
||||
|
||||
|
||||
- (void) setCurrentAddress:(unsigned short)addr
|
||||
{
|
||||
NSAssert1 ((addr & ~07777) == 0, @"Bad Current Address: 0%o", addr);
|
||||
curaddr = addr;
|
||||
NSAssert1 ((addr & ~07777) == 0, @"Bad Current Address: 0%o", addr);
|
||||
curaddr = addr;
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getCurrentDriveNumber
|
||||
{
|
||||
return (command >> 1) & 3;
|
||||
return (command >> 1) & 3;
|
||||
}
|
||||
|
||||
|
||||
- (void) setCRC:(unsigned)newCRC
|
||||
{
|
||||
crc = checkcrc = newCRC;
|
||||
crc = checkcrc = newCRC;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isCRCOK
|
||||
{
|
||||
return crc == checkcrc;
|
||||
return crc == checkcrc;
|
||||
}
|
||||
|
||||
|
||||
- (void) lockControl
|
||||
{
|
||||
[controlLock lock];
|
||||
[controlLock lock];
|
||||
}
|
||||
|
||||
|
||||
- (void) unlockControl
|
||||
{
|
||||
[controlLock unlock];
|
||||
[controlLock unlock];
|
||||
}
|
||||
|
||||
|
||||
|
@ -334,92 +334,95 @@ API_VERSION
|
|||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
[self setCommand:[coder decodeIntForKey:CODER_KEY_COMMAND]];
|
||||
[self setStatus:[coder decodeIntForKey:CODER_KEY_STATUS]];
|
||||
[self setBlockNumber:[coder decodeIntForKey:CODER_KEY_BLOCK]];
|
||||
[self setCurrentAddress:[coder decodeIntForKey:CODER_KEY_CURADDR]];
|
||||
[coder decodeBoolForKey:CODER_KEY_IOFLAG] ?
|
||||
[pdp8 setIOFlagBits:ioflag] : [pdp8 clearIOFlagBits:ioflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_IOMASK] ?
|
||||
[pdp8 setInterruptMaskBits:ioflag] : [pdp8 clearInterruptMaskBits:ioflag];
|
||||
maint = [coder decodeBoolForKey:CODER_KEY_MAINT];
|
||||
ldb[0] = [coder decodeIntForKey:CODER_KEY_LDB0];
|
||||
ldb[1] = [coder decodeIntForKey:CODER_KEY_LDB1];
|
||||
ldb[2] = [coder decodeIntForKey:CODER_KEY_LDB2];
|
||||
ldb[3] = [coder decodeIntForKey:CODER_KEY_LDB3];
|
||||
ldbfill = [coder decodeIntForKey:CODER_KEY_LDBFILL];
|
||||
udb = [coder decodeIntForKey:CODER_KEY_UDB];
|
||||
crc = [coder decodeIntForKey:CODER_KEY_CRC];
|
||||
checkcrc = [coder decodeIntForKey:CODER_KEY_CHECKCRC];
|
||||
shifts = [coder decodeIntForKey:CODER_KEY_SHIFTS];
|
||||
wordcount = [coder decodeIntForKey:CODER_KEY_WORDCOUNT];
|
||||
shiftEnabled = [coder decodeBoolForKey:CODER_KEY_SHIFT_ENABLE];
|
||||
return self;
|
||||
self = [super init];
|
||||
[self loadCoder: coder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) loadCoder:(NSCoder *)coder
|
||||
{
|
||||
[self setCommand:[coder decodeIntForKey:CODER_KEY_COMMAND]];
|
||||
[self setStatus:[coder decodeIntForKey:CODER_KEY_STATUS]];
|
||||
[self setBlockNumber:[coder decodeIntForKey:CODER_KEY_BLOCK]];
|
||||
[self setCurrentAddress:[coder decodeIntForKey:CODER_KEY_CURADDR]];
|
||||
[coder decodeBoolForKey:CODER_KEY_IOFLAG] ?
|
||||
[pdp8 setIOFlagBits:ioflag] : [pdp8 clearIOFlagBits:ioflag];
|
||||
[coder decodeBoolForKey:CODER_KEY_IOMASK] ?
|
||||
[pdp8 setInterruptMaskBits:ioflag] : [pdp8 clearInterruptMaskBits:ioflag];
|
||||
maint = [coder decodeBoolForKey:CODER_KEY_MAINT];
|
||||
ldb[0] = [coder decodeIntForKey:CODER_KEY_LDB0];
|
||||
ldb[1] = [coder decodeIntForKey:CODER_KEY_LDB1];
|
||||
ldb[2] = [coder decodeIntForKey:CODER_KEY_LDB2];
|
||||
ldb[3] = [coder decodeIntForKey:CODER_KEY_LDB3];
|
||||
ldbfill = [coder decodeIntForKey:CODER_KEY_LDBFILL];
|
||||
udb = [coder decodeIntForKey:CODER_KEY_UDB];
|
||||
crc = [coder decodeIntForKey:CODER_KEY_CRC];
|
||||
checkcrc = [coder decodeIntForKey:CODER_KEY_CHECKCRC];
|
||||
shifts = [coder decodeIntForKey:CODER_KEY_SHIFTS];
|
||||
wordcount = [coder decodeIntForKey:CODER_KEY_WORDCOUNT];
|
||||
shiftEnabled = [coder decodeBoolForKey:CODER_KEY_SHIFT_ENABLE];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeInt:[self getCommand] forKey:CODER_KEY_COMMAND];
|
||||
[coder encodeInt:[self getStatus] forKey:CODER_KEY_STATUS];
|
||||
[coder encodeInt:[self getBlockNumber] forKey:CODER_KEY_BLOCK];
|
||||
[coder encodeInt:[self getCurrentAddress] forKey:CODER_KEY_CURADDR];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:ioflag] ? YES : NO forKey:CODER_KEY_IOFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:ioflag] ? YES : NO forKey:CODER_KEY_IOMASK];
|
||||
[coder encodeBool:maint forKey:CODER_KEY_MAINT];
|
||||
[coder encodeInt:ldb[0] forKey:CODER_KEY_LDB0];
|
||||
[coder encodeInt:ldb[1] forKey:CODER_KEY_LDB1];
|
||||
[coder encodeInt:ldb[2] forKey:CODER_KEY_LDB2];
|
||||
[coder encodeInt:ldb[3] forKey:CODER_KEY_LDB3];
|
||||
[coder encodeInt:ldbfill forKey:CODER_KEY_LDBFILL];
|
||||
[coder encodeInt:udb forKey:CODER_KEY_UDB];
|
||||
[coder encodeInt:crc forKey:CODER_KEY_CRC];
|
||||
[coder encodeInt:checkcrc forKey:CODER_KEY_CHECKCRC];
|
||||
[coder encodeInt:shifts forKey:CODER_KEY_SHIFTS];
|
||||
[coder encodeInt:wordcount forKey:CODER_KEY_WORDCOUNT];
|
||||
[coder encodeBool:shiftEnabled forKey:CODER_KEY_SHIFT_ENABLE];
|
||||
[coder encodeInt:[self getCommand] forKey:CODER_KEY_COMMAND];
|
||||
[coder encodeInt:[self getStatus] forKey:CODER_KEY_STATUS];
|
||||
[coder encodeInt:[self getBlockNumber] forKey:CODER_KEY_BLOCK];
|
||||
[coder encodeInt:[self getCurrentAddress] forKey:CODER_KEY_CURADDR];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:ioflag] ? YES : NO forKey:CODER_KEY_IOFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:ioflag] ? YES : NO forKey:CODER_KEY_IOMASK];
|
||||
[coder encodeBool:maint forKey:CODER_KEY_MAINT];
|
||||
[coder encodeInt:ldb[0] forKey:CODER_KEY_LDB0];
|
||||
[coder encodeInt:ldb[1] forKey:CODER_KEY_LDB1];
|
||||
[coder encodeInt:ldb[2] forKey:CODER_KEY_LDB2];
|
||||
[coder encodeInt:ldb[3] forKey:CODER_KEY_LDB3];
|
||||
[coder encodeInt:ldbfill forKey:CODER_KEY_LDBFILL];
|
||||
[coder encodeInt:udb forKey:CODER_KEY_UDB];
|
||||
[coder encodeInt:crc forKey:CODER_KEY_CRC];
|
||||
[coder encodeInt:checkcrc forKey:CODER_KEY_CHECKCRC];
|
||||
[coder encodeInt:shifts forKey:CODER_KEY_SHIFTS];
|
||||
[coder encodeInt:wordcount forKey:CODER_KEY_WORDCOUNT];
|
||||
[coder encodeBool:shiftEnabled forKey:CODER_KEY_SHIFT_ENABLE];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"RK8E notifyApplicationWillTerminate");
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[rk05Controller_0 encodeWithCoder:archiver];
|
||||
[rk05Controller_1 encodeWithCoder:archiver];
|
||||
[rk05Controller_2 encodeWithCoder:archiver];
|
||||
[rk05Controller_3 encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[archiver release];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
// NSLog (@"RK8E notifyApplicationWillTerminate");
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[rk05Controller_0 encodeWithCoder:archiver];
|
||||
[rk05Controller_1 encodeWithCoder:archiver];
|
||||
[rk05Controller_2 encodeWithCoder:archiver];
|
||||
[rk05Controller_3 encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
}
|
||||
|
||||
|
||||
- (void) pluginDidLoad
|
||||
{
|
||||
rk05[0] = rk05_0; [rk05[0] setPDP8:pdp8];
|
||||
rk05[1] = rk05_1; [rk05[1] setPDP8:pdp8];
|
||||
rk05[2] = rk05_2; [rk05[2] setPDP8:pdp8];
|
||||
rk05[3] = rk05_3; [rk05[3] setPDP8:pdp8];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[[NSKeyedUnarchiver alloc] initForReadingWithData:data] autorelease];
|
||||
[self initWithCoder: unarchiver];
|
||||
[[rk05Controller_0 initWithCoder:unarchiver] autorelease];
|
||||
[[rk05Controller_1 initWithCoder:unarchiver] autorelease];
|
||||
[[rk05Controller_2 initWithCoder:unarchiver] autorelease];
|
||||
[[rk05Controller_3 initWithCoder:unarchiver] autorelease];
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
controlLock = [[NSLock alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
rk05[0] = rk05_0; [rk05[0] setPDP8:pdp8];
|
||||
rk05[1] = rk05_1; [rk05[1] setPDP8:pdp8];
|
||||
rk05[2] = rk05_2; [rk05[2] setPDP8:pdp8];
|
||||
rk05[3] = rk05_3; [rk05[3] setPDP8:pdp8];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self loadCoder: unarchiver];
|
||||
[rk05Controller_0 loadCoder: unarchiver];
|
||||
[rk05Controller_1 loadCoder: unarchiver];
|
||||
[rk05Controller_2 loadCoder: unarchiver];
|
||||
[rk05Controller_3 loadCoder: unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
controlLock = [[NSLock alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPDP8IOFlagsChanged:)
|
||||
name:IOFLAGS_CHANGED_NOTIFICATION
|
||||
object:nil];
|
||||
|
|
|
@ -145,8 +145,8 @@
|
|||
selector:@selector(notifyStop:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStep:) name:PDP8_STEP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyPluginsLoaded:) name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
}
|
||||
|
||||
|
||||
|
|
268
TSC8/TSC8.m
268
TSC8/TSC8.m
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* TSC8.m - TSC8-75 Board for the PDP-8/E Simulator
|
||||
* TSC8.m - TSC8-75 Board for the PDP-8/E Simulator
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -34,16 +34,16 @@
|
|||
#import "TSC8iot.h"
|
||||
|
||||
|
||||
#define CODER_KEY_TSC8_ERTB @"tsc8ERTB"
|
||||
#define CODER_KEY_TSC8_ERIOT @"tsc8ERIOT"
|
||||
#define CODER_KEY_TSC8_ECDF @"tsc8ECDF"
|
||||
#define CODER_KEY_TSC8_ESME_ENABLED @"tsc8ESME"
|
||||
#define CODER_KEY_TSC8_IOFLAG @"tsc8IOFLAG"
|
||||
#define CODER_KEY_TSC8_IOMASK @"tsc8IOMASK"
|
||||
#define CODER_KEY_TSC8_ERTB @"tsc8ERTB"
|
||||
#define CODER_KEY_TSC8_ERIOT @"tsc8ERIOT"
|
||||
#define CODER_KEY_TSC8_ECDF @"tsc8ECDF"
|
||||
#define CODER_KEY_TSC8_ESME_ENABLED @"tsc8ESME"
|
||||
#define CODER_KEY_TSC8_IOFLAG @"tsc8IOFLAG"
|
||||
#define CODER_KEY_TSC8_IOMASK @"tsc8IOMASK"
|
||||
|
||||
#define ERTB_CHANGED_NOTIFICATION @"tsc8ERTBChangedNotification"
|
||||
#define ERIOT_CHANGED_NOTIFICATION @"tsc8ERIOTChangedNotification"
|
||||
#define ECDF_CHANGED_NOTIFICATION @"tsc8ECDFChangedNotification"
|
||||
#define ERTB_CHANGED_NOTIFICATION @"tsc8ERTBChangedNotification"
|
||||
#define ERIOT_CHANGED_NOTIFICATION @"tsc8ERIOTChangedNotification"
|
||||
#define ECDF_CHANGED_NOTIFICATION @"tsc8ECDFChangedNotification"
|
||||
|
||||
|
||||
@implementation TSC8
|
||||
|
@ -57,59 +57,59 @@ API_VERSION
|
|||
|
||||
- (unsigned short) getERTB
|
||||
{
|
||||
return [pdp8 getTSC8ertb];
|
||||
return [pdp8 getTSC8ertb];
|
||||
}
|
||||
|
||||
|
||||
- (void) setERTB:(ushort)ertb
|
||||
{
|
||||
[pdp8 setTSC8ertb:ertb];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ERTB_CHANGED_NOTIFICATION object:self];
|
||||
[pdp8 setTSC8ertb:ertb];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ERTB_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getERIOT
|
||||
{
|
||||
return [pdp8 getTSC8eriot];
|
||||
return [pdp8 getTSC8eriot];
|
||||
}
|
||||
|
||||
|
||||
- (void) setERIOT:(ushort)eriot
|
||||
{
|
||||
[pdp8 setTSC8eriot:eriot];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ERIOT_CHANGED_NOTIFICATION object:self];
|
||||
[pdp8 setTSC8eriot:eriot];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ERIOT_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) getESMEenabled
|
||||
{
|
||||
return [pdp8 getTSC8esmeEnabled];
|
||||
return [pdp8 getTSC8esmeEnabled];
|
||||
}
|
||||
|
||||
|
||||
- (void) setESMEenabled:(BOOL)enabled
|
||||
{
|
||||
[pdp8 setTSC8esmeEnabled:enabled];
|
||||
[esmeButton setIntValue:enabled];
|
||||
[pdp8 setTSC8esmeEnabled:enabled];
|
||||
[esmeButton setIntValue:enabled];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) esmeEnabledClicked:(id)sender
|
||||
{
|
||||
[self setESMEenabled:[sender intValue]];
|
||||
[self setESMEenabled:[sender intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned short) getECDF
|
||||
{
|
||||
return [pdp8 getTSC8ecdf];
|
||||
return [pdp8 getTSC8ecdf];
|
||||
}
|
||||
|
||||
|
||||
- (void) setECDF:(ushort)ecdf
|
||||
{
|
||||
[pdp8 setTSC8ecdf:ecdf];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ECDF_CHANGED_NOTIFICATION object:self];
|
||||
[pdp8 setTSC8ecdf:ecdf];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ECDF_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,64 +118,64 @@ API_VERSION
|
|||
|
||||
- (NSArray *) iotsForAddress:(int)ioAddress
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6360],
|
||||
[NSValue valueWithPointer:i6361],
|
||||
[NSValue valueWithPointer:i6362],
|
||||
[NSValue valueWithPointer:i6363],
|
||||
[NSValue valueWithPointer:i6364],
|
||||
[NSValue valueWithPointer:i6365],
|
||||
[NSValue valueWithPointer:i6366],
|
||||
[NSValue valueWithPointer:i6367],
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:i6360],
|
||||
[NSValue valueWithPointer:i6361],
|
||||
[NSValue valueWithPointer:i6362],
|
||||
[NSValue valueWithPointer:i6363],
|
||||
[NSValue valueWithPointer:i6364],
|
||||
[NSValue valueWithPointer:i6365],
|
||||
[NSValue valueWithPointer:i6366],
|
||||
[NSValue valueWithPointer:i6367],
|
||||
nil];
|
||||
}
|
||||
|
||||
|
||||
- (NSArray *) skiptestsForAddress:(int)ioAddress
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6361],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6363],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6365],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
return [NSArray arrayWithObjects:
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6361],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6363],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:s6365],
|
||||
[NSValue valueWithPointer:nil],
|
||||
[NSValue valueWithPointer:nil],
|
||||
nil];
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void) setIOFlag:(unsigned long)flag forIOFlagName:(NSString *)name;
|
||||
{
|
||||
[pdp8 setTSC8flag:flag];
|
||||
[pdp8 setTSC8flag:flag];
|
||||
}
|
||||
|
||||
|
||||
- (void) CAF:(int)ioAddress
|
||||
{
|
||||
[pdp8 clearIOFlagBits:[pdp8 getTSC8flag]];
|
||||
[pdp8 clearInterruptMaskBits:[pdp8 getTSC8flag]];
|
||||
[pdp8 setTSC8ertb:0];
|
||||
[pdp8 setTSC8eriot:0];
|
||||
[pdp8 setTSC8ecdf:0];
|
||||
[pdp8 clearIOFlagBits:[pdp8 getTSC8flag]];
|
||||
[pdp8 clearInterruptMaskBits:[pdp8 getTSC8flag]];
|
||||
[pdp8 setTSC8ertb:0];
|
||||
[pdp8 setTSC8eriot:0];
|
||||
[pdp8 setTSC8ecdf:0];
|
||||
}
|
||||
|
||||
|
||||
- (void) clearAllFlags:(int)ioAddress
|
||||
{
|
||||
[pdp8 clearIOFlagBits:[pdp8 getTSC8flag]];
|
||||
[pdp8 clearInterruptMaskBits:[pdp8 getTSC8flag]];
|
||||
[self setERTB:0];
|
||||
[self setERIOT:0];
|
||||
[self setECDF:0];
|
||||
[pdp8 clearIOFlagBits:[pdp8 getTSC8flag]];
|
||||
[pdp8 clearInterruptMaskBits:[pdp8 getTSC8flag]];
|
||||
[self setERTB:0];
|
||||
[self setERIOT:0];
|
||||
[self setECDF:0];
|
||||
}
|
||||
|
||||
|
||||
- (void) resetDevice
|
||||
{
|
||||
[self clearAllFlags:0];
|
||||
[self clearAllFlags:0];
|
||||
}
|
||||
|
||||
|
||||
|
@ -184,27 +184,27 @@ API_VERSION
|
|||
|
||||
- (void) notifyGo:(NSNotification *)notification
|
||||
{
|
||||
[ertbRegister setEnabled:NO];
|
||||
[eriotRegister setEnabled:NO];
|
||||
[ecdfRegister setEnabled:NO];
|
||||
[ertbRegister setEnabled:NO];
|
||||
[eriotRegister setEnabled:NO];
|
||||
[ecdfRegister setEnabled:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyStep:(NSNotification *)notification
|
||||
{
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter postNotificationName:ERTB_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:ERIOT_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:ECDF_CHANGED_NOTIFICATION object:self];
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter postNotificationName:ERTB_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:ERIOT_CHANGED_NOTIFICATION object:self];
|
||||
[defaultCenter postNotificationName:ECDF_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyStop:(NSNotification *)notification
|
||||
{
|
||||
[self notifyStep:notification];
|
||||
[ertbRegister setEnabled:YES];
|
||||
[eriotRegister setEnabled:YES];
|
||||
[ecdfRegister setEnabled:YES];
|
||||
[self notifyStep:notification];
|
||||
[ertbRegister setEnabled:YES];
|
||||
[eriotRegister setEnabled:YES];
|
||||
[ecdfRegister setEnabled:YES];
|
||||
}
|
||||
|
||||
|
||||
|
@ -213,80 +213,82 @@ API_VERSION
|
|||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
[self setERTB:[coder decodeIntForKey:CODER_KEY_TSC8_ERTB]];
|
||||
[self setERIOT:[coder decodeIntForKey:CODER_KEY_TSC8_ERIOT]];
|
||||
[self setECDF:[coder decodeIntForKey:CODER_KEY_TSC8_ECDF]];
|
||||
[self setESMEenabled:[coder decodeBoolForKey:CODER_KEY_TSC8_ESME_ENABLED]];
|
||||
unsigned long flag = [pdp8 getTSC8flag];
|
||||
[coder decodeBoolForKey:CODER_KEY_TSC8_IOFLAG] ?
|
||||
[pdp8 setIOFlagBits:flag] : [pdp8 clearIOFlagBits:flag];
|
||||
[coder decodeBoolForKey:CODER_KEY_TSC8_IOMASK] ?
|
||||
[pdp8 setInterruptMaskBits:flag] : [pdp8 clearInterruptMaskBits:flag];
|
||||
return self;
|
||||
self = [super init];
|
||||
[self loadCoder: coder];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadCoder:(NSCoder *)coder
|
||||
{
|
||||
[self setERTB:[coder decodeIntForKey:CODER_KEY_TSC8_ERTB]];
|
||||
[self setERIOT:[coder decodeIntForKey:CODER_KEY_TSC8_ERIOT]];
|
||||
[self setECDF:[coder decodeIntForKey:CODER_KEY_TSC8_ECDF]];
|
||||
[self setESMEenabled:[coder decodeBoolForKey:CODER_KEY_TSC8_ESME_ENABLED]];
|
||||
unsigned long flag = [pdp8 getTSC8flag];
|
||||
[coder decodeBoolForKey:CODER_KEY_TSC8_IOFLAG] ?
|
||||
[pdp8 setIOFlagBits:flag] : [pdp8 clearIOFlagBits:flag];
|
||||
[coder decodeBoolForKey:CODER_KEY_TSC8_IOMASK] ?
|
||||
[pdp8 setInterruptMaskBits:flag] : [pdp8 clearInterruptMaskBits:flag];
|
||||
}
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeInt:[self getERTB] forKey:CODER_KEY_TSC8_ERTB];
|
||||
[coder encodeInt:[self getERIOT] forKey:CODER_KEY_TSC8_ERIOT];
|
||||
[coder encodeInt:[self getECDF] forKey:CODER_KEY_TSC8_ECDF];
|
||||
[coder encodeBool:[self getESMEenabled] forKey:CODER_KEY_TSC8_ESME_ENABLED];
|
||||
unsigned long flag = [pdp8 getTSC8flag];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:flag] ? YES : NO forKey:CODER_KEY_TSC8_IOFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:flag] ? YES : NO forKey:CODER_KEY_TSC8_IOMASK];
|
||||
[coder encodeInt:[self getERTB] forKey:CODER_KEY_TSC8_ERTB];
|
||||
[coder encodeInt:[self getERIOT] forKey:CODER_KEY_TSC8_ERIOT];
|
||||
[coder encodeInt:[self getECDF] forKey:CODER_KEY_TSC8_ECDF];
|
||||
[coder encodeBool:[self getESMEenabled] forKey:CODER_KEY_TSC8_ESME_ENABLED];
|
||||
unsigned long flag = [pdp8 getTSC8flag];
|
||||
[coder encodeBool:[pdp8 getIOFlagBits:flag] ? YES : NO forKey:CODER_KEY_TSC8_IOFLAG];
|
||||
[coder encodeBool:[pdp8 getInterruptMaskBits:flag] ? YES : NO forKey:CODER_KEY_TSC8_IOMASK];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"TSC8 notifyApplicationWillTerminate");
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[archiver release];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
// NSLog (@"TSC8 notifyApplicationWillTerminate");
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
|
||||
[self encodeWithCoder:archiver];
|
||||
[archiver finishEncoding];
|
||||
[[NSUserDefaults standardUserDefaults] setObject:data forKey:[self pluginName]];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyPluginsLoaded:(NSNotification *)notification
|
||||
{
|
||||
[window orderBackFromDefaults:self];
|
||||
[window makeFirstResponder:window];
|
||||
[window orderBackFromDefaults:self];
|
||||
[window makeFirstResponder:window];
|
||||
}
|
||||
|
||||
|
||||
- (void) pluginDidLoad
|
||||
{
|
||||
[ertbRegister setupRegisterFor:self
|
||||
getRegisterValue:@selector(getERTB) setRegisterValue:@selector(setERTB:)
|
||||
changedNotificationName:ERTB_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[eriotRegister setupRegisterFor:self
|
||||
getRegisterValue:@selector(getERIOT) setRegisterValue:@selector(setERIOT:)
|
||||
changedNotificationName:ERIOT_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[ecdfRegister setupRegisterFor:self
|
||||
getRegisterValue:@selector(getECDF) setRegisterValue:@selector(setECDF:)
|
||||
changedNotificationName:ECDF_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self initWithCoder:unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
[unarchiver release];
|
||||
}
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyGo:) name:PDP8_GO_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStop:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStep:) name:PDP8_STEP_NOTIFICATION object:nil];
|
||||
[ertbRegister setupRegisterFor:self
|
||||
getRegisterValue:@selector(getERTB) setRegisterValue:@selector(setERTB:)
|
||||
changedNotificationName:ERTB_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[eriotRegister setupRegisterFor:self
|
||||
getRegisterValue:@selector(getERIOT) setRegisterValue:@selector(setERIOT:)
|
||||
changedNotificationName:ERIOT_CHANGED_NOTIFICATION mask:07777 base:8];
|
||||
[ecdfRegister setupRegisterFor:self
|
||||
getRegisterValue:@selector(getECDF) setRegisterValue:@selector(setECDF:)
|
||||
changedNotificationName:ECDF_CHANGED_NOTIFICATION mask:01 base:8];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:[self pluginName]];
|
||||
if (data) {
|
||||
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
|
||||
[self loadCoder:unarchiver];
|
||||
[unarchiver finishDecoding];
|
||||
}
|
||||
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
[defaultCenter addObserver:self selector:@selector(notifyPluginsLoaded:)
|
||||
name:PLUGINS_LOADED_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyGo:) name:PDP8_GO_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStop:) name:PDP8_STOP_NOTIFICATION object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyStep:) name:PDP8_STEP_NOTIFICATION object:nil];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* Breakpoint.m - Class for a single breakpoint
|
||||
* Breakpoint.m - Class for a single breakpoint
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,60 +32,60 @@
|
|||
|
||||
+ (Breakpoint *) breakpointWithIdentifier:(unsigned)ident value:(unsigned)val
|
||||
{
|
||||
return [[[self alloc] initWithIdentifier:ident value:val] autorelease];
|
||||
return [[self alloc] initWithIdentifier:ident value:val];
|
||||
}
|
||||
|
||||
|
||||
- (id) initWithCoder:(NSCoder *)coder
|
||||
{
|
||||
self = [super init];
|
||||
identifier = [coder decodeIntForKey:@"id"];
|
||||
value = [coder decodeIntForKey:@"val"];
|
||||
return self;
|
||||
self = [super init];
|
||||
identifier = [coder decodeIntForKey:@"id"];
|
||||
value = [coder decodeIntForKey:@"val"];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void) encodeWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeInt:identifier forKey:@"id"];
|
||||
[coder encodeInt:value forKey:@"val"];
|
||||
[coder encodeInt:identifier forKey:@"id"];
|
||||
[coder encodeInt:value forKey:@"val"];
|
||||
}
|
||||
|
||||
|
||||
- (Breakpoint *) initWithIdentifier:(unsigned)ident value:(unsigned)val
|
||||
{
|
||||
self = [super init];
|
||||
identifier = ident;
|
||||
value = val;
|
||||
return self;
|
||||
self = [super init];
|
||||
identifier = ident;
|
||||
value = val;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) identifier
|
||||
{
|
||||
return identifier;
|
||||
return identifier;
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) value
|
||||
{
|
||||
return value;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
- (void) setUnsignedValue:(unsigned)val
|
||||
{
|
||||
value = val;
|
||||
value = val;
|
||||
}
|
||||
|
||||
|
||||
- (NSComparisonResult) compareAddress:(Breakpoint *)breakpoint
|
||||
{
|
||||
if (identifier < [breakpoint identifier])
|
||||
return NSOrderedAscending;
|
||||
if (identifier > [breakpoint identifier])
|
||||
return NSOrderedDescending;
|
||||
return NSOrderedSame;
|
||||
if (identifier < [breakpoint identifier])
|
||||
return NSOrderedAscending;
|
||||
if (identifier > [breakpoint identifier])
|
||||
return NSOrderedDescending;
|
||||
return NSOrderedSame;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* BreakpointArray.m - Container for a sorted array of breakpoints
|
||||
* BreakpointArray.m - Container for a sorted array of breakpoints
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -34,69 +34,68 @@
|
|||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
breakpoints = [[NSMutableArray alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
breakpoints = [[NSMutableArray alloc] init];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(notifyApplicationWillTerminate:)
|
||||
name:NSApplicationWillTerminateNotification object:nil];
|
||||
}
|
||||
|
||||
|
||||
- (void) loadFromPrefs:(NSString *)key
|
||||
{
|
||||
prefsKey = [key retain];
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:key];
|
||||
if (data) {
|
||||
[breakpoints release];
|
||||
breakpoints = [[NSMutableArray alloc]
|
||||
initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:data]];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
prefsKey = key;
|
||||
NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:key];
|
||||
if (data) {
|
||||
breakpoints = [[NSMutableArray alloc]
|
||||
initWithArray:[NSKeyedUnarchiver unarchiveObjectWithData:data]];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyApplicationWillTerminate:(NSNotification *)notification
|
||||
{
|
||||
// NSLog (@"BreakpointArray notifyApplicationWillTerminate");
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
setObject:[NSKeyedArchiver archivedDataWithRootObject:breakpoints] forKey:prefsKey];
|
||||
// NSLog (@"BreakpointArray notifyApplicationWillTerminate");
|
||||
[[NSUserDefaults standardUserDefaults]
|
||||
setObject:[NSKeyedArchiver archivedDataWithRootObject:breakpoints] forKey:prefsKey];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) hasBreakpointWithValueNotEqualTo:(unsigned)value
|
||||
{
|
||||
Breakpoint *breakpoint;
|
||||
|
||||
NSEnumerator *enumerator = [breakpoints objectEnumerator];
|
||||
while ((breakpoint = [enumerator nextObject])) {
|
||||
if ([breakpoint value] != value)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
Breakpoint *breakpoint;
|
||||
|
||||
NSEnumerator *enumerator = [breakpoints objectEnumerator];
|
||||
while ((breakpoint = [enumerator nextObject])) {
|
||||
if ([breakpoint value] != value)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) valueForIdentifier:(unsigned)ident
|
||||
{
|
||||
int n = [breakpoints indexOfObject:[Breakpoint breakpointWithIdentifier:ident value:0]
|
||||
inArraySortedBy:@selector(compareAddress:)];
|
||||
return (n == NSNotFound || n < 0) ? 0 : [(Breakpoint *)[breakpoints objectAtIndex:n] value];
|
||||
int n = [breakpoints indexOfObject:[Breakpoint breakpointWithIdentifier:ident value:0]
|
||||
inArraySortedBy:@selector(compareAddress:)];
|
||||
return (n == NSNotFound || n < 0) ? 0 : [(Breakpoint *)[breakpoints objectAtIndex:n] value];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) setBreakpointWithIdentifier:(unsigned)ident value:(unsigned)val
|
||||
{
|
||||
unsigned index = [breakpoints indexOfObject:[Breakpoint breakpointWithIdentifier:ident value:0]
|
||||
inArraySortedBy:@selector(compareAddress:)];
|
||||
if (index == NSNotFound)
|
||||
index = [breakpoints addObject:
|
||||
[Breakpoint breakpointWithIdentifier:ident value:val]
|
||||
toArraySortedBy:@selector(compareAddress:) replaceExistingObject:YES];
|
||||
else
|
||||
[[breakpoints objectAtIndex:index] setUnsignedValue:val];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
return index;
|
||||
unsigned index = [breakpoints indexOfObject:[Breakpoint breakpointWithIdentifier:ident value:0]
|
||||
inArraySortedBy:@selector(compareAddress:)];
|
||||
if (index == NSNotFound)
|
||||
index = [breakpoints addObject:
|
||||
[Breakpoint breakpointWithIdentifier:ident value:val]
|
||||
toArraySortedBy:@selector(compareAddress:) replaceExistingObject:YES];
|
||||
else
|
||||
[[breakpoints objectAtIndex:index] setUnsignedValue:val];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
|
@ -104,79 +103,79 @@
|
|||
// mass insert to avoid performance problems with the BREAKPOINTS_CHANGED_NOTIFICATION
|
||||
// idents must be sorted ascending to get a correct index set
|
||||
{
|
||||
NSNumber *number;
|
||||
|
||||
NSMutableIndexSet *index = [[[NSMutableIndexSet alloc] init] autorelease];
|
||||
NSEnumerator *enumerator = [idents objectEnumerator];
|
||||
while ((number = [enumerator nextObject]))
|
||||
[index addIndex:[breakpoints addObject:
|
||||
[Breakpoint breakpointWithIdentifier:[number intValue] value:val]
|
||||
toArraySortedBy:@selector(compareAddress:) replaceExistingObject:YES]];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
return index;
|
||||
NSNumber *number;
|
||||
|
||||
NSMutableIndexSet *index = [[NSMutableIndexSet alloc] init];
|
||||
NSEnumerator *enumerator = [idents objectEnumerator];
|
||||
while ((number = [enumerator nextObject]))
|
||||
[index addIndex:[breakpoints addObject:
|
||||
[Breakpoint breakpointWithIdentifier:[number intValue] value:val]
|
||||
toArraySortedBy:@selector(compareAddress:) replaceExistingObject:YES]];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) identifierAtIndex:(unsigned)index
|
||||
{
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
return [(Breakpoint *)[breakpoints objectAtIndex:index] identifier];
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
return [(Breakpoint *)[breakpoints objectAtIndex:index] identifier];
|
||||
}
|
||||
|
||||
|
||||
- (unsigned) valueAtIndex:(unsigned)index
|
||||
{
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
return [(Breakpoint *)[breakpoints objectAtIndex:index] value];
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
return [(Breakpoint *)[breakpoints objectAtIndex:index] value];
|
||||
}
|
||||
|
||||
|
||||
- (void) setBreakpointAtIndex:(unsigned)index value:(unsigned)val
|
||||
{
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
[[breakpoints objectAtIndex:index] setUnsignedValue:val];
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
[[breakpoints objectAtIndex:index] setUnsignedValue:val];
|
||||
}
|
||||
|
||||
|
||||
- (void) deleteBreakpointAtIndex:(unsigned)index
|
||||
{
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
[breakpoints removeObjectAtIndex:index];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
NSAssert (index < [breakpoints count], @"Index out of range");
|
||||
[breakpoints removeObjectAtIndex:index];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) deleteBreakpointsAtIndexes:(NSIndexSet *)indexes
|
||||
{
|
||||
[breakpoints removeObjectsAtIndexes:indexes];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
[breakpoints removeObjectsAtIndexes:indexes];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (void) setAllValues:(unsigned)val
|
||||
{
|
||||
Breakpoint *breakpoint;
|
||||
|
||||
NSEnumerator *enumerator = [breakpoints objectEnumerator];
|
||||
while ((breakpoint = [enumerator nextObject]))
|
||||
[breakpoint setUnsignedValue:val];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
Breakpoint *breakpoint;
|
||||
|
||||
NSEnumerator *enumerator = [breakpoints objectEnumerator];
|
||||
while ((breakpoint = [enumerator nextObject]))
|
||||
[breakpoint setUnsignedValue:val];
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:BREAKPOINTS_CHANGED_NOTIFICATION object:self];
|
||||
}
|
||||
|
||||
|
||||
- (int) numberOfBreakpoints
|
||||
{
|
||||
return (int)([breakpoints count]);
|
||||
return (int)([breakpoints count]);
|
||||
}
|
||||
|
||||
|
||||
- (NSEnumerator *) enumerator
|
||||
{
|
||||
return [breakpoints objectEnumerator];
|
||||
return [breakpoints objectEnumerator];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* Disassembler.m - Disassembler for PDP-8/E instructions
|
||||
* Disassembler.m - Disassembler for PDP-8/E instructions
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -34,247 +34,247 @@
|
|||
|
||||
+ (Disassembler *) sharedDisassembler
|
||||
{
|
||||
static Disassembler *sharedDisassembler;
|
||||
static Disassembler *sharedDisassembler;
|
||||
|
||||
if (! sharedDisassembler)
|
||||
sharedDisassembler = [[self alloc] init];
|
||||
return sharedDisassembler;
|
||||
if (! sharedDisassembler)
|
||||
sharedDisassembler = [[self alloc] init];
|
||||
return sharedDisassembler;
|
||||
}
|
||||
|
||||
|
||||
- (id) init
|
||||
{
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||
[[NSBundle mainBundle] pathForResource:@"disassembler" ofType:@"plist"]];
|
||||
|
||||
self = [super init];
|
||||
mriOpcodes = [[dict objectForKey:@"MRI"] retain];
|
||||
iotOpcodes = [[dict objectForKey:@"IOT"] retain];
|
||||
oprGroup1Opcodes = [[dict objectForKey:@"OPR Group 1"] retain];
|
||||
oprGroup2Opcodes = [[dict objectForKey:@"OPR Group 2"] retain];
|
||||
eaeModeAOpcodes = [[dict objectForKey:@"EAE Mode A"] retain];
|
||||
eaeModeBOpcodes = [[dict objectForKey:@"EAE Mode B"] retain];
|
||||
return self;
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||
[[NSBundle mainBundle] pathForResource:@"disassembler" ofType:@"plist"]];
|
||||
|
||||
self = [super init];
|
||||
mriOpcodes = [dict objectForKey:@"MRI"];
|
||||
iotOpcodes = [dict objectForKey:@"IOT"];
|
||||
oprGroup1Opcodes = [dict objectForKey:@"OPR Group 1"];
|
||||
oprGroup2Opcodes = [dict objectForKey:@"OPR Group 2"];
|
||||
eaeModeAOpcodes = [dict objectForKey:@"EAE Mode A"];
|
||||
eaeModeBOpcodes = [dict objectForKey:@"EAE Mode B"];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) disassembleOpcodeForPDP8:(PDP8 *)pdp8
|
||||
atAddress:(int)addr showOperandsAtPC:(BOOL)showOpAtPC
|
||||
atAddress:(int)addr showOperandsAtPC:(BOOL)showOpAtPC
|
||||
{
|
||||
short inst, word1, word2, ad, d, e, pc, field;
|
||||
char str[128], *p;
|
||||
|
||||
NSCAssert1 ((addr & ~077777) == 0, @"Bad address %o", addr);
|
||||
if (addr >= [pdp8 memorySize])
|
||||
return NSLocalizedString(@"n/a", @"");
|
||||
p = str;
|
||||
pc = [pdp8 getProgramCounter];
|
||||
inst = [pdp8 memoryAt:addr];
|
||||
word1 = [pdp8 memoryAtNext:addr];
|
||||
switch (inst & 07000) {
|
||||
case 00000 : /* AND */
|
||||
case 01000 : /* TAD */
|
||||
case 02000 : /* ISZ */
|
||||
case 03000 : /* DCA */
|
||||
case 04000 : /* JMS */
|
||||
case 05000 : /* JMP */
|
||||
[[mriOpcodes objectAtIndex:(inst >> 9)]
|
||||
getCString:p maxLength:(sizeof(str) - 1) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
p += sprintf(p, " %s", (inst & 0400) ? "I " : "");
|
||||
ad = ((inst & 0200) ? (addr & 07600) : 0) | (inst & 0177);
|
||||
d = ad - (addr & 07777);
|
||||
if (inst >= 04000 && ! (inst & 0400)) {
|
||||
if (d == 0)
|
||||
p += sprintf(p, ".");
|
||||
else if (-5 < d && d < 5)
|
||||
p += sprintf(p, ".%+d" /* %d (not %o) to get sign */, d);
|
||||
else
|
||||
p += sprintf(p, "%o", ad);
|
||||
} else
|
||||
p += sprintf(p, "%o", ad);
|
||||
if (addr == pc && showOpAtPC) {
|
||||
field = ((inst >= 04000 && ! (inst & 0400) && [pdp8 getIB] != [pdp8 getIF]) ?
|
||||
[pdp8 getIB] : [pdp8 getIF]) << 12;
|
||||
d = ((inst & 0400) && ad > 07 && ad < 020) ? 1 : 0;
|
||||
/* indirect auto index register access */
|
||||
word1 = field | ad;
|
||||
ad = ([pdp8 memoryAt:(field | ad)] + d) & 07777;
|
||||
if (inst < 05000 || inst >= 05400)
|
||||
p += sprintf(p, " (%4.4o)", ad);
|
||||
if (inst < 05000 && (inst & 0400)) {
|
||||
field = ((inst < 04000) ? [pdp8 getDF] : [pdp8 getIB]) << 12;
|
||||
d = (d && word1 == (field | ad)) ? 1 : 0;
|
||||
ad = ([pdp8 memoryAt:(field | ad)] + d) & 07777;
|
||||
p += sprintf(p, " ((%4.4o))", ad);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 06000 : /* IOT */
|
||||
[[iotOpcodes objectAtIndex:(inst & 0777)]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
break;
|
||||
case 07000 : /* OPR */
|
||||
switch (inst & 07401) {
|
||||
case 07000 : /* OPR Group I */
|
||||
case 07001 :
|
||||
[[oprGroup1Opcodes objectAtIndex:(inst & 0377)]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
break;
|
||||
case 07400 : /* OPR Group II */
|
||||
[[oprGroup2Opcodes objectAtIndex:((inst & 0377) >> 1)]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
break;
|
||||
short inst, word1, word2, ad, d, e, pc, field;
|
||||
char str[128], *p;
|
||||
|
||||
NSCAssert1 ((addr & ~077777) == 0, @"Bad address %o", addr);
|
||||
if (addr >= [pdp8 memorySize])
|
||||
return NSLocalizedString(@"n/a", @"");
|
||||
p = str;
|
||||
pc = [pdp8 getProgramCounter];
|
||||
inst = [pdp8 memoryAt:addr];
|
||||
word1 = [pdp8 memoryAtNext:addr];
|
||||
switch (inst & 07000) {
|
||||
case 00000 : /* AND */
|
||||
case 01000 : /* TAD */
|
||||
case 02000 : /* ISZ */
|
||||
case 03000 : /* DCA */
|
||||
case 04000 : /* JMS */
|
||||
case 05000 : /* JMP */
|
||||
[[mriOpcodes objectAtIndex:(inst >> 9)]
|
||||
getCString:p maxLength:(sizeof(str) - 1) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
p += sprintf(p, " %s", (inst & 0400) ? "I " : "");
|
||||
ad = ((inst & 0200) ? (addr & 07600) : 0) | (inst & 0177);
|
||||
d = ad - (addr & 07777);
|
||||
if (inst >= 04000 && ! (inst & 0400)) {
|
||||
if (d == 0)
|
||||
p += sprintf(p, ".");
|
||||
else if (-5 < d && d < 5)
|
||||
p += sprintf(p, ".%+d" /* %d (not %o) to get sign */, d);
|
||||
else
|
||||
p += sprintf(p, "%o", ad);
|
||||
} else
|
||||
p += sprintf(p, "%o", ad);
|
||||
if (addr == pc && showOpAtPC) {
|
||||
field = ((inst >= 04000 && ! (inst & 0400) && [pdp8 getIB] != [pdp8 getIF]) ?
|
||||
[pdp8 getIB] : [pdp8 getIF]) << 12;
|
||||
d = ((inst & 0400) && ad > 07 && ad < 020) ? 1 : 0;
|
||||
/* indirect auto index register access */
|
||||
word1 = field | ad;
|
||||
ad = ([pdp8 memoryAt:(field | ad)] + d) & 07777;
|
||||
if (inst < 05000 || inst >= 05400)
|
||||
p += sprintf(p, " (%4.4o)", ad);
|
||||
if (inst < 05000 && (inst & 0400)) {
|
||||
field = ((inst < 04000) ? [pdp8 getDF] : [pdp8 getIB]) << 12;
|
||||
d = (d && word1 == (field | ad)) ? 1 : 0;
|
||||
ad = ([pdp8 memoryAt:(field | ad)] + d) & 07777;
|
||||
p += sprintf(p, " ((%4.4o))", ad);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 06000 : /* IOT */
|
||||
[[iotOpcodes objectAtIndex:(inst & 0777)]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
break;
|
||||
case 07000 : /* OPR */
|
||||
switch (inst & 07401) {
|
||||
case 07000 : /* OPR Group I */
|
||||
case 07001 :
|
||||
[[oprGroup1Opcodes objectAtIndex:(inst & 0377)]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
break;
|
||||
case 07400 : /* OPR Group II */
|
||||
[[oprGroup2Opcodes objectAtIndex:((inst & 0377) >> 1)]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
break;
|
||||
/*
|
||||
* | | | |
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
|
||||
* | 1 |CLA|MQA|SCA|MQL| | | | 1 | Group III Mode A
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* Sequence: 1 2 2 \____3____/
|
||||
* V
|
||||
* 0 = NOP 2 = MUY# 4 = NMI 6 = ASR#
|
||||
* 1 = SCL# 3 = DVI# 5 = SHL# 7 = LSR#
|
||||
* | | | |
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
|
||||
* | 1 |CLA|MQA|SCA|MQL| | | | 1 | Group III Mode A
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* Sequence: 1 2 2 \____3____/
|
||||
* V
|
||||
* 0 = NOP 2 = MUY# 4 = NMI 6 = ASR#
|
||||
* 1 = SCL# 3 = DVI# 5 = SHL# 7 = LSR#
|
||||
*
|
||||
* | | | |
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
|
||||
* | 1 |CLA|MQA| |MQL| | | | 1 | Group III Mode B
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* Sequence: 1 2 \ 2 /
|
||||
* \_______3_______/
|
||||
* V
|
||||
* 0 = NOP 4 = NMI 10 = SCA 14 = DPSZ
|
||||
* 1 = ACS 5 = SHL# 11 = DAD# 15 = DPIC*
|
||||
* 2 = MUY# 6 = ASR# 12 = DST# 16 = DCM*
|
||||
* 3 = DVI# 7 = LSR# 13 = SWBA 17 = SAM
|
||||
* # = 2-word instructions
|
||||
* * = (MQL & MQA must be set)
|
||||
* | | | |
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11|
|
||||
* | 1 |CLA|MQA| |MQL| | | | 1 | Group III Mode B
|
||||
* |---|---|---|---|---|---|---|---|---|
|
||||
* Sequence: 1 2 \ 2 /
|
||||
* \_______3_______/
|
||||
* V
|
||||
* 0 = NOP 4 = NMI 10 = SCA 14 = DPSZ
|
||||
* 1 = ACS 5 = SHL# 11 = DAD# 15 = DPIC*
|
||||
* 2 = MUY# 6 = ASR# 12 = DST# 16 = DCM*
|
||||
* 3 = DVI# 7 = LSR# 13 = SWBA 17 = SAM
|
||||
* # = 2-word instructions
|
||||
* * = (MQL & MQA must be set)
|
||||
*/
|
||||
case 07401 : /* EAE */
|
||||
d = (inst & 0377) >> 1 ;
|
||||
if ([pdp8 getEAEmode] == EAE_MODE_A) {
|
||||
[[eaeModeAOpcodes objectAtIndex:d]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
switch (inst & 016) {
|
||||
case 002 : /* SCL */
|
||||
case 004 : /* MUY */
|
||||
case 006 : /* DVI */
|
||||
case 012 : /* SHL */
|
||||
case 014 : /* ASR */
|
||||
case 016 : /* LSR */
|
||||
if (inst != 07447) { /* SWBA */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* word1 is operand */
|
||||
}
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
} else { /* EAE mode B */
|
||||
[[eaeModeBOpcodes objectAtIndex:d]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
switch (inst & 056) {
|
||||
case 04 : /* MUY */
|
||||
case 06 : /* DVI */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* DF|word1 points to operand word */
|
||||
if (addr == pc && showOpAtPC) {
|
||||
ad = (addr & 070000) | ((addr + 1) & 07777);
|
||||
d = ((ad & 07770) == 010) ? 1 : 0; /* autoindex? */
|
||||
word1 = ([pdp8 getDF] << 12) | ((word1 + d) & 07777);
|
||||
d = (d && (ad == word1)) ? 1 : 0;
|
||||
/* operand == autoindexed ptr? */
|
||||
p += sprintf(p, " (%4.4o)",
|
||||
([pdp8 memoryAt:word1] + d) & 07777);
|
||||
}
|
||||
break;
|
||||
case 012 : /* SHL */
|
||||
case 014 : /* ASR */
|
||||
case 016 : /* LSR */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* word1 is operand */
|
||||
break;
|
||||
case 042 : /* DAD */
|
||||
case 044 : /* DST */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* DF|word1 points to op double word */
|
||||
/* DAD adds op double word to AC'MQ */
|
||||
/* DST overwrites op dword with AC'MQ */
|
||||
if (addr == pc && showOpAtPC) {
|
||||
ad = (addr & 070000) | ((addr + 1) & 07777);
|
||||
d = ((ad & 07770) == 010) ? 1 : 0; /* autoindex? */
|
||||
word2 = ([pdp8 getDF] << 12) | ((word1 + d + 1) & 07777);
|
||||
word1 = ([pdp8 getDF] << 12) | ((word1 + d) & 07777);
|
||||
e = (d && (ad == word2)) ? 1 : 0;
|
||||
/* operand == autoindexed ptr? */
|
||||
d = (d && (ad == word1)) ? 1 : 0;
|
||||
p += sprintf(p, " (%4.4o%4.4o)",
|
||||
([pdp8 memoryAt:word2] + e) & 07777,
|
||||
([pdp8 memoryAt:word1] + d) & 07777);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*p = '\0'; /* to avoid Xcode analyzer warning */
|
||||
return [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
|
||||
case 07401 : /* EAE */
|
||||
d = (inst & 0377) >> 1 ;
|
||||
if ([pdp8 getEAEmode] == EAE_MODE_A) {
|
||||
[[eaeModeAOpcodes objectAtIndex:d]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
switch (inst & 016) {
|
||||
case 002 : /* SCL */
|
||||
case 004 : /* MUY */
|
||||
case 006 : /* DVI */
|
||||
case 012 : /* SHL */
|
||||
case 014 : /* ASR */
|
||||
case 016 : /* LSR */
|
||||
if (inst != 07447) { /* SWBA */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* word1 is operand */
|
||||
}
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
} else { /* EAE mode B */
|
||||
[[eaeModeBOpcodes objectAtIndex:d]
|
||||
getCString:p maxLength:sizeof(str) encoding:NSASCIIStringEncoding];
|
||||
p += strlen(p);
|
||||
switch (inst & 056) {
|
||||
case 04 : /* MUY */
|
||||
case 06 : /* DVI */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* DF|word1 points to operand word */
|
||||
if (addr == pc && showOpAtPC) {
|
||||
ad = (addr & 070000) | ((addr + 1) & 07777);
|
||||
d = ((ad & 07770) == 010) ? 1 : 0; /* autoindex? */
|
||||
word1 = ([pdp8 getDF] << 12) | ((word1 + d) & 07777);
|
||||
d = (d && (ad == word1)) ? 1 : 0;
|
||||
/* operand == autoindexed ptr? */
|
||||
p += sprintf(p, " (%4.4o)",
|
||||
([pdp8 memoryAt:word1] + d) & 07777);
|
||||
}
|
||||
break;
|
||||
case 012 : /* SHL */
|
||||
case 014 : /* ASR */
|
||||
case 016 : /* LSR */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* word1 is operand */
|
||||
break;
|
||||
case 042 : /* DAD */
|
||||
case 044 : /* DST */
|
||||
p += sprintf(p, " %o", word1);
|
||||
/* DF|word1 points to op double word */
|
||||
/* DAD adds op double word to AC'MQ */
|
||||
/* DST overwrites op dword with AC'MQ */
|
||||
if (addr == pc && showOpAtPC) {
|
||||
ad = (addr & 070000) | ((addr + 1) & 07777);
|
||||
d = ((ad & 07770) == 010) ? 1 : 0; /* autoindex? */
|
||||
word2 = ([pdp8 getDF] << 12) | ((word1 + d + 1) & 07777);
|
||||
word1 = ([pdp8 getDF] << 12) | ((word1 + d) & 07777);
|
||||
e = (d && (ad == word2)) ? 1 : 0;
|
||||
/* operand == autoindexed ptr? */
|
||||
d = (d && (ad == word1)) ? 1 : 0;
|
||||
p += sprintf(p, " (%4.4o%4.4o)",
|
||||
([pdp8 memoryAt:word2] + e) & 07777,
|
||||
([pdp8 memoryAt:word1] + d) & 07777);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
*p = '\0'; /* to avoid Xcode analyzer warning */
|
||||
return [NSString stringWithCString:str encoding:NSASCIIStringEncoding];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) operandInfoForPDP8:(PDP8 *)pdp8 atAddress:(int)addr
|
||||
{
|
||||
NSMutableString *string;
|
||||
int inst, op, ad, oldad, field, d, d1, mark, i;
|
||||
NSMutableString *string;
|
||||
int inst, op, ad, oldad, field, d, d1, mark, i;
|
||||
|
||||
inst = [pdp8 memoryAt:addr];
|
||||
if (inst >= 06000)
|
||||
return nil; /* no MRI */
|
||||
if (05000 <= inst && inst < 05400)
|
||||
return nil; /* direct JMP */
|
||||
ad = ((inst & 0200) ? (addr & 07600) : 0) | (inst & 0177);
|
||||
d = ((inst & 0400) && ad > 07 && ad < 020) ? 1 : 0; /* indirect auto index register access */
|
||||
ad |= addr & 070000;
|
||||
op = ([pdp8 memoryAt:ad] + d) & 07777;
|
||||
string = [NSMutableString stringWithFormat:@"%5.5o: %4.4o", ad, op];
|
||||
if (inst < 05000 && (inst & 0400)) {
|
||||
[string appendString:@"\n\n"];
|
||||
oldad = ad;
|
||||
ad = op;
|
||||
mark = ((inst < 04000) ? [pdp8 getDF] : [pdp8 getIB]) << 12;
|
||||
for (i = 0; i < 4; i++) {
|
||||
field = i << 12;
|
||||
part2 :
|
||||
d1 = (d && oldad == (field | ad)) ? 1 : 0;
|
||||
op = ([pdp8 memoryAt:field | ad] + d1) & 07777;
|
||||
[string appendFormat:@"%5.5o: %4.4o", field | ad, op];
|
||||
if (field == mark)
|
||||
[string appendFormat:@"%C", UNICODE_DIAMOND];
|
||||
if (field & 040000)
|
||||
[string appendString:@"\n"];
|
||||
else {
|
||||
[string appendString:@"\t"];
|
||||
field |= 040000;
|
||||
goto part2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return string;
|
||||
inst = [pdp8 memoryAt:addr];
|
||||
if (inst >= 06000)
|
||||
return nil; /* no MRI */
|
||||
if (05000 <= inst && inst < 05400)
|
||||
return nil; /* direct JMP */
|
||||
ad = ((inst & 0200) ? (addr & 07600) : 0) | (inst & 0177);
|
||||
d = ((inst & 0400) && ad > 07 && ad < 020) ? 1 : 0; /* indirect auto index register access */
|
||||
ad |= addr & 070000;
|
||||
op = ([pdp8 memoryAt:ad] + d) & 07777;
|
||||
string = [NSMutableString stringWithFormat:@"%5.5o: %4.4o", ad, op];
|
||||
if (inst < 05000 && (inst & 0400)) {
|
||||
[string appendString:@"\n\n"];
|
||||
oldad = ad;
|
||||
ad = op;
|
||||
mark = ((inst < 04000) ? [pdp8 getDF] : [pdp8 getIB]) << 12;
|
||||
for (i = 0; i < 4; i++) {
|
||||
field = i << 12;
|
||||
part2 :
|
||||
d1 = (d && oldad == (field | ad)) ? 1 : 0;
|
||||
op = ([pdp8 memoryAt:field | ad] + d1) & 07777;
|
||||
[string appendFormat:@"%5.5o: %4.4o", field | ad, op];
|
||||
if (field == mark)
|
||||
[string appendFormat:@"%C", UNICODE_DIAMOND];
|
||||
if (field & 040000)
|
||||
[string appendString:@"\n"];
|
||||
else {
|
||||
[string appendString:@"\t"];
|
||||
field |= 040000;
|
||||
goto part2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
- (void) addMnemonic:(NSString *)mnemonic forIOT:(int)opcode
|
||||
{
|
||||
NSAssert1 ((opcode & ~00777) == 06000, @"Invalid IOT %o", opcode);
|
||||
[iotOpcodes replaceObjectAtIndex:opcode & 0777 withObject:mnemonic];
|
||||
NSAssert1 ((opcode & ~00777) == 06000, @"Invalid IOT %o", opcode);
|
||||
[iotOpcodes replaceObjectAtIndex:opcode & 0777 withObject:mnemonic];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* FloatingPointNumber.h - Floating point numbers for format conversions
|
||||
* FloatingPointNumber.h - Floating point numbers for format conversions
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -31,139 +31,139 @@
|
|||
|
||||
|
||||
+ (FloatingPointNumber *) floatingPointNumberWithExponent:(int)e bias:(int)b negative:(BOOL)n
|
||||
twoComplementMantissa:(BOOL)tcm mantissa:(unsigned long long)m
|
||||
twoComplementMantissa:(BOOL)tcm mantissa:(unsigned long long)m
|
||||
{
|
||||
return [[[self alloc]
|
||||
initWithExponent:e bias:b negative:n twoComplementMantissa:tcm mantissa:m] autorelease];
|
||||
return [[self alloc]
|
||||
initWithExponent:e bias:b negative:n twoComplementMantissa:tcm mantissa:m];
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (FloatingPointNumber *) floatingPointNumberFromString:(NSString *)string
|
||||
withBias:(int)bias withTwoComplementMantissa:(BOOL)tcm error:(NSString **)error
|
||||
withBias:(int)bias withTwoComplementMantissa:(BOOL)tcm error:(NSString **)error
|
||||
{
|
||||
decimal dec;
|
||||
short ok;
|
||||
int exponent;
|
||||
BOOL negative;
|
||||
unsigned long long mantissa;
|
||||
|
||||
const char *p = [string cStringUsingEncoding:NSMacOSRomanStringEncoding];
|
||||
short ix = 0;
|
||||
str2dec (p, &ix, &dec, &ok);
|
||||
if (! ok) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"Invalid floating point number.", @"");
|
||||
return nil;
|
||||
}
|
||||
double d = dec2num(&dec);
|
||||
if (! isfinite(d)) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"IEEE overflow.", @"");
|
||||
return nil;
|
||||
}
|
||||
if (d != 0.0 && ! isnormal(d)) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"IEEE underflow.", @"");
|
||||
return nil;
|
||||
}
|
||||
if (d < 0.0) {
|
||||
negative = YES;
|
||||
d = -d;
|
||||
} else
|
||||
negative = NO;
|
||||
d = frexp(d, &exponent);
|
||||
mantissa = (unsigned long long) ldexp(d, 64);
|
||||
if (bias) {
|
||||
if (d != 0.0)
|
||||
exponent += bias;
|
||||
if (exponent < 0 || 2 * bias <= exponent) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"Floating point number out of range.", @"");
|
||||
return nil;
|
||||
}
|
||||
} else { // exponent must be a 12-bit two complement integer
|
||||
if ((exponent & ~07777) != 0 && (exponent & ~07777) != ~07777) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"Floating point number out of range.", @"");
|
||||
return nil;
|
||||
} else
|
||||
exponent &= 07777;
|
||||
}
|
||||
if (negative && tcm)
|
||||
mantissa = ~mantissa + 1;
|
||||
return [FloatingPointNumber floatingPointNumberWithExponent:exponent
|
||||
bias:bias negative:negative twoComplementMantissa:tcm mantissa:mantissa];
|
||||
decimal dec;
|
||||
short ok;
|
||||
int exponent;
|
||||
BOOL negative;
|
||||
unsigned long long mantissa;
|
||||
|
||||
const char *p = [string cStringUsingEncoding:NSMacOSRomanStringEncoding];
|
||||
short ix = 0;
|
||||
str2dec (p, &ix, &dec, &ok);
|
||||
if (! ok) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"Invalid floating point number.", @"");
|
||||
return nil;
|
||||
}
|
||||
double d = dec2num(&dec);
|
||||
if (! isfinite(d)) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"IEEE overflow.", @"");
|
||||
return nil;
|
||||
}
|
||||
if (d != 0.0 && ! isnormal(d)) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"IEEE underflow.", @"");
|
||||
return nil;
|
||||
}
|
||||
if (d < 0.0) {
|
||||
negative = YES;
|
||||
d = -d;
|
||||
} else
|
||||
negative = NO;
|
||||
d = frexp(d, &exponent);
|
||||
mantissa = (unsigned long long) ldexp(d, 64);
|
||||
if (bias) {
|
||||
if (d != 0.0)
|
||||
exponent += bias;
|
||||
if (exponent < 0 || 2 * bias <= exponent) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"Floating point number out of range.", @"");
|
||||
return nil;
|
||||
}
|
||||
} else { // exponent must be a 12-bit two complement integer
|
||||
if ((exponent & ~07777) != 0 && (exponent & ~07777) != ~07777) {
|
||||
if (error)
|
||||
*error = NSLocalizedString(@"Floating point number out of range.", @"");
|
||||
return nil;
|
||||
} else
|
||||
exponent &= 07777;
|
||||
}
|
||||
if (negative && tcm)
|
||||
mantissa = ~mantissa + 1;
|
||||
return [FloatingPointNumber floatingPointNumberWithExponent:exponent
|
||||
bias:bias negative:negative twoComplementMantissa:tcm mantissa:mantissa];
|
||||
}
|
||||
|
||||
|
||||
- (FloatingPointNumber *) initWithExponent:(int)e bias:(int)b negative:(BOOL)n
|
||||
twoComplementMantissa:(BOOL)tcm mantissa:(unsigned long long)m
|
||||
twoComplementMantissa:(BOOL)tcm mantissa:(unsigned long long)m
|
||||
{
|
||||
self = [super init];
|
||||
exponent = e;
|
||||
bias = b;
|
||||
negative = n;
|
||||
twoComplementMantissa = tcm;
|
||||
mantissa = m;
|
||||
return self;
|
||||
self = [super init];
|
||||
exponent = e;
|
||||
bias = b;
|
||||
negative = n;
|
||||
twoComplementMantissa = tcm;
|
||||
mantissa = m;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) stringValueWithPrecision:(int)precision
|
||||
{
|
||||
if (exponent == 0 && mantissa == 0)
|
||||
return @"0.0";
|
||||
unsigned long long mant = (negative && twoComplementMantissa) ? (~mantissa + 1) : mantissa;
|
||||
if ((mant >> 63) == 0)
|
||||
return NSLocalizedString(@"(not normalized)", @"");
|
||||
double d = ldexp((double) mant, -64);
|
||||
if (negative)
|
||||
d = -d;
|
||||
int exp = exponent;
|
||||
if (bias)
|
||||
exp -= bias;
|
||||
else {
|
||||
if (exp == 04000) /* exponent -0 */
|
||||
exp = 0;
|
||||
if (exp & 04000) /* negative 12-bit two complement exponent */
|
||||
exp |= ~07777;
|
||||
}
|
||||
d = ldexp(d, exp);
|
||||
if (! isfinite(d))
|
||||
return NSLocalizedString(@"(IEEE overflow)", @"");
|
||||
if (! isnormal(d))
|
||||
return NSLocalizedString(@"(IEEE underflow)", @"");
|
||||
return [NSString stringWithFormat:@"%.*g", precision, d];
|
||||
if (exponent == 0 && mantissa == 0)
|
||||
return @"0.0";
|
||||
unsigned long long mant = (negative && twoComplementMantissa) ? (~mantissa + 1) : mantissa;
|
||||
if ((mant >> 63) == 0)
|
||||
return NSLocalizedString(@"(not normalized)", @"");
|
||||
double d = ldexp((double) mant, -64);
|
||||
if (negative)
|
||||
d = -d;
|
||||
int exp = exponent;
|
||||
if (bias)
|
||||
exp -= bias;
|
||||
else {
|
||||
if (exp == 04000) /* exponent -0 */
|
||||
exp = 0;
|
||||
if (exp & 04000) /* negative 12-bit two complement exponent */
|
||||
exp |= ~07777;
|
||||
}
|
||||
d = ldexp(d, exp);
|
||||
if (! isfinite(d))
|
||||
return NSLocalizedString(@"(IEEE overflow)", @"");
|
||||
if (! isnormal(d))
|
||||
return NSLocalizedString(@"(IEEE underflow)", @"");
|
||||
return [NSString stringWithFormat:@"%.*g", precision, d];
|
||||
}
|
||||
|
||||
|
||||
- (int) exponent
|
||||
{
|
||||
return exponent;
|
||||
return exponent;
|
||||
}
|
||||
|
||||
|
||||
- (int) bias
|
||||
{
|
||||
return bias;
|
||||
return bias;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) negative
|
||||
{
|
||||
return negative;
|
||||
return negative;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) twoComplementMantissa
|
||||
{
|
||||
return twoComplementMantissa;
|
||||
return twoComplementMantissa;
|
||||
}
|
||||
|
||||
|
||||
- (unsigned long long) mantissa
|
||||
{
|
||||
return mantissa;
|
||||
return mantissa;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* OctalFormatter.m - Formatter for octal numbers
|
||||
* OctalFormatter.m - Formatter for octal numbers
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,52 +32,52 @@
|
|||
|
||||
+ (OctalFormatter *) formatterWithBitMask:(unsigned)mask wildcardAllowed:(BOOL)withWildcard
|
||||
{
|
||||
return [[[OctalFormatter alloc] initWithBitMask:mask wildcardAllowed:withWildcard] autorelease];
|
||||
return [[OctalFormatter alloc] initWithBitMask:mask wildcardAllowed:withWildcard];
|
||||
}
|
||||
|
||||
|
||||
- (OctalFormatter *) initWithBitMask:(unsigned)mask wildcardAllowed:(BOOL)withWildcard
|
||||
{
|
||||
if ((self = [super init])) {
|
||||
wildcardAllowed = withWildcard;
|
||||
bitMask = mask;
|
||||
int digits = 0;
|
||||
while (mask) {
|
||||
digits++;
|
||||
mask >>= 3;
|
||||
}
|
||||
outputFormat = [[NSString alloc] initWithFormat:@"%%%d.%do", digits, digits];
|
||||
numberOfWords = 1;
|
||||
}
|
||||
return self;
|
||||
if ((self = [super init])) {
|
||||
wildcardAllowed = withWildcard;
|
||||
bitMask = mask;
|
||||
int digits = 0;
|
||||
while (mask) {
|
||||
digits++;
|
||||
mask >>= 3;
|
||||
}
|
||||
outputFormat = [[NSString alloc] initWithFormat:@"%%%d.%do", digits, digits];
|
||||
numberOfWords = 1;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void) setNumberOfWords:(unsigned)n
|
||||
{
|
||||
numberOfWords = n;
|
||||
numberOfWords = n;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) stringForObjectValue:(id)value
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
NSMutableString *string = nil;
|
||||
if ([value isKindOfClass:[NSNumber class]])
|
||||
string = [NSMutableString stringWithFormat:outputFormat, [value intValue]];
|
||||
else if ([value isKindOfClass:[NSArray class]]) {
|
||||
NSUInteger count = [value count];
|
||||
if (numberOfWords < count)
|
||||
count = numberOfWords;
|
||||
string = [NSMutableString stringWithCapacity:5 * count];
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i > 0)
|
||||
[string appendString:@" "];
|
||||
[string appendFormat:outputFormat, [[value objectAtIndex:i] intValue]];
|
||||
}
|
||||
}
|
||||
return string;
|
||||
unsigned i;
|
||||
|
||||
NSMutableString *string = nil;
|
||||
if ([value isKindOfClass:[NSNumber class]])
|
||||
string = [NSMutableString stringWithFormat:outputFormat, [value intValue]];
|
||||
else if ([value isKindOfClass:[NSArray class]]) {
|
||||
NSUInteger count = [value count];
|
||||
if (numberOfWords < count)
|
||||
count = numberOfWords;
|
||||
string = [NSMutableString stringWithCapacity:5 * count];
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i > 0)
|
||||
[string appendString:@" "];
|
||||
[string appendFormat:outputFormat, [[value objectAtIndex:i] intValue]];
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,72 +87,72 @@
|
|||
an asencding sorted NSArray of NSNumbers (for numberOfWords == 1) or an NSArray of such NSArrays
|
||||
(for numberOfWords > 1). */
|
||||
{
|
||||
char buf[128];
|
||||
char *bp = buf;
|
||||
NSMutableArray *values = [NSMutableArray arrayWithCapacity:numberOfWords];
|
||||
if (! [string getCString:buf maxLength:(sizeof(buf) - 1) encoding:NSMacOSRomanStringEncoding]) {
|
||||
if (error)
|
||||
*error = [string canBeConvertedToEncoding:NSMacOSRomanStringEncoding] ?
|
||||
NSLocalizedString(@"Input too long.", @"") :
|
||||
NSLocalizedString(@"Input contains invalid characters.", @"");
|
||||
return FALSE;
|
||||
}
|
||||
while (*bp == ' ')
|
||||
bp++;
|
||||
while (('0' <= *bp && *bp < '8') || (wildcardAllowed && *bp == '#')) {
|
||||
unsigned val = 0;
|
||||
unsigned pattern = 0;
|
||||
while (('0' <= *bp && *bp < '8') || (wildcardAllowed && *bp == '#')) {
|
||||
pattern <<= 3;
|
||||
if ('0' <= *bp && *bp < '8')
|
||||
val = val * 8 + (*bp - '0');
|
||||
else {
|
||||
val *= 8;
|
||||
pattern |= 7;
|
||||
}
|
||||
bp++;
|
||||
}
|
||||
while (*bp == ' ')
|
||||
bp++;
|
||||
if ((val | pattern) & ~bitMask) {
|
||||
if (error)
|
||||
*error = [NSString stringWithFormat:NSLocalizedString(
|
||||
@"The octal number is of range. The largest allowed number is %o.",
|
||||
@""), bitMask];
|
||||
return FALSE;
|
||||
}
|
||||
if (pattern) {
|
||||
unsigned long mask = pattern;
|
||||
NSMutableArray *patternValues = [NSMutableArray arrayWithCapacity:8];
|
||||
do {
|
||||
[patternValues insertObject:[NSNumber numberWithInt:val + pattern]
|
||||
atIndex:0];
|
||||
pattern = (pattern - 1) & mask;
|
||||
} while (pattern != mask);
|
||||
[values addObject:patternValues];
|
||||
} else
|
||||
[values addObject:[NSNumber numberWithInt:val]];
|
||||
}
|
||||
if (*bp || [values count] != numberOfWords) {
|
||||
if (error)
|
||||
*error = (numberOfWords == 1) ?
|
||||
(wildcardAllowed ?
|
||||
NSLocalizedString(
|
||||
@"Invalid input. An octal number is expected. "
|
||||
@"The wildcard character # is allowed.", @"") :
|
||||
NSLocalizedString(
|
||||
@"Invalid input. An octal number is expected.", @"")) :
|
||||
[NSString stringWithFormat:wildcardAllowed ?
|
||||
NSLocalizedString(
|
||||
@"Invalid input. %d octal numbers are expected. "
|
||||
@"The wildcard character # is allowed.", @"") :
|
||||
NSLocalizedString(
|
||||
@"Invalid input. %d octal numbers are expected.", @""),
|
||||
numberOfWords];
|
||||
return FALSE;
|
||||
}
|
||||
*value = (numberOfWords == 1) ? [values objectAtIndex:0] : values;
|
||||
return TRUE;
|
||||
char buf[128];
|
||||
char *bp = buf;
|
||||
NSMutableArray *values = [NSMutableArray arrayWithCapacity:numberOfWords];
|
||||
if (! [string getCString:buf maxLength:(sizeof(buf) - 1) encoding:NSMacOSRomanStringEncoding]) {
|
||||
if (error)
|
||||
*error = [string canBeConvertedToEncoding:NSMacOSRomanStringEncoding] ?
|
||||
NSLocalizedString(@"Input too long.", @"") :
|
||||
NSLocalizedString(@"Input contains invalid characters.", @"");
|
||||
return FALSE;
|
||||
}
|
||||
while (*bp == ' ')
|
||||
bp++;
|
||||
while (('0' <= *bp && *bp < '8') || (wildcardAllowed && *bp == '#')) {
|
||||
unsigned val = 0;
|
||||
unsigned pattern = 0;
|
||||
while (('0' <= *bp && *bp < '8') || (wildcardAllowed && *bp == '#')) {
|
||||
pattern <<= 3;
|
||||
if ('0' <= *bp && *bp < '8')
|
||||
val = val * 8 + (*bp - '0');
|
||||
else {
|
||||
val *= 8;
|
||||
pattern |= 7;
|
||||
}
|
||||
bp++;
|
||||
}
|
||||
while (*bp == ' ')
|
||||
bp++;
|
||||
if ((val | pattern) & ~bitMask) {
|
||||
if (error)
|
||||
*error = [NSString stringWithFormat:NSLocalizedString(
|
||||
@"The octal number is of range. The largest allowed number is %o.",
|
||||
@""), bitMask];
|
||||
return FALSE;
|
||||
}
|
||||
if (pattern) {
|
||||
unsigned long mask = pattern;
|
||||
NSMutableArray *patternValues = [NSMutableArray arrayWithCapacity:8];
|
||||
do {
|
||||
[patternValues insertObject:[NSNumber numberWithInt:val + pattern]
|
||||
atIndex:0];
|
||||
pattern = (pattern - 1) & mask;
|
||||
} while (pattern != mask);
|
||||
[values addObject:patternValues];
|
||||
} else
|
||||
[values addObject:[NSNumber numberWithInt:val]];
|
||||
}
|
||||
if (*bp || [values count] != numberOfWords) {
|
||||
if (error)
|
||||
*error = (numberOfWords == 1) ?
|
||||
(wildcardAllowed ?
|
||||
NSLocalizedString(
|
||||
@"Invalid input. An octal number is expected. "
|
||||
@"The wildcard character # is allowed.", @"") :
|
||||
NSLocalizedString(
|
||||
@"Invalid input. An octal number is expected.", @"")) :
|
||||
[NSString stringWithFormat:wildcardAllowed ?
|
||||
NSLocalizedString(
|
||||
@"Invalid input. %d octal numbers are expected. "
|
||||
@"The wildcard character # is allowed.", @"") :
|
||||
NSLocalizedString(
|
||||
@"Invalid input. %d octal numbers are expected.", @""),
|
||||
numberOfWords];
|
||||
return FALSE;
|
||||
}
|
||||
*value = (numberOfWords == 1) ? [values objectAtIndex:0] : values;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* Opcode.m - Class representing a PDP-8 opcode
|
||||
* Opcode.m - Class representing a PDP-8 opcode
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -32,72 +32,72 @@
|
|||
|
||||
+ (Opcode *) opcodeWithAddress:(int)addr
|
||||
{
|
||||
return [[[self alloc] initWithAddress:addr] autorelease];
|
||||
return [[self alloc] initWithAddress:addr];
|
||||
}
|
||||
|
||||
|
||||
+ (Opcode *) opcodeWithAddress:(int)addr value:(int)value
|
||||
{
|
||||
return [[[self alloc] initWithAddress:addr value:value] autorelease];
|
||||
return [[self alloc] initWithAddress:addr value:value];
|
||||
}
|
||||
|
||||
|
||||
- (id) copyWithZone:(NSZone *)zone
|
||||
{
|
||||
Opcode *new = [[Opcode alloc] initWithAddress:address];
|
||||
|
||||
new->word0 = word0;
|
||||
new->word1 = word1;
|
||||
return new;
|
||||
Opcode *new = [[Opcode alloc] initWithAddress:address];
|
||||
|
||||
new->word0 = word0;
|
||||
new->word1 = word1;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
||||
- (Opcode *) initWithAddress:(int)addr
|
||||
{
|
||||
self = [super init];
|
||||
address = addr;
|
||||
word0 = word1 = -1;
|
||||
return self;
|
||||
self = [super init];
|
||||
address = addr;
|
||||
word0 = word1 = -1;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (Opcode *) initWithAddress:(int)addr value:(int)value
|
||||
{
|
||||
self = [super init];
|
||||
address = addr;
|
||||
word0 = value;
|
||||
word1 = -1;
|
||||
return self;
|
||||
self = [super init];
|
||||
address = addr;
|
||||
word0 = value;
|
||||
word1 = -1;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (int) address
|
||||
{
|
||||
return address;
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
- (int) word0
|
||||
{
|
||||
return word0;
|
||||
return word0;
|
||||
}
|
||||
|
||||
|
||||
- (void) setWord0:(int)w0
|
||||
{
|
||||
word0 = w0;
|
||||
word0 = w0;
|
||||
}
|
||||
|
||||
|
||||
- (int) word1
|
||||
{
|
||||
return word1;
|
||||
return word1;
|
||||
}
|
||||
|
||||
|
||||
- (void) setWord1:(int)w1
|
||||
{
|
||||
word1 = w1;
|
||||
word1 = w1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* OpcodeFormatter.m - Formatter for the Opcode column of the CPU window
|
||||
* OpcodeFormatter.m - Formatter for the Opcode column of the CPU window
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -35,43 +35,43 @@
|
|||
|
||||
+ (OpcodeFormatter *) formatterWithPDP8:(PDP8 *)p8 addressGetter:(id <OpcodeFormatterAddressGetter>)addrGetter
|
||||
{
|
||||
return [[[OpcodeFormatter alloc] initWithPDP8:p8 addressGetter:addrGetter] autorelease];
|
||||
return [[OpcodeFormatter alloc] initWithPDP8:p8 addressGetter:addrGetter];
|
||||
}
|
||||
|
||||
|
||||
- (OpcodeFormatter *) initWithPDP8:(PDP8 *)p8 addressGetter:(id <OpcodeFormatterAddressGetter>)addrGetter;
|
||||
{
|
||||
pdp8 = p8;
|
||||
addressGetter = addrGetter;
|
||||
return self;
|
||||
pdp8 = p8;
|
||||
addressGetter = addrGetter;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) stringForObjectValue:(Opcode *)opcode
|
||||
{
|
||||
// with Leopard, the formatter is called once for a Text Cell - don't know why
|
||||
if (! [opcode isKindOfClass:[Opcode class]])
|
||||
return nil;
|
||||
return [[Disassembler sharedDisassembler] disassembleOpcodeForPDP8:pdp8
|
||||
atAddress:[opcode address] showOperandsAtPC:TRUE];
|
||||
// with Leopard, the formatter is called once for a Text Cell - don't know why
|
||||
if (! [opcode isKindOfClass:[Opcode class]])
|
||||
return nil;
|
||||
return [[Disassembler sharedDisassembler] disassembleOpcodeForPDP8:pdp8
|
||||
atAddress:[opcode address] showOperandsAtPC:TRUE];
|
||||
}
|
||||
|
||||
|
||||
- (NSString *) editingStringForObjectValue:(Opcode *)opcode
|
||||
{
|
||||
// with Yosemite, after typing invalid input, this method is called with the invalid string, not with an Opcode
|
||||
if ([opcode isKindOfClass:[NSString class]])
|
||||
return (NSString *) opcode;
|
||||
return [[Disassembler sharedDisassembler] disassembleOpcodeForPDP8:pdp8
|
||||
atAddress:[opcode address] showOperandsAtPC:FALSE];
|
||||
// with Yosemite, after typing invalid input, this method is called with the invalid string, not with an Opcode
|
||||
if ([opcode isKindOfClass:[NSString class]])
|
||||
return (NSString *) opcode;
|
||||
return [[Disassembler sharedDisassembler] disassembleOpcodeForPDP8:pdp8
|
||||
atAddress:[opcode address] showOperandsAtPC:FALSE];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) getObjectValue:(Opcode **)opcode forString:(NSString *)string errorDescription:(NSString **)error
|
||||
- (BOOL) getObjectValue:(id *)opcode forString:(NSString *)string errorDescription:(NSString **)error
|
||||
{
|
||||
*opcode = [[Assembler sharedAssembler]
|
||||
assemble:string atAddress:[addressGetter getCurrentAddress] error:error];
|
||||
return *opcode != nil;
|
||||
*(Opcode **)opcode = [[Assembler sharedAssembler]
|
||||
assemble:string atAddress:[addressGetter getCurrentAddress] error:error];
|
||||
return *opcode != nil;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import "FileDropControlTargetProtocol.h"
|
||||
|
||||
@protocol InputConsumer;
|
||||
@class PaperTapeProgressIndicator, EnableDisableTextField;
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* PaperTapeController.m - Controller for a paper tape reader and punch
|
||||
* PaperTapeController.m - Controller for a paper tape reader and punch
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -38,180 +38,177 @@
|
|||
@implementation PaperTapeController
|
||||
|
||||
|
||||
#define PAPER_TAPE_ON_TAG 0
|
||||
#define PAPER_TAPE_OFF_TAG 1
|
||||
#define PAPER_TAPE_ON_TAG 0
|
||||
#define PAPER_TAPE_OFF_TAG 1
|
||||
|
||||
#define PAPER_TAPE_READER 0
|
||||
#define PAPER_TAPE_PUNCH 1
|
||||
#define PAPER_TAPE_READER 0
|
||||
#define PAPER_TAPE_PUNCH 1
|
||||
|
||||
|
||||
- (void) setEnabled:(BOOL)flag
|
||||
{
|
||||
[loadUnloadButton setEnabled:flag];
|
||||
[filenameField setEnabled:flag];
|
||||
if (onOffButton)
|
||||
[onOffButton setEnabled:flag && fileHandle != nil];
|
||||
[loadUnloadButton setEnabled:flag];
|
||||
[filenameField setEnabled:flag];
|
||||
if (onOffButton)
|
||||
[onOffButton setEnabled:flag && fileHandle != nil];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (int) getChar
|
||||
{
|
||||
NSAssert (kind == PAPER_TAPE_READER, @"Cannot read from paper tape punch");
|
||||
int c = EOF;
|
||||
if (fileHandle) {
|
||||
if (onOffButton == nil || [onOffButton selectedSegment] == PAPER_TAPE_ON_TAG) {
|
||||
NSData *data = [fileHandle readDataOfLength:1];
|
||||
if ([data length] == 1) {
|
||||
c = * (unsigned char *) [data bytes];
|
||||
if ([NSThread isMainThread])
|
||||
[progressIndicator incrementAndAnimate];
|
||||
else
|
||||
[progressIndicator
|
||||
performSelectorOnMainThread:@selector(incrementAndAnimate)
|
||||
withObject:self waitUntilDone:NO];
|
||||
} else {
|
||||
if ([NSThread isMainThread])
|
||||
[self loadUnloadClicked:self];
|
||||
else
|
||||
[self performSelectorOnMainThread:@selector(loadUnloadClicked:)
|
||||
withObject:self waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
NSAssert (kind == PAPER_TAPE_READER, @"Cannot read from paper tape punch");
|
||||
int c = EOF;
|
||||
if (fileHandle) {
|
||||
if (onOffButton == nil || [onOffButton selectedSegment] == PAPER_TAPE_ON_TAG) {
|
||||
NSData *data = [fileHandle readDataOfLength:1];
|
||||
if ([data length] == 1) {
|
||||
c = * (unsigned char *) [data bytes];
|
||||
if ([NSThread isMainThread])
|
||||
[progressIndicator incrementAndAnimate];
|
||||
else
|
||||
[progressIndicator
|
||||
performSelectorOnMainThread:@selector(incrementAndAnimate)
|
||||
withObject:self waitUntilDone:NO];
|
||||
} else {
|
||||
if ([NSThread isMainThread])
|
||||
[self loadUnloadClicked:self];
|
||||
else
|
||||
[self performSelectorOnMainThread:@selector(loadUnloadClicked:)
|
||||
withObject:self waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) putChar:(unsigned char)c handleBackspace:(BOOL)handleBackspace
|
||||
{
|
||||
NSAssert (kind == PAPER_TAPE_PUNCH, @"Cannot punch to paper tape reader");
|
||||
BOOL done = NO;
|
||||
if (fileHandle && (onOffButton == nil || [onOffButton selectedSegment] == PAPER_TAPE_ON_TAG)) {
|
||||
if (c == '\b' && handleBackspace) {
|
||||
long size = (long) [fileHandle offsetInFile];
|
||||
if (size > 0)
|
||||
[fileHandle truncateFileAtOffset:size - 1];
|
||||
} else
|
||||
[fileHandle writeData:[NSData dataWithBytes:&c length:1]];
|
||||
if ([NSThread isMainThread])
|
||||
[progressIndicator incrementAndAnimate];
|
||||
else
|
||||
[progressIndicator
|
||||
performSelectorOnMainThread:@selector(incrementAndAnimate)
|
||||
withObject:self waitUntilDone:NO];
|
||||
done = YES;
|
||||
}
|
||||
return done;
|
||||
NSAssert (kind == PAPER_TAPE_PUNCH, @"Cannot punch to paper tape reader");
|
||||
BOOL done = NO;
|
||||
if (fileHandle && (onOffButton == nil || [onOffButton selectedSegment] == PAPER_TAPE_ON_TAG)) {
|
||||
if (c == '\b' && handleBackspace) {
|
||||
long size = (long) [fileHandle offsetInFile];
|
||||
if (size > 0)
|
||||
[fileHandle truncateFileAtOffset:size - 1];
|
||||
} else
|
||||
[fileHandle writeData:[NSData dataWithBytes:&c length:1]];
|
||||
if ([NSThread isMainThread])
|
||||
[progressIndicator incrementAndAnimate];
|
||||
else
|
||||
[progressIndicator
|
||||
performSelectorOnMainThread:@selector(incrementAndAnimate)
|
||||
withObject:self waitUntilDone:NO];
|
||||
done = YES;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
- (void) mountFile:(NSFileHandle *)handle withPath:(NSString *)path
|
||||
{
|
||||
fileHandle = handle;
|
||||
[fileHandle retain];
|
||||
[fileHandle seekToEndOfFile];
|
||||
unsigned long long offset = [fileHandle offsetInFile];
|
||||
[fileHandle seekToFileOffset:0];
|
||||
[progressIndicator setMaxValue:offset];
|
||||
[progressIndicator setDoubleValue:0];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *title = NSLocalizedStringFromTableInBundle(@"Unload", nil, bundle, @"");
|
||||
if ([loadUnloadButton class] == [NSSegmentedControl class])
|
||||
[(NSSegmentedControl *) loadUnloadButton setLabel:title forSegment:0];
|
||||
else
|
||||
[(NSButton *) loadUnloadButton setTitle:title];
|
||||
[loadUnloadButton unregisterAsFileDropTarget];
|
||||
if (onOffButton)
|
||||
[onOffButton setEnabled:YES];
|
||||
[filenameField setStringValue:[[NSFileManager defaultManager] displayNameAtPath:path]];
|
||||
[filenameField setHidden:NO];
|
||||
[progressIndicator setHidden:NO];
|
||||
fileHandle = handle;
|
||||
[fileHandle seekToEndOfFile];
|
||||
unsigned long long offset = [fileHandle offsetInFile];
|
||||
[fileHandle seekToFileOffset:0];
|
||||
[progressIndicator setMaxValue:offset];
|
||||
[progressIndicator setDoubleValue:0];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *title = NSLocalizedStringFromTableInBundle(@"Unload", nil, bundle, @"");
|
||||
if ([loadUnloadButton class] == [NSSegmentedControl class])
|
||||
[(NSSegmentedControl *) loadUnloadButton setLabel:title forSegment:0];
|
||||
else
|
||||
[(NSButton *) loadUnloadButton setTitle:title];
|
||||
[loadUnloadButton unregisterAsFileDropTarget];
|
||||
if (onOffButton)
|
||||
[onOffButton setEnabled:YES];
|
||||
[filenameField setStringValue:[[NSFileManager defaultManager] displayNameAtPath:path]];
|
||||
[filenameField setHidden:NO];
|
||||
[progressIndicator setHidden:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void) panelDidEnd:(NSSavePanel *)panel result:(NSModalResponse)result
|
||||
{
|
||||
NSFileHandle *handle;
|
||||
|
||||
if (result == NSModalResponseOK) {
|
||||
NSString *path = [[panel URL] path];
|
||||
if (kind == PAPER_TAPE_READER)
|
||||
handle = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
else {
|
||||
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
|
||||
handle = [NSFileHandle fileHandleForWritingAtPath:path];
|
||||
}
|
||||
if (handle)
|
||||
[self mountFile:handle withPath:path];
|
||||
else {
|
||||
[panel close];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:(kind == PAPER_TAPE_READER) ?
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot open this paper tape file.", nil, bundle, @"") :
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot create this paper tape file.", nil, bundle, @"")];
|
||||
[alert setInformativeText:path];
|
||||
NSFileHandle *handle;
|
||||
|
||||
if (result == NSModalResponseOK) {
|
||||
NSString *path = [[panel URL] path];
|
||||
if (kind == PAPER_TAPE_READER)
|
||||
handle = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
else {
|
||||
[[NSFileManager defaultManager] createFileAtPath:path contents:nil attributes:nil];
|
||||
handle = [NSFileHandle fileHandleForWritingAtPath:path];
|
||||
}
|
||||
if (handle)
|
||||
[self mountFile:handle withPath:path];
|
||||
else {
|
||||
[panel close];
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:(kind == PAPER_TAPE_READER) ?
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot open this paper tape file.", nil, bundle, @"") :
|
||||
NSLocalizedStringFromTableInBundle(
|
||||
@"Cannot create this paper tape file.", nil, bundle, @"")];
|
||||
[alert setInformativeText:path];
|
||||
[alert beginSheetModalForWindow:[loadUnloadButton window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
[alert release];
|
||||
}
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
}
|
||||
}
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[[panel directoryURL] path] forKey:LAST_FILE_PANEL_DIR_KEY];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) loadUnloadClicked:(id)sender
|
||||
{
|
||||
if (fileHandle) {
|
||||
[fileHandle closeFile];
|
||||
[fileHandle release];
|
||||
fileHandle = nil;
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *title = NSLocalizedStringFromTableInBundle(@"Load", nil, bundle, @"");
|
||||
if ([loadUnloadButton class] == [NSSegmentedControl class])
|
||||
[(NSSegmentedControl *) loadUnloadButton setLabel:title forSegment:0];
|
||||
else
|
||||
[(NSButton *) loadUnloadButton setTitle:title];
|
||||
[loadUnloadButton setEnabled:onOffButton == nil ||[onOffButton isEnabled]];
|
||||
[loadUnloadButton registerAsFileDropTarget];
|
||||
if (onOffButton) {
|
||||
[onOffButton setEnabled:NO];
|
||||
[onOffButton selectSegmentWithTag:PAPER_TAPE_OFF_TAG];
|
||||
}
|
||||
[filenameField setHidden:YES];
|
||||
[progressIndicator setHidden:YES];
|
||||
} else {
|
||||
if (fileHandle) {
|
||||
[fileHandle closeFile];
|
||||
fileHandle = nil;
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSString *title = NSLocalizedStringFromTableInBundle(@"Load", nil, bundle, @"");
|
||||
if ([loadUnloadButton class] == [NSSegmentedControl class])
|
||||
[(NSSegmentedControl *) loadUnloadButton setLabel:title forSegment:0];
|
||||
else
|
||||
[(NSButton *) loadUnloadButton setTitle:title];
|
||||
[loadUnloadButton setEnabled:onOffButton == nil ||[onOffButton isEnabled]];
|
||||
[loadUnloadButton registerAsFileDropTarget];
|
||||
if (onOffButton) {
|
||||
[onOffButton setEnabled:NO];
|
||||
[onOffButton selectSegmentWithTag:PAPER_TAPE_OFF_TAG];
|
||||
}
|
||||
[filenameField setHidden:YES];
|
||||
[progressIndicator setHidden:YES];
|
||||
} else {
|
||||
NSSavePanel *panel = (kind == PAPER_TAPE_READER) ? [NSOpenPanel openPanel] : [NSSavePanel savePanel];
|
||||
[panel setDirectoryURL: [NSURL fileURLWithPath:[[NSUserDefaults standardUserDefaults] stringForKey:LAST_FILE_PANEL_DIR_KEY] isDirectory: YES]];
|
||||
[panel beginSheetModalForWindow:[loadUnloadButton window]
|
||||
completionHandler:^(NSModalResponse result) {
|
||||
[self panelDidEnd:panel result:result];
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) onOffClicked:(id)sender
|
||||
{
|
||||
if ([onOffButton selectedSegment] == PAPER_TAPE_ON_TAG) {
|
||||
[loadUnloadButton setEnabled:NO];
|
||||
if (kind == PAPER_TAPE_READER)
|
||||
[inputConsumer canContinueInput];
|
||||
} else {
|
||||
[loadUnloadButton setEnabled:YES];
|
||||
[progressIndicator stopAnimation:sender];
|
||||
}
|
||||
if ([onOffButton selectedSegment] == PAPER_TAPE_ON_TAG) {
|
||||
[loadUnloadButton setEnabled:NO];
|
||||
if (kind == PAPER_TAPE_READER)
|
||||
[inputConsumer canContinueInput];
|
||||
} else {
|
||||
[loadUnloadButton setEnabled:YES];
|
||||
[progressIndicator stopAnimation:sender];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) awakeFromNib
|
||||
{
|
||||
kind = (int)([loadUnloadButton tag]);
|
||||
adjustToolbarControlForTiger (filenameField);
|
||||
adjustToolbarControlForTiger (progressIndicator);
|
||||
[loadUnloadButton registerAsFileDropTarget];
|
||||
kind = (int)([loadUnloadButton tag]);
|
||||
adjustToolbarControlForTiger (filenameField);
|
||||
adjustToolbarControlForTiger (progressIndicator);
|
||||
[loadUnloadButton registerAsFileDropTarget];
|
||||
}
|
||||
|
||||
|
||||
|
@ -220,45 +217,44 @@
|
|||
|
||||
- (BOOL) willAcceptFile:(NSString *)path
|
||||
{
|
||||
NSFileHandle *handle = (kind == PAPER_TAPE_READER) ?
|
||||
[NSFileHandle fileHandleForReadingAtPath:path] :
|
||||
[NSFileHandle fileHandleForWritingAtPath:path];
|
||||
if (handle) {
|
||||
[handle closeFile];
|
||||
// [handle release]; // dont'd release, it crashs
|
||||
}
|
||||
return handle != nil;
|
||||
NSFileHandle *handle = (kind == PAPER_TAPE_READER) ?
|
||||
[NSFileHandle fileHandleForReadingAtPath:path] :
|
||||
[NSFileHandle fileHandleForWritingAtPath:path];
|
||||
if (handle) {
|
||||
[handle closeFile];
|
||||
// [handle release]; // dont'd release, it crashs
|
||||
}
|
||||
return handle != nil;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) acceptFile:(NSString *)path
|
||||
{
|
||||
NSFileHandle *handle = nil;
|
||||
if (kind == PAPER_TAPE_PUNCH) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(
|
||||
@"Do you really want to overwrite %C%@%C with the paper tape output?",
|
||||
nil, bundle, @""),
|
||||
UNICODE_LEFT_DOUBLEQUOTE,
|
||||
[[NSFileManager defaultManager] displayNameAtPath:path],
|
||||
UNICODE_RIGHT_DOUBLEQUOTE]];
|
||||
[alert setInformativeText:NSLocalizedStringFromTableInBundle(
|
||||
@"The current content of the file will be lost.", nil, bundle, @"")];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(
|
||||
@"Yes", nil, bundle, @"")] setKeyEquivalent:@"\r"];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(
|
||||
@"No", nil, bundle, @"")] setKeyEquivalent:@"\e"];
|
||||
NSFileHandle *handle = nil;
|
||||
if (kind == PAPER_TAPE_PUNCH) {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:[NSString stringWithFormat:NSLocalizedStringFromTableInBundle(
|
||||
@"Do you really want to overwrite %C%@%C with the paper tape output?",
|
||||
nil, bundle, @""),
|
||||
UNICODE_LEFT_DOUBLEQUOTE,
|
||||
[[NSFileManager defaultManager] displayNameAtPath:path],
|
||||
UNICODE_RIGHT_DOUBLEQUOTE]];
|
||||
[alert setInformativeText:NSLocalizedStringFromTableInBundle(
|
||||
@"The current content of the file will be lost.", nil, bundle, @"")];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(
|
||||
@"Yes", nil, bundle, @"")] setKeyEquivalent:@"\r"];
|
||||
[[alert addButtonWithTitle:NSLocalizedStringFromTableInBundle(
|
||||
@"No", nil, bundle, @"")] setKeyEquivalent:@"\e"];
|
||||
[alert setAlertStyle:NSAlertStyleCritical];
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn &&
|
||||
(handle = [NSFileHandle fileHandleForWritingAtPath:path]))
|
||||
[handle truncateFileAtOffset:0];
|
||||
[alert release];
|
||||
} else
|
||||
handle = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
if (handle)
|
||||
[self mountFile:handle withPath:path];
|
||||
return handle != nil;
|
||||
if ([alert runModal] == NSAlertFirstButtonReturn &&
|
||||
(handle = [NSFileHandle fileHandleForWritingAtPath:path]))
|
||||
[handle truncateFileAtOffset:0];
|
||||
} else
|
||||
handle = [NSFileHandle fileHandleForReadingAtPath:path];
|
||||
if (handle)
|
||||
[self mountFile:handle withPath:path];
|
||||
return handle != nil;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* RegisterFormCell.m - NSFormCell subclass for PDP-8/E registers
|
||||
* RegisterFormCell.m - NSFormCell subclass for PDP-8/E registers
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -34,62 +34,83 @@
|
|||
|
||||
- (BOOL) control:(NSControl *)control textView:(NSTextView *)textView doCommandBySelector:(SEL)command
|
||||
{
|
||||
if (command == @selector(cancelOperation:)) {
|
||||
// ESC aborts editing of the cell
|
||||
[control abortEditing];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
if (command == @selector(cancelOperation:)) {
|
||||
// ESC aborts editing of the cell
|
||||
[control abortEditing];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) control:(NSControl *)control didFailToFormatString:(NSString *)string
|
||||
errorDescription:(NSString *)error
|
||||
errorDescription:(NSString *)error
|
||||
{
|
||||
NSRange range;
|
||||
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
|
||||
range.location = 0;
|
||||
range.length = -1;
|
||||
[[control currentEditor] setSelectedRange:range];
|
||||
[alert setMessageText:error];
|
||||
[alert beginSheetModalForWindow:[control window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
[alert release];
|
||||
return NO;
|
||||
NSRange range;
|
||||
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
|
||||
range.location = 0;
|
||||
range.length = -1;
|
||||
[[control currentEditor] setSelectedRange:range];
|
||||
[alert setMessageText:error];
|
||||
[alert beginSheetModalForWindow:[control window] completionHandler:^(NSModalResponse returnCode) { }];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (void) controlTextDidEndEditing:(NSNotification *)notification
|
||||
{
|
||||
[registerOwner performSelector:setRegisterValue withObject:[self intValue]];
|
||||
if ([registerOwner respondsToSelector:setRegisterValue])
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
unsigned int val = [self intValue];
|
||||
NSMethodSignature *signature = [registerOwner methodSignatureForSelector:setRegisterValue];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
[invocation setSelector:setRegisterValue];
|
||||
[invocation setArgument:&val atIndex:2];
|
||||
[invocation invokeWithTarget:registerOwner];
|
||||
#pragma clang diagnostic pop
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:setRegisterValue");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) notifyRegisterHasChanged:(NSNotification *)notification
|
||||
{
|
||||
[self setIntValue:(unsigned)[registerOwner performSelector:getRegisterValue]];
|
||||
if ([registerOwner respondsToSelector:getRegisterValue])
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
unsigned int val = [registerOwner performSelector:getRegisterValue];
|
||||
[self setIntValue:val];
|
||||
#pragma clang diagnostic pop
|
||||
} else {
|
||||
NSLog(@"** Cannot performSelector:getRegisterValue");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) setupRegisterFor:(id)owner getRegisterValue:(SEL)getter setRegisterValue:(SEL)setter
|
||||
changedNotificationName:(NSString *)notification
|
||||
mask:(unsigned)mask base:(short)base
|
||||
changedNotificationName:(NSString *)notification
|
||||
mask:(unsigned)mask base:(short)base
|
||||
{
|
||||
NSAssert (base == 8, @"Currenty only base 8 is implemented for RegisterFormCell");
|
||||
[(NSForm *)[self controlView] setDelegate:self];
|
||||
[self setFormatter:[[[OctalFormatter alloc] initWithBitMask:mask wildcardAllowed:NO] autorelease]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyRegisterHasChanged:)
|
||||
name:notification object:nil];
|
||||
registerOwner = owner;
|
||||
getRegisterValue = getter;
|
||||
setRegisterValue = setter;
|
||||
if (runningOnYosemiteOrNewer()) {
|
||||
// with Helvetica Neue, the content digits are one pixel too small, so reset to Lucida Grande
|
||||
[self setFont:[NSFont fontWithName:@"LucidaGrande" size:11]];
|
||||
// with Helvetica Neue, many titles are too long and characters are clipped, so reset to Lucida Grande
|
||||
[self setTitleFont:[NSFont fontWithName:@"LucidaGrande" size:11]];
|
||||
}
|
||||
NSAssert (base == 8, @"Currently only base 8 is implemented for RegisterFormCell");
|
||||
[(NSForm *)[self controlView] setDelegate:self];
|
||||
[self setFormatter:[[OctalFormatter alloc] initWithBitMask:mask wildcardAllowed:NO]];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyRegisterHasChanged:)
|
||||
name:notification object:nil];
|
||||
registerOwner = owner;
|
||||
getRegisterValue = getter;
|
||||
setRegisterValue = setter;
|
||||
if (runningOnYosemiteOrNewer()) {
|
||||
// with Helvetica Neue, the content digits are one pixel too small, so reset to Lucida Grande
|
||||
[self setFont:[NSFont fontWithName:@"LucidaGrande" size:11]];
|
||||
// with Helvetica Neue, many titles are too long and characters are clipped, so reset to Lucida Grande
|
||||
[self setTitleFont:[NSFont fontWithName:@"LucidaGrande" size:11]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/*
|
||||
* PDP-8/E Simulator
|
||||
* PDP-8/E Simulator
|
||||
*
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
* Copyright © 1994-2015 Bernhard Baehr
|
||||
*
|
||||
* TableCornerView.m - Status indicator and button corner view for a NSTableControl
|
||||
* TableCornerView.m - Status indicator and button corner view for a NSTableControl
|
||||
*
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
* This file is part of PDP-8/E Simulator.
|
||||
*
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* PDP-8/E Simulator is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
@ -37,11 +37,11 @@
|
|||
@implementation TableCornerCell
|
||||
|
||||
|
||||
- (void) setState:(int)state
|
||||
- (void) setState:(NSControlStateValue)state
|
||||
{
|
||||
// ignore state setting caused by mouse klick, otherwise the cell switchs from white to gray
|
||||
// send the action here because NSTableHeaderControl does not send any action
|
||||
[NSApp sendAction:[self action] to:[self target] from:self];
|
||||
// ignore state setting caused by mouse klick, otherwise the cell switchs from white to gray
|
||||
// send the action here because NSTableHeaderControl does not send any action
|
||||
[NSApp sendAction:[self action] to:[self target] from:self];
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,56 +61,56 @@
|
|||
|
||||
- (NSRect) framerect:(NSRect)frame
|
||||
{
|
||||
NSRect rect;
|
||||
rect.size = [[self image] size];
|
||||
unsigned width = frame.size.width;
|
||||
if (width % 2 == 0)
|
||||
width--;
|
||||
rect.origin.x = (width - rect.size.width) / 2;
|
||||
if (rect.origin.x >= 2)
|
||||
rect.origin.x++;
|
||||
rect.origin.y = (frame.size.height - rect.size.height) / 2;
|
||||
return rect;
|
||||
NSRect rect;
|
||||
rect.size = [[self image] size];
|
||||
unsigned width = frame.size.width;
|
||||
if (width % 2 == 0)
|
||||
width--;
|
||||
rect.origin.x = (width - rect.size.width) / 2;
|
||||
if (rect.origin.x >= 2)
|
||||
rect.origin.x++;
|
||||
rect.origin.y = (frame.size.height - rect.size.height) / 2;
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
||||
- (void) highlight:(BOOL)flag withFrame:(NSRect)frame inView:(NSView *)view
|
||||
{
|
||||
// [super hightlight:NO ...] does not cause an unhighlight of the cell - Cocoa bug?
|
||||
if (flag) {
|
||||
if (runningOnYosemiteOrNewer()) { // else, there is no highlight of the wrongly gray background
|
||||
// draw frame at the left (this is clipped when the column separator is visible)
|
||||
[[NSColor secondarySelectedControlColor] set];
|
||||
NSRect rect = [self framerect:frame];
|
||||
rect.origin.x--;
|
||||
rect.size.width++;
|
||||
[NSBezierPath fillRect:rect];
|
||||
// draw content of the table corner view
|
||||
[[NSColor controlHighlightColor] set];
|
||||
[NSBezierPath fillRect:[self framerect:frame]];
|
||||
[self drawWithFrame:frame inView:view];
|
||||
} else
|
||||
[super highlight:YES withFrame:frame inView:view];
|
||||
} else {
|
||||
[self drawWithFrame:frame inView:view];
|
||||
if (runningOnYosemiteOrNewer()) // when moving the cursor out of the frame with mouse key down
|
||||
[view setNeedsDisplay:YES];
|
||||
}
|
||||
// [super hightlight:NO ...] does not cause an unhighlight of the cell - Cocoa bug?
|
||||
if (flag) {
|
||||
if (runningOnYosemiteOrNewer()) { // else, there is no highlight of the wrongly gray background
|
||||
// draw frame at the left (this is clipped when the column separator is visible)
|
||||
[[NSColor secondarySelectedControlColor] set];
|
||||
NSRect rect = [self framerect:frame];
|
||||
rect.origin.x--;
|
||||
rect.size.width++;
|
||||
[NSBezierPath fillRect:rect];
|
||||
// draw content of the table corner view
|
||||
[[NSColor controlHighlightColor] set];
|
||||
[NSBezierPath fillRect:[self framerect:frame]];
|
||||
[self drawWithFrame:frame inView:view];
|
||||
} else
|
||||
[super highlight:YES withFrame:frame inView:view];
|
||||
} else {
|
||||
[self drawWithFrame:frame inView:view];
|
||||
if (runningOnYosemiteOrNewer()) // when moving the cursor out of the frame with mouse key down
|
||||
[view setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void) drawWithFrame:(NSRect)frame inView:(NSView *)view
|
||||
{
|
||||
if (runningOnYosemiteOrNewer()) {
|
||||
// else the background is drawn in light gray and a separator is drawn at the right, not in the frame
|
||||
[[NSColor secondarySelectedControlColor] set];
|
||||
[NSBezierPath fillRect:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, 1)]; // bottom line
|
||||
NSImage *image = [self image];
|
||||
if (image)
|
||||
[image drawInRect:[self framerect:frame] fromRect:NSZeroRect
|
||||
operation:NSCompositeSourceOver fraction:1];
|
||||
} else
|
||||
[super drawWithFrame:frame inView:view];
|
||||
if (runningOnYosemiteOrNewer()) {
|
||||
// else the background is drawn in light gray and a separator is drawn at the right, not in the frame
|
||||
[[NSColor secondarySelectedControlColor] set];
|
||||
[NSBezierPath fillRect:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, 1)]; // bottom line
|
||||
NSImage *image = [self image];
|
||||
if (image)
|
||||
[image drawInRect:[self framerect:frame] fromRect:NSZeroRect
|
||||
operation:NSCompositeSourceOver fraction:1];
|
||||
} else
|
||||
[super drawWithFrame:frame inView:view];
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,44 +122,44 @@
|
|||
|
||||
- (TableCornerView *) initWithFrame:(NSRect)frame
|
||||
{
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
[self setCell:[[[TableCornerCell alloc] init] autorelease]];
|
||||
[self setClickable:NO];
|
||||
}
|
||||
return self;
|
||||
if ((self = [super initWithFrame:frame])) {
|
||||
[self setCell:[[TableCornerCell alloc] init]];
|
||||
[self setClickable:NO];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) setImageNamed:(NSString *)name toolTip:(NSString *)toolTip
|
||||
{
|
||||
[[self cell] setImage:[NSImage imageNamed:name]];
|
||||
[self setToolTip:toolTip];
|
||||
[[self cell] setImage:[NSImage imageNamed:name]];
|
||||
[self setToolTip:toolTip];
|
||||
}
|
||||
|
||||
|
||||
- (void) mouseDown:(NSEvent *)event
|
||||
{
|
||||
if (clickable)
|
||||
[super mouseDown:event];
|
||||
if (clickable)
|
||||
[super mouseDown:event];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isFlipped
|
||||
// don't know why this is required - see http://zzot.net/2004/11/20/nstableheadercell/
|
||||
{
|
||||
return ! runningOnYosemiteOrNewer(); // see above for Yosemite drawing glitches
|
||||
return ! runningOnYosemiteOrNewer(); // see above for Yosemite drawing glitches
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isClickable
|
||||
{
|
||||
return clickable;
|
||||
return clickable;
|
||||
}
|
||||
|
||||
|
||||
- (void) setClickable:(BOOL)flag
|
||||
{
|
||||
clickable = flag;
|
||||
clickable = flag;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user