Bläddra i källkod

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 1 vecka sedan
förälder
incheckning
1f6fcfee17
11 ändrade filer med 37 tillägg och 23 borttagningar
  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är
      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är
      vim/work.d81
  11. +2
    -2
      vim/work.stamp

+ 6
- 4
skills/powerc/SKILL.md Visa fil

@@ -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.



+ 12
- 5
vim/NOTES.md Visa fil

@@ -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.


+ 1
- 1
vim/build-ml.ps1 Visa fil

@@ -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


+ 1
- 1
vim/mltest.c Visa fil

@@ -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;


Binär
vim/shots/run.png Visa fil

Before After
Width: 384  |  Height: 272  |  Size: 2.0KB Width: 384  |  Height: 272  |  Size: 1.6KB

+ 1
- 1
vim/vml.c Visa fil

@@ -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;
}

+ 1
- 1
vim/vml.pet Visa fil

@@ -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 Visa fil

@@ -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.
*/



+ 1
- 1
vim/vscreen.pet Visa fil

@@ -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är
vim/work.d81 Visa fil


+ 2
- 2
vim/work.stamp Visa fil

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

Laddar…
Avbryt
Spara

Powered by TurnKey Linux.