diff --git a/skills/powerc/SKILL.md b/skills/powerc/SKILL.md index 336c8a4..5710380 100644 --- a/skills/powerc/SKILL.md +++ b/skills/powerc/SKILL.md @@ -193,10 +193,12 @@ Link `stdlib.l` and `syslib.l` via `^`; `math.l` by name. - Zero page `20-33`, `43-74`, `253-254` (decimal) are reserved by the system; `34-42`, `75-96`, `251-252` are scratch and safe for your ML routines. - The tape buffer `$033C-$03FB` is used by the system; do not touch it. -- Call machine code with `sys(bank, address, &a, &x, &y)` (the manual's example - uses bank 15); A/X/Y are loaded from the pointers and written back afterwards; - it returns the carry flag. Example: - `while (*s++) sys(15, 0xffd2, s, &x, &y);` prints via KERNAL CHROUT. +- Call machine code on the **C64** with `sys(address, &a, &x, &y)` -- no bank + argument. The manual's library page shows the **C128** form + `sys(bank, address, ...)` (bank 15); used on a C64 it jumps to address 15 and + warm-starts the machine (verified in VICE). A/X/Y are loaded from the + pointers and written back afterwards; it returns the carry flag. Example: + `char a, x, y; a = 147; sys(0xffd2, &a, &x, &y);` clears the screen via CHROUT. - Pass multiple args to an ML routine by declaring one `float args;` parameter so they stay contiguous, and hand the routine the address of that block in X/Y. diff --git a/vim/NOTES.md b/vim/NOTES.md index a32f0b8..ad9dbd7 100644 --- a/vim/NOTES.md +++ b/vim/NOTES.md @@ -89,11 +89,18 @@ run ## Calling machine language: sys() and the keyboard -- `sys(bank, address, &a, &x, &y)` is documented as - `int bank; unsigned address; char *aptr, *xptr, *yptr;` with `bank` from 0 to - 15 (BASIC 7 style). **Calling KERNAL GETIN through it crashed the program**; - the crash warm-starts the C64, which clears the screen, so the only evidence - was a blank blue screen and `READY.`. +- **On the C64, `sys` takes no bank: `sys(address, &a, &x, &y)`.** The + library reference page documents the C128 form `sys(bank, address, ...)` + (with "bank 15" in its example); only the C64 tutorial section ("add3" at + `$C000`) shows the four-argument call. Passing the bank makes `15` the jump + address, so the CPU runs zero page and the C64 warm-starts: blank screen and + `READY.`, no other evidence. That was the real cause of the earlier + "GETIN through sys() crashes" and of the first ML row-painter crash. +- **Do not return from `main()` to BASIC.** Power C reserves zero page 43-74 + (`$2B-$4A`), which is BASIC's program/variable pointer area, so after the + program ends BASIC runs on garbage: no `READY.`, or a mangled message such + as `UNCTIO?VER`. The editor quits with `sys(0xfce2, &a, &x, &y)` (KERNAL + reset) instead, which comes up with the banner and `READY.`. - The library's **`getchar()` is line buffered**: it echoes through the KERNAL's screen editor and only hands the characters over after RETURN. Useless for an editor. diff --git a/vim/build-ml.ps1 b/vim/build-ml.ps1 index 81d7c31..a588c15 100644 --- a/vim/build-ml.ps1 +++ b/vim/build-ml.ps1 @@ -72,7 +72,7 @@ int len, cur, rev; a = 0; x = 0; y = 0; - sys(15, (unsigned) mlcode, &a, &x, &y); + sys((unsigned) mlcode, &a, &x, &y); /* c64 form: no bank argument */ return 0; } "@ | Set-Content (Join-Path $here "vml.c") -Encoding utf8 diff --git a/vim/mltest.c b/vim/mltest.c index cad0807..dac4f22 100644 --- a/vim/mltest.c +++ b/vim/mltest.c @@ -18,7 +18,7 @@ main() y = 0; p[1] = 2; /* B: about to sys() a bare RTS */ for (;;) { } - sys(15, (unsigned) rts, &a, &x, &y); + sys((unsigned) rts, &a, &x, &y); p[2] = 3; /* C: sys + array address work */ txt[0] = 72; diff --git a/vim/shots/run.png b/vim/shots/run.png index f9165fc..a485291 100644 Binary files a/vim/shots/run.png and b/vim/shots/run.png differ diff --git a/vim/vml.c b/vim/vml.c index 1e9d418..67d61ac 100644 --- a/vim/vml.c +++ b/vim/vml.c @@ -41,6 +41,6 @@ int len, cur, rev; a = 0; x = 0; y = 0; - sys(15, (unsigned) mlcode, &a, &x, &y); + sys((unsigned) mlcode, &a, &x, &y); /* c64 form: no bank argument */ return 0; } diff --git a/vim/vml.pet b/vim/vml.pet index 3fe6377..ef693a7 100644 --- a/vim/vml.pet +++ b/vim/vml.pet @@ -1 +1 @@ -/* VML.C - ÇÅÎÅÒÁÔÅÄ BY BUILD-ML.PS1 FROM VROW.S. ÄO NOT EDIT BY HAND. * * ÔHE MACHINE CODE ROW PAINTER, KEPT AS A BYTE ARRAY AND CALLED IN PLACE * THROUGH SYS(). ÉT IS POSITION INDEPENDENT; ITS PARAMETERS GO THROUGH ZERO * PAGE SCRATCH $22-$28, WHICH ÐOWER Ã LEAVES TO ÍÌ ROUTINES. */ CHAR MLCODE[76] = Û 165, 40, 9, 32, 160, 39, 145, 37, 136, 16, 251, 160, 0, 196, 36, 240, 45, 177, 34, 201, 32, 176, 2, 169, 32, 201, 192, 144, 4, 233, 128, 176, 22, 201, 160, 144, 4, 233, 64, 176, 14, 201, 96, 144, 4, 233, 32, 176, 6, 201, 64, 144, 2, 233, 64, 5, 40, 145, 37, 200, 208, 207, 165, 39, 201, 255, 240, 7, 168, 177, 37, 73, 128, 145, 37, 96 Ý; /* NOTHING TO INSTALL: THE CODE RUNS WHERE THE ARRAY SITS */ MLINIT() Û RETURN 0; Ý /* PAINT THE SCREEN ROW AT ADDRESS DST: LEN BYTES FROM SRC, CURSOR AT COLUMN CUR (255 = NONE), REV = 128 FOR AN ALL REVERSE ROW */ MLROW(SRC, LEN, DST, CUR, REV) UNSIGNED SRC, DST; INT LEN, CUR, REV; Û CHAR *P; CHAR A, X, Y; P = (CHAR *) 0X22; P[0] = SRC & 255; P[1] = SRC >> 8; P[2] = LEN; P[3] = DST & 255; P[4] = DST >> 8; P[5] = CUR; P[6] = REV; A = 0; X = 0; Y = 0; SYS(15, (UNSIGNED) MLCODE, &A, &X, &Y); RETURN 0; Ý \ No newline at end of file +/* VML.C - ÇÅÎÅÒÁÔÅÄ BY BUILD-ML.PS1 FROM VROW.S. ÄO NOT EDIT BY HAND. * * ÔHE MACHINE CODE ROW PAINTER, KEPT AS A BYTE ARRAY AND CALLED IN PLACE * THROUGH SYS(). ÉT IS POSITION INDEPENDENT; ITS PARAMETERS GO THROUGH ZERO * PAGE SCRATCH $22-$28, WHICH ÐOWER Ã LEAVES TO ÍÌ ROUTINES. */ CHAR MLCODE[76] = Û 165, 40, 9, 32, 160, 39, 145, 37, 136, 16, 251, 160, 0, 196, 36, 240, 45, 177, 34, 201, 32, 176, 2, 169, 32, 201, 192, 144, 4, 233, 128, 176, 22, 201, 160, 144, 4, 233, 64, 176, 14, 201, 96, 144, 4, 233, 32, 176, 6, 201, 64, 144, 2, 233, 64, 5, 40, 145, 37, 200, 208, 207, 165, 39, 201, 255, 240, 7, 168, 177, 37, 73, 128, 145, 37, 96 Ý; /* NOTHING TO INSTALL: THE CODE RUNS WHERE THE ARRAY SITS */ MLINIT() Û RETURN 0; Ý /* PAINT THE SCREEN ROW AT ADDRESS DST: LEN BYTES FROM SRC, CURSOR AT COLUMN CUR (255 = NONE), REV = 128 FOR AN ALL REVERSE ROW */ MLROW(SRC, LEN, DST, CUR, REV) UNSIGNED SRC, DST; INT LEN, CUR, REV; Û CHAR *P; CHAR A, X, Y; P = (CHAR *) 0X22; P[0] = SRC & 255; P[1] = SRC >> 8; P[2] = LEN; P[3] = DST & 255; P[4] = DST >> 8; P[5] = CUR; P[6] = REV; A = 0; X = 0; Y = 0; SYS((UNSIGNED) MLCODE, &A, &X, &Y); /* C64 FORM: NO BANK ARGUMENT */ RETURN 0; Ý \ No newline at end of file diff --git a/vim/vscreen.c b/vim/vscreen.c index d1cd458..6ce3c9d 100644 --- a/vim/vscreen.c +++ b/vim/vscreen.c @@ -107,8 +107,8 @@ sinit() /* give the machine back the way basic expects it */ sdone() { - int i; char *p; + char a, x, y; p = (char *) 0xd018; *p = 0x15; @@ -116,10 +116,15 @@ sdone() *p = 14; p = (char *) 0xd021; *p = 6; - for (i = 0; i < 1000; i++) { - scr[i] = 32; - colr[i] = 1; - } + /* do not return to basic: power c owns zero page 43-74, which is where + basic keeps its program and variable pointers, so basic carries on with + garbage and prints a mangled error instead of READY. restart the + machine through the kernal reset instead - banner and READY, like + switching on. the file has been saved (or abandoned with :q!) by now. */ + a = 0; + x = 0; + y = 0; + sys(0xfce2, &a, &x, &y); /* never comes back */ return 0; } @@ -130,8 +135,8 @@ sdone() * 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 + * (GETIN through sys() once "crashed" - but that was sys() called with the + * c128 bank argument; on the c64 it is sys(addr, &a, &x, &y).) And the library's getchar() is line buffered - it * echoes through the screen editor and only hands characters over after RETURN. */ diff --git a/vim/vscreen.pet b/vim/vscreen.pet index f2720b9..ac9d505 100644 --- a/vim/vscreen.pet +++ b/vim/vscreen.pet @@ -1 +1 @@ -/* VSCREEN.C - SCREEN AND KEYBOARD FOR THE C64 VIM CLONE. * * ÔHE 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. * * ÅVERYTHING HERE RETURNS INT, SO THE OTHER COMPILATION UNIT CAN CALL THESE * WITHOUT DECLARING THEM (POWER C IS Ë&Ò Ã). */ 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 * * ËEYS COME STRAIGHT OUT OF THE KERNAL'S KEYBOARD BUFFER: $C6 SAYS HOW MANY * ARE WAITING AND THEY QUEUE FROM $0277. ÔHE 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. * * ÔWO OBVIOUS ALTERNATIVES DO NOT WORK: CALLING THE KERNAL'S ÇÅÔÉÎ 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 ÒÅÔÕÒÎ. */ /* 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; Ý Ý \ No newline at end of file +/* VSCREEN.C - SCREEN AND KEYBOARD FOR THE C64 VIM CLONE. * * ÔHE 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. * * ÅVERYTHING HERE RETURNS INT, SO THE OTHER COMPILATION UNIT CAN CALL THESE * WITHOUT DECLARING THEM (POWER C IS Ë&Ò Ã). */ 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() Û CHAR *P; CHAR A, X, Y; P = (CHAR *) 0XD018; *P = 0X15; P = (CHAR *) 0XD020; *P = 14; P = (CHAR *) 0XD021; *P = 6; /* DO NOT RETURN TO BASIC: POWER C OWNS ZERO PAGE 43-74, WHICH IS WHERE BASIC KEEPS ITS PROGRAM AND VARIABLE POINTERS, SO BASIC CARRIES ON WITH GARBAGE AND PRINTS A MANGLED ERROR INSTEAD OF ÒÅÁÄÙ. RESTART THE MACHINE THROUGH THE KERNAL RESET INSTEAD - BANNER AND ÒÅÁÄÙ, LIKE SWITCHING ON. THE FILE HAS BEEN SAVED (OR ABANDONED WITH :Q!) BY NOW. */ A = 0; X = 0; Y = 0; SYS(0XFCE2, &A, &X, &Y); /* NEVER COMES BACK */ RETURN 0; Ý /* ---------------------------------------------------------------- KEYBOARD * * ËEYS COME STRAIGHT OUT OF THE KERNAL'S KEYBOARD BUFFER: $C6 SAYS HOW MANY * ARE WAITING AND THEY QUEUE FROM $0277. ÔHE 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. * * (ÇÅÔÉÎ THROUGH SYS() ONCE "CRASHED" - BUT THAT WAS SYS() CALLED WITH THE * C128 BANK ARGUMENT; ON THE C64 IT IS SYS(ADDR, &A, &X, &Y).) ÁND THE LIBRARY'S GETCHAR() IS LINE BUFFERED - IT * ECHOES THROUGH THE SCREEN EDITOR AND ONLY HANDS CHARACTERS OVER AFTER ÒÅÔÕÒÎ. */ /* 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; Ý Ý \ No newline at end of file diff --git a/vim/work.d81 b/vim/work.d81 index 62109cd..54aa2f5 100644 Binary files a/vim/work.d81 and b/vim/work.d81 differ diff --git a/vim/work.stamp b/vim/work.stamp index 5eb49e8..314456f 100644 --- a/vim/work.stamp +++ b/vim/work.stamp @@ -1,6 +1,6 @@ vim=8E13FCED4A0CAFD92855B9281D268368 -vscreen=FFCDAD177DF3AD43CE2809EA7ACD6029 +vscreen=7773151D0C575F00E919F19875CB498F vview=F3C7D092B8080C956D9EBD7B95800CD5 mltest=E4BDE10600DE08AF766FFB32A6D9A3E5 vedit=8BE6C95F2BDA01EC535A8C51CD666881 -vml=D600B54B6821800D24B2986D920E9B12 +vml=B9A7F164619D4675A2E78B48F02C179D