PDP-8-E-Simulator/CPUWindow/IOFlagController.m
2018-05-26 15:52:10 +12:00

200 lines
5.7 KiB
Objective-C

/*
* PDP-8/E Simulator
*
* Copyright © 1994-2015 Bernhard Baehr
*
* IOFlagController.m - Controller for the I/O flags table view in the CPU window
*
* 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 "IOFlagController.h"
#import "PDP8.h"
#define NAME_COLUMN 0
#define IENABLE_COLUMN 1
#define IOFLAG_COLUMN 2
#define USER_MODE_ROW 0
@implementation IOFlagController
- (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];
}
- (void) notifyMainWindowChanged:(NSNotification *)notification
{
if ([[notification object] isEqualTo:[ioFlagsView window]])
[ioFlagsView reloadData];
}
- (void) notifyIOFlagsChanged:(NSNotification *)notification
{
[ioFlagsView reloadData];
}
- (void) notifyKM8EMount:(NSNotification *)notification
{
if ([pdp8 hasKM8E])
[self enableIODevice:userFLAG];
else
[self disableIODevice:userFLAG];
}
- (unsigned) numberOfAvailableFlags
{
return 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;
}
- (void) disableIODevice:(unsigned long)ioflag
{
NSAssert1 ((((1 << [deviceNames count]) - 1) & ioflag) == ioflag, @"Invalid IO flag: %o", 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", ioflag);
enabledFlags |= ioflag;
[ioFlagsView reloadData];
}
- (int) numberOfRowsInTableView:(NSTableView *)tableView
{
return [deviceNames count];
}
- (BOOL) tableView:(NSTableView *)tableView shouldSelectRow:(int)row
{
return ((1 << row) & enabledFlags) != 0;
}
- (id) tableView:(NSTableView *)tableView
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;
}
- (void) tableView:(NSTableView *)tableView setObjectValue:(id)val
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;
}
}
- (NSString *) tableView:(NSTableView *)tableView toolTipForCell:(NSCell *)cell
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;
}
@end