Quellcode durchsuchen

vim: fix sys() for C64 (no bank arg), exit via KERNAL reset

Power C on the C64 calls ML as sys(addr, &a, &x, &y); the bank argument
from the manual's C128 library page made sys() jump to $000F and crash.
The ML row painter now runs. Quitting resets through $FCE2 because Power C
owns BASIC's zero-page pointers. Notes and Power C skill updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main
Daniel Covington vor 1 Woche
Ursprung
Commit
1f6fcfee17
11 geänderte Dateien mit 37 neuen und 23 gelöschten Zeilen
  1. +6
    -4
      skills/powerc/SKILL.md
  2. +12
    -5
      vim/NOTES.md
  3. +1
    -1
      vim/build-ml.ps1
  4. +1
    -1
      vim/mltest.c
  5. BIN
      vim/shots/run.png
  6. +1
    -1
      vim/vml.c
  7. +1
    -1
      vim/vml.pet
  8. +12
    -7
      vim/vscreen.c
  9. +1
    -1
      vim/vscreen.pet
  10. BIN
      vim/work.d81
  11. +2
    -2
      vim/work.stamp

+ 6
- 4
skills/powerc/SKILL.md Datei anzeigen

@@ -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; - 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. `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. - 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 - 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. so they stay contiguous, and hand the routine the address of that block in X/Y.




+ 12
- 5
vim/NOTES.md Datei anzeigen

@@ -89,11 +89,18 @@ run


## Calling machine language: sys() and the keyboard ## 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 - 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 screen editor and only hands the characters over after RETURN. Useless for an
editor. editor.


+ 1
- 1
vim/build-ml.ps1 Datei anzeigen

@@ -72,7 +72,7 @@ int len, cur, rev;
a = 0; a = 0;
x = 0; x = 0;
y = 0; y = 0;
sys(15, (unsigned) mlcode, &a, &x, &y);
sys((unsigned) mlcode, &a, &x, &y); /* c64 form: no bank argument */
return 0; return 0;
} }
"@ | Set-Content (Join-Path $here "vml.c") -Encoding utf8 "@ | Set-Content (Join-Path $here "vml.c") -Encoding utf8


+ 1
- 1
vim/mltest.c Datei anzeigen

@@ -18,7 +18,7 @@ main()
y = 0; y = 0;
p[1] = 2; /* B: about to sys() a bare RTS */ p[1] = 2; /* B: about to sys() a bare RTS */
for (;;) { } for (;;) { }
sys(15, (unsigned) rts, &a, &x, &y);
sys((unsigned) rts, &a, &x, &y);
p[2] = 3; /* C: sys + array address work */ p[2] = 3; /* C: sys + array address work */


txt[0] = 72; txt[0] = 72;


BIN
vim/shots/run.png Datei anzeigen

Vorher Nachher
Breite: 384  |  Höhe: 272  |  Größe: 2.0KB Breite: 384  |  Höhe: 272  |  Größe: 1.6KB

+ 1
- 1
vim/vml.c Datei anzeigen

@@ -41,6 +41,6 @@ int len, cur, rev;
a = 0; a = 0;
x = 0; x = 0;
y = 0; y = 0;
sys(15, (unsigned) mlcode, &a, &x, &y);
sys((unsigned) mlcode, &a, &x, &y); /* c64 form: no bank argument */
return 0; return 0;
} }

+ 1
- 1
vim/vml.pet Datei anzeigen

@@ -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; Ý
/* 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; Ý

+ 12
- 7
vim/vscreen.c Datei anzeigen

@@ -107,8 +107,8 @@ sinit()
/* give the machine back the way basic expects it */ /* give the machine back the way basic expects it */
sdone() sdone()
{ {
int i;
char *p; char *p;
char a, x, y;


p = (char *) 0xd018; p = (char *) 0xd018;
*p = 0x15; *p = 0x15;
@@ -116,10 +116,15 @@ sdone()
*p = 14; *p = 14;
p = (char *) 0xd021; p = (char *) 0xd021;
*p = 6; *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; return 0;
} }


@@ -130,8 +135,8 @@ sdone()
* the keyboard matrix and fills that buffer, so this gets each press as it * 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. * 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. * echoes through the screen editor and only hands characters over after RETURN.
*/ */




+ 1
- 1
vim/vscreen.pet Datei anzeigen

@@ -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; Ý Ý
/* 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; Ý Ý

BIN
vim/work.d81 Datei anzeigen


+ 2
- 2
vim/work.stamp Datei anzeigen

@@ -1,6 +1,6 @@
vim=8E13FCED4A0CAFD92855B9281D268368 vim=8E13FCED4A0CAFD92855B9281D268368
vscreen=FFCDAD177DF3AD43CE2809EA7ACD6029
vscreen=7773151D0C575F00E919F19875CB498F
vview=F3C7D092B8080C956D9EBD7B95800CD5 vview=F3C7D092B8080C956D9EBD7B95800CD5
mltest=E4BDE10600DE08AF766FFB32A6D9A3E5 mltest=E4BDE10600DE08AF766FFB32A6D9A3E5
vedit=8BE6C95F2BDA01EC535A8C51CD666881 vedit=8BE6C95F2BDA01EC535A8C51CD666881
vml=D600B54B6821800D24B2986D920E9B12
vml=B9A7F164619D4675A2E78B48F02C179D

Laden…
Abbrechen
Speichern

Powered by TurnKey Linux.