/* vscreen.c - screen and keyboard for the c64 vim clone. * * The editor writes straight into the screen matrix at $0400 and colour ram at * $d800 rather than going through the kernal, and it selects the lower/upper * case character set at $1800 so that petscii $41-$5a draws as real lowercase. * * Everything here returns int, so the other compilation unit can call these * without declaring them (power c is K&R C). */ char *scr; /* screen matrix, $0400 */ char *colr; /* colour ram, $d800 */ /* petscii byte -> screen code */ s2v(p) int p; { if (p >= 0xc0) return p - 0x80; if (p >= 0xa0) return p - 0x40; if (p >= 0x60) return p - 0x20; if (p >= 0x40) return p - 0x40; return p; } /* raw screen code at row r, column c */ sraw(r, c, v) int r, c, v; { int i; if (r < 0) return 0; if (r > 24) return 0; if (c < 0) return 0; if (c > 39) return 0; i = r * 40 + c; scr[i] = v; colr[i] = 1; return 0; } /* one petscii character */ spc(r, c, p) int r, c, p; { sraw(r, c, s2v(p)); return 0; } /* one petscii character, inverted: the cursor and the status row */ srpc(r, c, p) int r, c, p; { sraw(r, c, s2v(p) + 128); return 0; } /* a reversed space, for the cursor sitting past the end of a line */ sblk(r, c) int r, c; { sraw(r, c, 160); return 0; } /* a zero terminated petscii string */ sps(r, c, s) int r, c; char *s; { while (*s) spc(r, c++, *s++); return 0; } /* n blanks from (r,c) */ sclr(r, c, n) int r, c, n; { while (n-- > 0) sraw(r, c++, 32); return 0; } /* take over the machine: black on blue, lower case, no blinking cursor */ sinit() { int i; char *p; scr = (char *) 0x0400; colr = (char *) 0xd800; p = (char *) 0xd018; *p = 0x17; p = (char *) 0xd020; *p = 0; p = (char *) 0xd021; *p = 6; p = (char *) 0x00cc; *p = 0; p = (char *) 0x0091; /* run/stop flag: drop whatever boot left */ *p = 0; for (i = 0; i < 1000; i++) { scr[i] = 32; colr[i] = 1; } return 0; } /* give the machine back the way basic expects it */ sdone() { int i; char *p; p = (char *) 0xd018; *p = 0x15; p = (char *) 0xd020; *p = 14; p = (char *) 0xd021; *p = 6; for (i = 0; i < 1000; i++) { scr[i] = 32; colr[i] = 1; } return 0; } /* ---------------------------------------------------------------- keyboard * * Keys come straight out of the kernal's keyboard buffer: $c6 says how many * are waiting and they queue from $0277. The kernal's own irq handler scans * the keyboard matrix and fills that buffer, so this gets each press as it * happens - and it also catches anything typed before the program started. * * Two obvious alternatives do not work: calling the kernal's GETIN through * sys() crashed the program, and the library's getchar() is line buffered - it * echoes through the screen editor and only hands characters over after RETURN. */ /* next key, or 0 if none is waiting */ skeyp() { int n, k, i; char *cnt, *buf; cnt = (char *) 0x00c6; n = *cnt; n = n & 255; if (n == 0) return 0; buf = (char *) 0x0277; k = buf[0]; k = k & 255; for (i = 1; i < n; i++) buf[i - 1] = buf[i]; *cnt = (char) (n - 1); return k; } /* wait for a key */ skey() { int k; for (;;) { k = skeyp(); if (k != 0) return k; } }