|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 18075 (0x469b) Types: TextFile Notes: UNIX file Names: »mm.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦2d53db1df⟧ UNIX Filesystem └─ ⟦this⟧ »sys/z8001/rec/mm.c«
/* (-lgl * The information contained herein is a trade secret of Mark Williams * Company, and is confidential information. It is provided under a * license agreement, and may be copied or disclosed only under the * terms of that agreement. Any reproduction or disclosure of this * material without the express written authorization of Mark Williams * Company or persuant to the license agreement is unlawful. * * COHERENT Version 0.7.3 * Copyright (c) 1982, 1983, 1984. * An unpublished work by Mark Williams Company, Chicago. * All rights reserved. -lgl) */ /* * Coherent. Commodore Z-8000 memory-mapped video using the * Commodore/MOS Technology "6845" (a. k. a. the 6545-1). * * The terminal emulation is as close as is * reasonable to the Heath H-19 (Zenith Z-19) terminal. * * The CRT controller is wired as follows: * bit 0 of the memory address determines whether * character or attribute (0 is character, 1 attribute). * Thus each character position takes 2 bytes of display * memory. * 14 bits are given to the CRT controller. * For the monochrome display which has only 2048 character * positions (11 bits) the upper 3 address bits are replicated * into the controller as 0. Therefore no masks need be used * on ascending (circular) addresses. */ /* Special hacking by rec 85.VI.06 */ /* Cannot emulate z19 very closely because CBU keyboard driver doesn't */ #define istty kvtty #define ismmfunc(c) /* ismmfunc(c) */ #define initkeys() /* initkeys() */ #include <coherent.h> #if 0 #include <i8086.h> #endif #include <errno.h> #include <uproc.h> #include <stat.h> #include <tty.h> #include <signal.h> #include <timeout.h> #define setcurse() mmcrt(14,((mmoffset)>>1)&mmmask) #define position(r,c) (2*((r)*NCOL+(c))) #define reposition() (mmoffset=position(mmrow,mmcol)) #define setctype(x) mmcrt(10,x) #define setpage() mmcrt(12,0) /* Set display page 0 */ #define checkspec() (mmrow == SPECIAL-1) /* Cursor on line 25? */ #define TRUE 1 #define FALSE 0 #define NROW 24 /* Maximum rows */ #define NCOL 80 /* Columns on screen */ #define TABLIM 72 /* Tab limit (0-relative) */ #define SPECIAL 25 /* Line 25 is special */ #undef ESC #define ESC 033 #define CAN 030 #define DEL 0177 #define NUL 0 #define ATT 0x0700 /* Ordinary Video */ #define INTENSE 0x0800 /* Intense video */ #define BLINK 0x8000 /* Blinking video */ #define REVERSE 0x7000 /* Reverse video */ #define UNDERL 0x0100 /* Underline video (mono board) */ #if 0 /* For beeper */ #define TIMCTL 0x43 /* Timer control port */ #define TIMCNT 0x42 /* Counter timer port */ #define PORTB 0x61 /* Port containing speaker enable */ #define FREQ ((int)(1193181L/440)) /* Counter for 440 Hz. tone */ unsigned mmbase = 0; /* Segment of memory */ unsigned mmport = 0; /* Port address of 6845 */ #endif unsigned mmmask = 0; /* Mask for page+offset */ #define STANDALONE 1 /* JFF */ #define MMSEG 0x3a /* screen memory segment JFF */ #define MMADDR 0x370000L /* screen memory base address JFF */ char *pfix(); /* map memory base address to char JFF */ static char *mmbase = 0; /* pointer to screen memory base JFF */ char mminsmode = 0; /* Insert mode */ static unsigned mmoffset = 0; /* Working offset saves calculation */ static char mmrow = 0; /* Row on screen */ static char mmcol = 0; /* Column on screen */ static char mmsrow = 0; /* Saved row */ static char mmscol = 0; /* Saved column */ static char mmtimer = 0; /* Audible bell sounding */ static char mmescesc = 0; /* Escape escape */ static char mmspec = 0; /* Special line (25) enabled */ static char mmwrap = TRUE; /* End-of-line wrap mode */ static char mmlfcr = 0; /* Auto-CR after LF */ static char mmcrlf = 0; /* Auto-LF after CR */ static unsigned mmattr = 0; /* Current attribute byte */ static int mmncurse = 0; /* Normal (underline) cursor */ static int mmbcurse = 0; /* Block cursor */ static char mmblank = 0; /* Blank video on scroll - REC */ int (*mmfunc)() = 0; /* Output function */ int mmbeepoff(); int mmput(); int mmescape(); int mmsetrow(); int mmsetcol(); int mmsetmode(); int mmresetmode(); int mmstart(); /* * Initialise memory-mapped video. * Have to enable sense switches to * find out monitor style selected on * the switches. */ mmload() { #ifdef STANDALONE /* Let the rom do it otherwise */ register unsigned char i; register char *ip; static char col80x25[] = { /* Colour card settings 80x25 */ 0x71, 0x50, 0x5A, 0x0A, 0x1F, 0x06, 0x19, 0x1c, 0x02, 0x07 }; static char mono[] = { /* Monochrome settings 80x25 */ 0x61, 0x50, 0x52, 0x0F, 0x19, 0x06, 0x19, 0x19, 0x02, 0x0D }; #endif if (mmfunc != NULL) return; #if 0 switch (int11() & 0x30) { #endif switch (0x30) { /* JFF */ case 0x30: /* Monochrome card */ #if 0 mmbase = 0xB000; mmport = 0x3B4; #else mmmask = 0xFFF; mmbase = pfix(MMSEG, MMADDR); /* fix screen memory base JFF */ #endif mmncurse = (0xB<<8)|0xC; /* normal (underline) cursor */ mmbcurse = (0x1<<8)|0xC; /* block cursor */ mmblank = 0; /* No blanking - REC */ #ifdef STANDALONE ip = mono; #endif break; case 0x20: /* Colour card 80x25 */ #if 0 mmbase = 0xB800; mmport = 0x3D4; #endif mmmask = 0x3FFF; mmncurse = (6<<8)|7; /* normal (underline) cursor */ mmbcurse = (1<<8)|7; /* block cursor */ mmblank = 1; /* Blank video - REC */ #ifdef STANDALONE ip = col80x25; #endif break; default: /* Cannot print error here */ panic(""); } /* * Set up initial attributes of the * 6845 CRT controller. */ mmvonn(); /* Video on, high-res */ #ifdef STANDALONE for (i=0; i<10; i+=2) { register int mode; mode = *ip++<<8; mode |= *ip++; mmcrt(i, mode); } #endif mmfunc = mmput; mmattr = ATT; setctype(mmncurse); /* set normal cursor */ setpage(); mmclear(); setcurse(); } /* * Start the output stream. * Called from `ttwrite' and `isrint' routines. * This is probably the most grossly * inefficient way to do memory mapped i/O. */ mmstart(tp) register TTY *tp; { register int c; while ((c = ttout(tp)) >= 0) (*mmfunc)(c); } /* * Turn the speaker off from the * previously begun beep. */ mmbeepoff(save) int save; { #if 0 outb(PORTB, save); mmtimer = 0; #endif } /* * Put a character to the memory-mapped * display, taking into account escape * sequences. */ mmput(c) int c; { static TIM tout; register unsigned off; register unsigned n; switch (c) { case '\007': /* Bell */ #if 0 outb(TIMCTL, 0xB6); /* Timer 2, lsb, msb, binary */ outb(TIMCNT, FREQ&0xFF); outb(TIMCNT, FREQ>>8); n = inb(PORTB); outb(PORTB, n|03); /* Turn speaker on */ if (mmtimer == 0) { mmtimer++; timeout(&tout, (HZ/8), mmbeepoff, n); } #endif break; case '\t': if (mmcol >= TABLIM) /* at tab limit? */ n = 1; /* only move one space */ else { n = (mmcol + 8) & ~7; /* normal tab */ n -= mmcol; } mmstuff(mmoffset, ' '|mmattr, n, mmbase); /* JFF */ if ((mmcol += n) == NCOL) /* end of line? */ { if (mmwrap) { mmcol = 0; if (++mmrow >= NROW) mmscroll(0); reposition(); } } else mmoffset += 2*n; break; case '\r': mmoffset -= 2*mmcol; mmcol = 0; if (mmcrlf) /* auto-LF after CR? */ donl(); /* newline processing */ break; case '\n': donl(); /* newline */ if (mmlfcr) /* auto-CR after LF? */ { mmoffset -= 2*mmcol; mmcol = 0; } break; case '\b': if (mmcol) { mmcol--; mmoffset -= 2; } break; case DEL: case NUL: break; /* ignore these chars */ case ESC: if (!mmescesc) { mmfunc = mmescape; break; } mmescesc = 0; /* Fall through */ default: if (mmcol == NCOL) /* stuck at end of line? */ break; /* ignore char (wrap wasn't on) */ if (mminsmode && mmcol < NCOL-1) { off = position(mmrow, NCOL-1); n = NCOL-1-mmcol; mmcopy(off-2, off, n, 1, mmbase); /* JFF */ } /* JFF */ mmstuff(mmoffset, c|mmattr, 1, mmbase); /* up goes the char */ if (mmcol == NCOL-1) /* at end of line? */ { if (mmwrap) /* wrap mode? */ { mmoffset -= 2*mmcol; /* carriage return */ mmcol = 0; donl(); /* newline or scroll */ } else mmcol++; /* to make cursor stick */ } else /* normal cursor advance */ { mmcol++; reposition(); } } setcurse(); } /* * Handle special escape sequences for H-19/Z-19 */ mmescape(c) register int c; { register unsigned off; register unsigned n; extern TTY istty; mmfunc = mmput; switch (c) { case CAN: /* [<CTRL><X>] cancel escape */ return; case '=': /* Enter Alternate Keypad Mode */ ismmfunc(c); return; case '>': /* Exit Alternate Keypad Mode */ ismmfunc(c); return; case '@': /* Enter Insert Character Mode */ mminsmode = TRUE; return; case 'A': /* Cursor Up */ if (checkspec()) /* no action if on line 25 */ return; if (mmrow) { --mmrow; mmoffset -= 2*NCOL; } break; case 'B': /* Cursor Down */ if (checkspec()) /* no action if on line 25 */ return; if (mmrow < NROW-1) { ++mmrow; mmoffset += 2*NCOL; } break; case 'C': /* Cursor Forward */ if (mmcol < NCOL-1) ++mmcol; reposition(); break; case 'D': /* Cursor Backward */ if (mmcol) --mmcol; reposition(); break; case 'E': /* Clear Screen */ mmclear(); break; case 'H': /* Cursor Home */ if (checkspec()) { mmoffset = position(SPECIAL-1, 0); /* start of line 25 */ mmrow = SPECIAL-1; mmcol = 0; } else mmoffset = mmrow = mmcol = 0; break; case 'I': /* Reverse Index */ if (checkspec()) /* no action if on line 25 */ return; if (--mmrow < 0) mmscroll(1); else mmoffset -= 2*NCOL; break; case 'J': /* Erase rest of screen */ if (!checkspec()) /* if not on line 25 */ { n = (NROW-1-mmrow)*NCOL + NCOL-mmcol; mmstuff(mmoffset, ' '|ATT, n, mmbase); /* JFF */ break; } /* fall through */ case 'K': /* Erase to end of line */ off = position(mmrow, mmcol); mmstuff(off, ' '|ATT, NCOL-mmcol, mmbase); /* JFF */ break; case 'L': /* Insert line */ if (checkspec()) /* no action if on line 25 */ return; if (mmrow < NROW-1) { off = position(NROW-1, NCOL-1); n = NCOL * (NROW-1-mmrow); mmcopy(off-2*NCOL, off, n, 1, mmbase); /* JFF */ } off = position(mmrow, 0); mmstuff(off, ' '|ATT, NCOL, mmbase); /* JFF */ break; case 'M': /* Delete line */ if (checkspec()) /* no action if on line 25 */ return; if (mmrow < NROW-1) { off = position(mmrow, 0); n = NCOL * (NROW-1-mmrow); mmcopy(off+2*NCOL, off, n, 0, mmbase); /* JFF */ } off = position(NROW-1, 0); mmstuff(off, ' '|ATT, NCOL, mmbase); /* JFF */ break; case 'N': /* Delete character */ if (mmcol < NCOL-1) { n = NCOL-1-mmcol; mmcopy(mmoffset+2, mmoffset, n, 0, mmbase); /* JFF */ } off = position(mmrow, NCOL-1); mmstuff(off, ' '|ATT, 1, mmbase); /* JFF */ break; case 'O': /* Leave insert mode */ mminsmode = FALSE; return; case 'Y': /* Direct cursor addressing */ mmfunc = mmsetrow; return; case 'b': /* Erase to beginning of display */ if (!checkspec()) /* if not on line 25 */ { off = position(0, 0); n = mmrow*NCOL + mmcol+1; mmstuff(off, ' '|ATT, n, mmbase); /* JFF */ break; } /* fall through */ case 'o': /* Erase to beginning of Line */ off = position(mmrow, 0); mmstuff(off, ' '|ATT, mmcol+1, mmbase); /* JFF */ break; case 'c': /* Blink mode */ mmattr |= BLINK; return; case 'd': /* Non-blink mode */ mmattr &= ~BLINK; return; case 'e': /* Intense mode */ mmattr |= INTENSE; return; case 'f': /* Non-intense mode */ mmattr &= ~INTENSE; return; case 'j': /* Save cursor position */ mmsrow = mmrow; mmscol = mmcol; break; case 'k': /* Restore cursor position */ mmrow = mmsrow; mmcol = mmscol; reposition(); break; case 'l': /* Erase entire line */ off = position(mmrow, 0); mmstuff(off, ' '|ATT, NCOL, mmbase); /* JFF */ break; case 'n': /* Report cursor position */ n = sphi(); ttin(&istty, ESC); ttin(&istty, 'Y'); ttin(&istty, mmrow+' '); ttin(&istty, mmcol+' '); spl(n); return; case 'p': /* Reverse Video */ mmattr &= ~0x7700; /* clear video flags */ mmattr |= REVERSE; return; case 'q': /* Leave reverse video */ mmattr &= ~0x7700; /* clear video flags */ mmattr |= ATT; return; case 'h': /* Underline video */ mmattr &= ~0x7700; /* clear video flags */ mmattr |= UNDERL; return; case 'i': /* Don't underline video */ mmattr &= ~0x7700; /* clear video flags */ mmattr |= ATT; return; case 't': /* Enter keypad shifted mode */ ismmfunc(c); return; case 'u': /* Exit keypad shifted mode */ ismmfunc(c); return; case 'v': /* Wrap mode on (default) */ mmwrap = TRUE; return; case 'w': /* Wrap mode off */ /* Note: This is the H19 "discard at end of line" * mode. Attempting to delete chars (e.g. with ^H) at the * end of a line when wrap mode is off may cause * the wrong chars on that line to be "visually" erased due * to confusion between chars in the output queue and chars * actually displayed on the screen. This could be fixed, * but would require considerable code. Since this situation * should be EXTREMELY rare in practice, it may safely * be considered to be pathological. */ mmwrap = FALSE; return; case 'Z': /* Identify terminal (send "ESC/K") */ n = sphi(); ttin(&istty, ESC); ttin(&istty, '/'); ttin(&istty, 'K'); spl(n); return; case 'x': /* Set mode */ mmfunc = mmsetmode; return; case 'y': /* Reset mode */ mmfunc = mmresetmode; return; case 'z': /* Reset to powerup configuration */ mmattr = ATT; mminsmode = FALSE; mmwrap = TRUE; ismmfunc(c); /* reset shift states */ initkeys(); /* re-init function keys */ setctype(mmncurse); /* set normal (underline) cursor */ mmclear(); /* clear screen */ setcurse(); /* home up */ /* fall through */ case '2': /* Disable line 25 */ disspec(); return; case '1': /* Enable line 25 */ mmspec = TRUE; return; case 'G': /* Exit graphics mode */ case '\\': /* Exit "hold-screen" mode */ return; /* nothing to do */ default: mmescesc += 1; mmput(ESC); mmput(c); return; } setcurse(); } /* * Clear the screen. */ mmclear() { if (checkspec()) /* if on line 25 */ { mmoffset = position(SPECIAL-1, 0); /* start of line 25 */ mmcol = 0; /* JFF */ mmstuff(mmoffset, ' '|ATT, NCOL, mmbase); /* clear line 25, only */ } else /* not on line 25 */ { mmoffset = mmrow = mmcol = 0; /* JFF */ mmstuff(0, ' '|ATT, (mmspec ? NROW*NCOL : (NROW+1)*NCOL), mmbase); } } /* * Set the row in direct cursor * addressing sequences: * ESC Y line# row# */ unsigned int trow, tcol; mmsetrow(c) register int c; { mmfunc = mmput; if (c == CAN) return; mmfunc = mmsetcol; trow = c - ' '; } /* * Set the column number in * direct cursor addressing. */ mmsetcol(c) register int c; { mmfunc = mmput; if (c == CAN) return; tcol = c - ' '; if (trow < (mmspec ? SPECIAL : NROW) && tcol < NCOL) { mmrow = trow; mmcol = tcol; reposition(); setcurse(); } } /* * Implement set mode and reset mode sequences. */ mmsetmode(c) register int c; { mmfunc = mmput; switch(c) { case '1': /* enable line 25 */ mmspec = TRUE; break; case '4': /* block cursor */ setctype(mmbcurse); break; case '6': /* keypad shifted */ ismmfunc('t'); break; case '7': /* alternate keypad */ ismmfunc('='); break; case '8': /* Auto-LF after CR */ mmcrlf = TRUE; break; case '9': /* Auto-CR after LF */ mmlfcr = TRUE; break; } } mmresetmode(c) register int c; { mmfunc = mmput; switch(c) { case '1': /* disable line 25 */ disspec(); break; case '4': /* underscore cursor */ setctype(mmncurse); break; case '6': /* keypad unshifted */ ismmfunc('u'); break; case '7': /* exit alternate keypad */ ismmfunc('>'); break; case '8': /* no Auto-LF after CR */ mmcrlf = FALSE; break; case '9': /* no Auto-CR after LF */ mmlfcr = FALSE; break; } } /* * Scroll the screen. The flag indicates direction. * Non-zero indicates downward (normally scrolling * is upward). */ mmscroll(down) register int down; { register int off; if (mmblank) mmvoff(); /* REC */ if (down) { off = position(0, 0); mmrow = 0; mmcopy(position(NROW-2, NCOL-1), position(NROW-1, NCOL-1), (NROW-1)*NCOL, 1, mmbase); /* JFF */ } else { off = position(NROW-1, 0); mmrow = NROW-1; mmcopy(position(1, 0), position(0, 0), (NROW-1)*NCOL, 0, mmbase); /* JFF */ } mmstuff(off, ' '|ATT, NCOL, mmbase); /* JFF */ reposition(); if (mmblank) mmvonn(); /* REC */ } /* Disable line 25 */ disspec() { if (mmspec) /* if already enabled, clear line */ { mmstuff(position(SPECIAL-1, 0), ' '|ATT, NCOL, mmbase); /* JFF */ if (checkspec()) /* cursor on line 25? */ mmrow--; /* yes, move off line 25 */ mmspec = FALSE; } } /* Newline processing */ donl() { if (checkspec()) /* no action if on line 25 */ return; if (++mmrow >= NROW) mmscroll(0); else mmoffset += 2*NCOL; } /* Video ioctl */ mmioctl(com, vec) int com; int vec; { paddr_t pos; int count; char *buffer; pos = getuwd(vec); count = getuwd(vec += 2); buffer = getupd(vec += 2); if (pos < 0 || pos + count > mmmask) u.u_error = EINVAL; if (u.u_error) return; pos += ((paddr_t)mmbase) << 4; if (com == TIOVGETB) pucopy(pos, buffer, count); else { if (mmblank) mmvoff(); upcopy(buffer, pos, count); if (mmblank) mmvonn(); } }