PDP-8-E-Simulator/RK8E/RK8E.m

428 lines
12 KiB
Objective-C

/*
* PDP-8/E Simulator
*
* Copyright © 1994-2015 Bernhard Baehr
*
* RK8E.m - RK8-E Disk Cartridge System for the 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.
*
* 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/>.
*/
#import <Cocoa/Cocoa.h>
#import "PluginFramework/PluginAPI.h"
#import "PluginFramework/PDP8.h"
#import "PluginFramework/Utilities.h"
#import "PluginFramework/FileDropControlTargetProtocol.h"
#import "PluginFramework/NSThread+MainThread.h"
#define USE_RK8E_REGISTERS_DIRECTLY 1
#import "RK8E.h"
#import "RK8Eiot.h"
#import "RK05.h"
#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"
@implementation RK8E
API_VERSION
#pragma mark Plugin Methods
- (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];
}
- (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];
}
- (void) setIOFlag:(unsigned long)flag forIOFlagName:(NSString *)name;
{
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;
}
- (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];
}
- (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];
}
- (void) resetDevice
{
[self clearAllFlags:0];
[rk05[0] setWriteProtected:NO];
[rk05[1] setWriteProtected:NO];
[rk05[2] setWriteProtected:NO];
[rk05[3] setWriteProtected:NO];
}
#pragma mark Register Access
- (unsigned short) getCommand
{
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];
}
- (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];
}
- (unsigned short) getStatus
{
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];
}
- (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];
}
- (void) notifyStatusChangedWhenNotRunning
{
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];
}
- (unsigned short) getBlockNumber
{
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)];
}
- (unsigned short) getMemoryAddress
{
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)];
}
- (unsigned short) getCurrentAddress
{
return curaddr;
}
- (void) setCurrentAddress:(unsigned short)addr
{
NSAssert1 ((addr & ~07777) == 0, @"Bad Current Address: 0%o", addr);
curaddr = addr;
}
- (unsigned short) getCurrentDriveNumber
{
return (command >> 1) & 3;
}
- (void) setCRC:(unsigned)newCRC
{
crc = checkcrc = newCRC;
}
- (BOOL) isCRCOK
{
return crc == checkcrc;
}
- (void) lockControl
{
[controlLock lock];
}
- (void) unlockControl
{
[controlLock unlock];
}
#pragma mark Initialization
- (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;
}
- (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];
}
- (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]];
}
- (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];
self = [self initWithCoder:unarchiver];
[rk05Controller_0 initWithCoder:unarchiver];
[rk05Controller_1 initWithCoder:unarchiver];
[rk05Controller_2 initWithCoder:unarchiver];
[rk05Controller_3 initWithCoder:unarchiver];
[unarchiver finishDecoding];
[unarchiver release];
}
controlLock = [[NSLock alloc] init];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(notifyApplicationWillTerminate:)
name:NSApplicationWillTerminateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notifyPDP8IOFlagsChanged:)
name:IOFLAGS_CHANGED_NOTIFICATION object:nil];
}
@end