Everything below was verified on this machine (GTK3VICE 3.10, reference/POWERc.d81),
mostly by first getting it wrong. Read this before touching the build or the
keyboard code.
Compile every unit, link, then bye out of the Power C shell, then load and
run from BASIC — all typed into one emulator session from one -keybuf
string:
cc vim.c <RETURN><RETURN><RETURN> ... padding
cc vscreen.c <RETURN><RETURN><RETURN> ... padding
link -s
vim.o
vscreen.o
^ up-arrow: stdlib.l + syslib.l
empty RETURN: done
vim output name
bye
load"vim",8,1
run
.d81. Both hold the whole image
in memory and write it back on exit, so the second one's exit silently erases
what the first wrote. Symptoms: a compile that “produced nothing”, a linker
that “found no object”, a directory that changes between two c1541 -list
calls.Start-Process -Wait (or .NET Process + WaitForExit) so a step cannot
overlap the next.-keybuf-delay is wall-clock milliseconds per keystroke while the machine
runs at warp, so 900 ms per key is plenty for the machine.cc clears the keyboard buffer when it starts, so its three disk-prompt
answers have to arrive after the prompts appear, not before. That is why a
300 ms burst of RETURNs fails: the answers are eaten and cc sits at “insert
object disk” forever. 900 ms plus ~20 spare RETURNs after each cc works.
Spare RETURNs at the shell prompt are harmless.> prompts are line-based and it loads each object before
asking again, so no padding RETURNs may sit between the object names — an
empty line means “end of object list”. ^ is the up-arrow key and pulls in
the libraries; forget it and you get “unresolved external references”
(Main, SYS, MALLOC, ...).-exitscreenshot will not overwrite an existing file, and -limitcycles
is what ends the session (VICE exits with status 1 and prints “cycle limit
reached” — that is normal).image:file autostart argument on a colon, so a full path is ambiguous.Start-Process -ArgumentList joins the array with spaces and quotes
nothing. "-keybuf", "cc vim.c\n" therefore arrived as two arguments and
VICE silently never started (no window, no screenshot). Build the command
line yourself and hand it to System.Diagnostics.ProcessStartInfo.Arguments,
escaping inner " as \" (see build.ps1).\n in a double-quoted string, so
"cc $u.c\n" really is backslash-n — which is what VICE wants.cc name.c → name.o; it prompts for source disk / compiler disk / object
disk. The Shell prompt is $; bye returns to BASIC.link -s with no address links at the start of BASIC: the file begins
01 08, holds 10 SYS 2062, and $080E is a JMP to the C runtime, so
load"name",8,1 + run works.a-z → $41-$5A,
A-Z → $C1-$DA, CRLF → CR, { | } ~ → $DB $DC $DD $DE (ASCII $7B-$7F plus
$60).||. It needs | = LOGO+* = PETSCII $DC, and cc dies
with “*** illegal character” part-way through the file. Use nested ifs.
(&& is fine.)EOF is not declared unless you #include <stdio.h>; test
if (ch < 0) break; instead.void, no // comments, identifiers significant
to 8 characters, int is 16 bits, chars are unsigned and not sign-extended.
Functions returning int need no declaration; declare char *malloc();.peek()/poke() are C128-only — use pointer casts.malloc() (declared char *malloc();) happily gives 19000 bytes. Compiled
programs and the heap end at $D000 by default..c authoritative and .pet derived. In one bad
session the converted PETSCII copy ended up written over the host .c file
(every letter uppercased, CR line endings). It still compiled — the
conversion round-trips — but the source was gone.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.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..getchar() is line buffered: it echoes through the KERNAL's
screen editor and only hands the characters over after RETURN. Useless for an
editor.$C6 holds how many
characters are queued and they sit from $0277. The KERNAL's IRQ handler
scans the matrix and fills that buffer, so this gets every real press as it
happens, with no line buffering and no echo. Pop by shifting the rest down and
decrementing $C6.$91 at startup. Bit 7 is the RUN/STOP flag and it can already be
set when the program starts; treating that as “Esc” made the editor's first
keypress a phantom and swallowed the filename.-keybuf feeds that same buffer, so a program reading $C6 can be
driven from the command line — but the keys race the program's start: type a
filename and it can be eaten by BASIC before the program runs.sys() is using zero page $22-$2A while your routine runs. The manual
lists 34-42 as “temporary storage” for ML, but sys() keeps where to store
A/X/Y back in there: our routine left a screen pointer in $25, so sys()
wrote X/Y into screen RAM ($0404) and then jumped to $0002. Every entry in
vml.s saves $22-$2A, $4B-$60, $FB-$FC on entry and restores them
before returning (zsave/zrest). The old single-row painter had the same
bug; it only showed as one wrong cell at the start of the status row.$CF00. Power C's C stack starts just under
$D000, and it is set up before main() runs, so highmem(0xc000) cannot
move it. The code goes at $C000 (copied there by mlinit() after
highmem(0xc000), before malloc), the parameter block at $C400, the
zero page save area at $C410.sys() paints all 24 rows (scrn), memmove (bmove)
and line-index fix-ups (ladj) are ML too.$028A set to repeat every key, and
VICE -keybuf holds each key for wall-clock time while the machine runs at
warp, so one j became seven. sinit() puts $028A back to 0 (C64
default: only cursor keys, space and DEL repeat).SEI, so the IRQ
cannot append a key half way through the shift.Measured with the jiffy clock at $a2 and a temporary d<draw> e<op> readout
on the status row (since removed):
| before | after | |
|---|---|---|
j (repaint) |
17 jiffies | 0-3 |
| insert a char near the top of a 9 KB file | 103 jiffies | 14 |
$0400, colour RAM $D800 (both directly writable).$D018 = $17 → screen at $0400, character set at $1800 (lower/upper case),
so PETSCII $41-$5A draws as real lowercase and $C1-$DA as uppercase.
Default is $15 (uppercase/graphics at $1000) — restore it on exit.$20-$3F unchanged, $40-$5F minus $40,
$60-$7F minus $20, $A0-$BF minus $40, $C0-$FF minus $80.+ $80. That is the cursor block
and the status row.$00CC non-zero stops the KERNAL cursor blinking (0 turns it on); with
it left at 0 the KERNAL blinked one cell of the status row.open() the file, read the status from 15 (a missing file still
opens - only the status says 62), read the file, close it, close 15 last.$11 down, $91 up, $1D right, $9D left;
RETURN $0D, DEL $14.-exitscreenshot + -limitcycles gives one png per run; read it directly.READY., evidence gone.
So probe in steps — write a marker to $0400 (p[0] = 2 shows as B) and
end with for (;;) { } instead of going on. Whatever is on screen when it
hangs is the last step that worked.shots\cc-*.png, link.png) and make
the script fail per step (“cc vim.c produced no object”) instead of at the
end, or a compile failure looks like a linker failure.The editing commands were driven from build.ps1 -Keys against a scratch file
(ALPHA/BRAVO/CHARLIE/DELTA on work.d81), then read back with c1541
and compared:
dd removes the current line and p puts it below the next one.A, I, O and o insert where they should; RUN/STOP leaves insert mode.:q on a dirty buffer refuses with unsaved - :q! quits; :q! quits and
leaves the file alone.not found - create it? (y/n): y starts an empty
buffer that :wq creates, n goes back to the file: prompt.\x03 in -keybuf arrives as RUN/STOP (PETSCII $03), so a script can
leave insert mode.:dir added to vim.c (9 KB of code) the compiler emitted
return; in main as a jump to garbage (jmp $a657, an address outside the object), so the
editor crashed on :q. Moving dirlist() into its own unit (vdir.c) fixed the size, and
main no longer has a return after sdone() (which never returns anyway). Even at 7.5 KB the
bad jump came back until that return was removed - treat return; in a big main with suspicion.build.ps1 lists the units: vim, vscreen, vview, vedit, vdir, vml.open(5, 8, 0, "$"), skip the load address, then per line
link word (0,0 = end), block count word, text up to a 0 byte.build-improved.bat builds all six units with the improved toolchain from
reference/powerc-re (peephole optimizer + faster runtime objects; the original Power C disk is
untouched) and writes vim-improved.d81; run-improved.bat starts it. The plain build.bat /
run.bat path (original toolchain, work.d81) still works.
Powered by TurnKey Linux.