diff --git a/Emulators/Apple80.h b/Emulators/Apple80.h index a1f2835..b446540 100644 --- a/Emulators/Apple80.h +++ b/Emulators/Apple80.h @@ -13,10 +13,7 @@ @interface Apple80 : NSObject { - unsigned _state; - - iPoint _dca; - + _context ctx; } @end diff --git a/Emulators/Apple80.mm b/Emulators/Apple80.mm deleted file mode 100644 index 7d4aa6b..0000000 --- a/Emulators/Apple80.mm +++ /dev/null @@ -1,312 +0,0 @@ -// -// Apple80.mm -// 2Term -// -// Created by Kelvin Sherlock on 12/23/2010. -// Copyright 2010 __MyCompanyName__. All rights reserved. -// - -/* - * See Apple IIe Tech Ref page 273. - * See Apple IIgs Firmware Reference page 77 - * - * - */ - -#import "Apple80.h" - -#include - -#include "OutputChannel.h" -#include "Screen.h" - -@implementation Apple80 - -enum { - StateText, - - StateDCAX, - StateDCAY -}; - -+(void)load -{ - [EmulatorManager registerClass: self]; -} - -+(NSString *)name -{ - return @"Apple 80"; -} - --(NSString *)name -{ - return @"Apple 80"; -} - --(const char *)termName -{ - return "appleIIe"; -} - - --(void)reset -{ - _state = StateText; - -} - --(BOOL)resizable -{ - return NO; -} - --(struct winsize)defaultSize -{ - struct winsize ws = { 24, 80, 0, 0 }; - - return ws; -} - --(void)initTerm: (struct termios *)term -{ - // Control-U is used by the up-arrow key. - term->c_cc[VKILL] = CTRL('X'); -} - - --(void)processCharacter:(uint8_t)c screen:(Screen *)screen output:(OutputChannel *)output -{ - - if (_state == StateText) - { - switch (c) - { - case CTRL('E'): - // cursor on - break; - - case CTRL('F'): - //cursor off - break; - - case CTRL('G'): - // beep 1000 hz for .1 seconds. - NSBeep(); - break; - - case CTRL('H'): - // decrement x. moves to end of previous line... - screen->decrementX(true); - break; - - case CTRL('I'): - // tab - screen->tabTo((screen->x() + 8) & ~0x07); - break; - - case CTRL('J'): - // down 1 line. - screen->lineFeed(); - break; - - case CTRL('K'): - // clear to end of screen - screen->erase(Screen::EraseAfterCursor); - break; - - case CTRL('L'): - // clear screen, go home. - screen->erase(Screen::EraseAll); - screen->setCursor(0, 0, true, true); - break; - - case CTRL('M'): - // move to left edge. - // IIe also did a linefeed. [?] - screen->setX(0, true); - break; - - case CTRL('N'): - // normal text. - screen->clearFlagBit(Screen::FlagInverse); - break; - - case CTRL('O'): - // inverse text. - screen->setFlagBit(Screen::FlagInverse); - break; - - case CTRL('Q'): - // 40 column mode. - break; - - case CTRL('R'): - // 80 column mode - break; - - case CTRL('S'): - // stop listing until another key pressed. - break; - - case CTRL('U'): - // deactivate 80 column firmware - break; - - case CTRL('V'): - // scroll down 1 line, leaving cursor at current position. - screen->deleteLine(0); - break; - - case CTRL('W'): - // scroll up 1 line, leaving cursor at current position. - screen->insertLine(0); - break; - - case CTRL('X'): - //mouse text off - screen->clearFlagBit(Screen::FlagMouseText); - break; - - case CTRL('Y'): - // cursor home - screen->setCursor(0, 0, true, true); - break; - - case CTRL('Z'): - // clear entire line - screen->erase(Screen::EraseLineAll); - break; - - case CTRL('['): - // mouse text on - screen->setFlagBit(Screen::FlagMouseText); - break; - - - case CTRL('\\'): - // move cursor 1 character to the right - // TODO -- should wrap to next line. - screen->incrementX(true); - break; - - case CTRL(']'): - // clear to end of line. - // TODO -- should also clear cursor. - screen->erase(Screen::EraseLineAfterCursor); - break; - - case CTRL('^'): - // goto x y - _state = StateDCAX; - break; - - case CTRL('_'): - // move up 1 line, no scroll. - screen->decrementY(true); - break; - - default: - if (c >= 0x20 && c < 0x7f) - { - screen->putc(c); - } - break; - - } - - return; - } - - switch (_state) - { - case StateDCAX: - _dca.x = c - 32; - _state = StateDCAY; - break; - - case StateDCAY: - _dca.y = c - 32; - screen->setCursor(_dca); - - _state = StateText; - break; - - } - - -} - - --(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output -{ - NSEventModifierFlags flags = [event modifierFlags]; - NSString *chars = [event charactersIgnoringModifiers]; - - NSUInteger length = [chars length]; - - for (unsigned i = 0; i < length; ++i) - { - unichar uc = [chars characterAtIndex: i]; - - switch (uc) - { - case NSEnterCharacter: - output->write(CTRL('M')); - break; - /* - case NSDeleteCharacter: - output->write(0x7f); - break; - */ - - - // the Apple II keyboard had a delete where the backspace key was. - // it functions as a backspace key. - case NSBackspaceCharacter: - output->write(0x7f); - break; - - case NSLeftArrowFunctionKey: - output->write(CTRL('H')); - break; - - case NSRightArrowFunctionKey: - output->write(CTRL('U')); - break; - - case NSUpArrowFunctionKey: - output->write(CTRL('K')); - break; - - case NSDownArrowFunctionKey: - output->write(CTRL('J')); - break; - - - default: - if (uc <= 0x7f) - { - char c = uc; - - //NSLog(@"%@", event); - - if (flags & NSAlphaShiftKeyMask) - { - c = flags & NSShiftKeyMask ? tolower(c) : toupper(c); - } - - if (flags & NSControlKeyMask) - c = CTRL(c); - - output->write(c); - } - break; - } - - - - } -} - -@end diff --git a/Emulators/Apple80.mm.ragel b/Emulators/Apple80.mm.ragel new file mode 100644 index 0000000..9adea8d --- /dev/null +++ b/Emulators/Apple80.mm.ragel @@ -0,0 +1,387 @@ +// +// Apple80.mm +// 2Term +// +// Created by Kelvin Sherlock on 12/23/2010. +// Copyright 2010 __MyCompanyName__. All rights reserved. +// + +/* + * See Apple IIe Tech Ref page 273. + * See Apple IIgs Firmware Reference page 77 + * See Apple IIe Extended 80-Column TextCard (revision B) appendix C. + * + */ + +#import "Apple80.h" + +#include + +#include "OutputChannel.h" +#include "Screen.h" + + +%%{ + machine console; + alphtype unsigned int; + + action nop {} + + action advance { + // advance cursor + if (++cursor.x == 80) { + cursor.x = 0; + if (cursor.y >= 24-1) { + screen->scrollUp(); + } else cursor.y++; + } + } + + arg1 = any ${ _scratch[0] = (fc - 32); }; + arg2 = any ${ _scratch[1] = (fc - 32); }; + + + + + main := ( + 0x00 $nop + | 0x01 $nop + | 0x02 $nop + | 0x03 $nop + | 0x04 $nop + + | 0x05 ${ + /* E - $05 - Turns cursor on (enables cursor display) */ + screen->setCursorType(Screen::CursorTypeUnderscore); + } + + | 0x06 ${ + /* F - $06 - Turns cursor off (disables cursor display) */ + screen->setCursorType(Screen::CursorTypeNone); + } + + | 0x07 ${ + /* G - $07 - beep 1000 hz for .1 seconds. */ + NSBeep(); + } + + | 0x08 ${ + /* H - $08 - Moves cursor left one column; + if cursor was at beginning of line, moves + it to end of previous line + */ + + if (cursor.x) cursor.x--; + else { + cursor.x = 80-1; + // go up, possibly scrolling. + if (cursor.y) cursor.y--; + } + } + + | 0x09 ${ + // control-I + // tab -- todo, verify. + cursor.x = (cursor.x + 7) & ~7; + cursor.x = std::min(cursor.x, 79); + } + + | 0x0a ${ + /* J - $0A - Moves cursor down one row; scrolls if needed */ + + if (cursor.y >= 24-1) { + screen->scrollUp(); + } else cursor.y++; + + } + + | 0x0b ${ + /* K - $0B - Clears to end of screen */ + + iRect tmp; + tmp.origin = cursor; + tmp.size = iSize(80 - cursor.x, 1); + + screen->eraseRect(tmp); + + tmp = _iRect(0, 0, 80, 24); + tmp.origin.y = cursor.y+1; + tmp.size.height -= cursor.y+1; + screen->eraseRect(tmp); + + } + + | 0x0c ${ + // control-L + /* clear text port and home */ + screen->erase(); + cursor = iPoint(0,0); + } + + | 0x0d ${ + // control-M + /* carriage return */ + // BASIC also moves to next line, PASCAL does not. + cursor.x = 0; + } + + | 0x0e ${ + // control-N + /* set normal display */ + _context->clearFlagBit(Screen::FlagInverse); + } + + | 0x0f ${ + // control-O + /* set inverse display */ + _context->setFlagBit(Screen::FlagInverse); + } + + | 0x10 $nop + + | 0x11 ${ /* ^Q 40 column mode */ } + | 0x12 ${ /* ^R 80 column mode */ } + + | 0x13 ${ /* ^S - stop listing until any keypress. */ } + + | 0x14 $nop + + | 0x15 ${ + /* ^U - deactivate 80 column? */ + } + + | 0x16 ${ /* CTRL('V') */ screen->scrollDown(); } + + | 0x17 ${ /* CTRL('W') */ screen->scrollUp(); } + + | 0x18 ${ + // CTRL('X'): + /* disable mouse text */ + _context->clearFlagBit(Screen::FlagMouseText); + } + + | 0x19 ${ + // CTRL('Y'): + /* home cursor */ + cursor = iPoint(0,0); + } + + | 0x1a ${ + // CTRL('Z'): + /* clear line */ + iRect tmp; + tmp.origin = iPoint(0 cursor.y); + tmp.size = iSize(80, 1); + screen->eraseRect(tmp); + } + + | 0x1b ${ + // CTRL('['): + /* ^[ enable mouse text mapping */ + _context->setFlagBit(Screen::FlagMouseText); + } + + | 0x1c ${ + // CTRL('\\'): + /* Moves cursor right one column; if at end of line, does Control-M */ + // n.b. - BASIC ^M also moves to next line. + cursor.x++; + if (cursor.x == 24) cursor.x = 0; + } + + | 0x1d ${ + // CTRL(']'): + /* clear to end of line */ + iRect tmp; + tmp.origin = cursor; + tmp.size = iSize(80 - cursor.x, 1); + + screen->eraseRect(tmp); + } + + | 0x1e arg1 arg2 ${ + // CTRL('^'): + /* goto x y */ + // todo - verify behavior for illegal values. + cursor.x = clamp(_scratch[0], 0, 80 - 1); + cursor.y = clamp(_scratch[1], 0, 24 - 1); + } + + | 0x1f ${ + // CTRL('_'): + /* move cursor up */ + if (cursor.y) cursor.y--; + } + + | 0x20 .. 0x7f ${ + screen->putc(fc, _context); + } $advance + + | 0x80 .. 0x9f ${ + /* uppercase inverse/normal */ + uint8_t flag = ~(_context.flags & Screen::FlagInverse); + screen->putc(fc - 0x40, _context.cursor, flag); + } $advance + + | 0xa0 .. 0xbf ${ + /* special inverse/normal */ + uint8_t flag = ~(_context.flags & Screen::FlagInverse); + screen->putc(fc - 0x80, _context.cursor(), flag); + } $advance + + | 0xc0 .. 0xdf ${ + /* uppercase normal / mouse text. */ + uint8_t flag = ~(_context.flags & Screen::FlagInverse); + if (flag) flag |= Screen::FlagMouseText; + screen->putc(fc - 0x80, _context.cursor(), flag); + } $advance + + | 0xe0 .. 0xff ${ + /* special inverse/normal */ + uint8_t flag = ~(_context.flags & Screen::FlagInverse); + screen->putc(fc - 0x80, _context.cursor(), flag); + } $advance + + )* $err{ fgoto main; }; + + write data; +}%% + +@implementation Apple80 + + ++(void)load +{ + [EmulatorManager registerClass: self]; +} + ++(NSString *)name +{ + return @"Apple 80"; +} + +-(NSString *)name +{ + return @"Apple 80"; +} + +-(const char *)termName +{ + return "appleIIe"; +} + + +-(void)reset +{ + + %%write init; + _context.window = iRect(0, 0, 80, 24); + _context.cursor = iPoint(0,0); + _context.flags = 0; + _cursorType = Screen::CursorTypeUnderscore; +} + +-(BOOL)resizable +{ + return NO; +} + +-(struct winsize)defaultSize +{ + struct winsize ws = { 24, 80, 0, 0 }; + + return ws; +} + +-(void)initTerm: (struct termios *)term +{ + // Control-U is used by the up-arrow key. + term->c_cc[VKILL] = CTRL('X'); +} + + +-(void)processData:(const uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output +{ + + const uint8_t *eof = nullptr; + const uint8_t *p = data; + const uint8_t *pe = data + length; + + auto &cursor = _context.cursor; + %%write exec; + _screen->setCursor(cursor); +} + + +-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output +{ + NSEventModifierFlags flags = [event modifierFlags]; + NSString *chars = [event charactersIgnoringModifiers]; + + NSUInteger length = [chars length]; + + for (unsigned i = 0; i < length; ++i) + { + unichar uc = [chars characterAtIndex: i]; + + switch (uc) + { + case NSEnterCharacter: + output->write(CTRL('M')); + break; + /* + case NSDeleteCharacter: + output->write(0x7f); + break; + */ + + + // the Apple II keyboard had a delete where the backspace key was. + // it functions as a backspace key. + case NSBackspaceCharacter: + output->write(0x7f); + break; + + case NSLeftArrowFunctionKey: + output->write(CTRL('H')); + break; + + case NSRightArrowFunctionKey: + output->write(CTRL('U')); + break; + + case NSUpArrowFunctionKey: + output->write(CTRL('K')); + break; + + case NSDownArrowFunctionKey: + output->write(CTRL('J')); + break; + + + default: + if (uc <= 0x7f) + { + char c = uc; + + //NSLog(@"%@", event); + + if (flags & NSAlphaShiftKeyMask) + { + c = flags & NSShiftKeyMask ? tolower(c) : toupper(c); + } + + if (flags & NSControlKeyMask) + c = CTRL(c); + + output->write(c); + } + break; + } + + + + } +} + +@end