Make the cursor blink while the machine is waiting, and show how the palette works
THE CURSOR DID NOT BLINK, and the reason is worth stating: it blinks on the machine's clock, and the machine's clock had stopped. A console waiting on a key stops the CPU, so no cycles passed, so the phase never moved - and the one moment somebody is looking at a cursor is the moment they are being asked to type. Waiting is now charged as IDLE CYCLES, which is what they were built for: a machine stopped on a device is not using memory, the same distinction WAIT makes, arrived at from the other direction. And the devices are told as it happens rather than when the instruction finally finishes, because a display controller does not stop blinking because the processor is waiting on a keyboard, any more than a disk stops turning. A keyboard file can now say NOTHING happened. A zero is a byte no keyboard sends, so it is free to mean "a moment went by with nobody typing" - which is the commonest thing behind a window and the only thing a file otherwise could not express. That unlocked the whole waiting path: three checks that the cursor is lit, then dark half a second later, then lit again, which is what blinking is. And Programs/Examples/colours.asm, because the palette had nowhere a newcomer could read it. It prints the sixteen pairs, prints each one again turned inside out, and then CHANGES ONE by writing three bytes into the palette - so the difference between using the colours a machine wakes up with and choosing your own is visible in one program. Its header explains what a cell is, what the attribute nibble does, why palette entries are four bytes rather than three, and why video memory has to be reached through the controller. The manual now says where the palette lives and points at it. SplitLint found a redundant RSTA in the example, which was worth acting on rather than suppressing: the zero was already in A from the mode write two lines up, and saying so in a comment teaches that SETD does not touch A, which is a thing worth knowing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
This commit is contained in:
co-authored by
Claude Opus 5
parent
d6feddd1b6
commit
ff4b025058
+48
-1
@@ -109,13 +109,27 @@ say() {
|
||||
done
|
||||
}
|
||||
|
||||
# Waits, as a keyboard file: a zero is a moment of nobody typing, which is the commonest
|
||||
# thing that happens behind a window and the only thing a file otherwise cannot say.
|
||||
waiting() {
|
||||
python3 -c "import sys; sys.stdout.buffer.write(b'\\x00' * int(sys.argv[1]) + b'x')" "$1" \
|
||||
> "$BUILD/waits.keys"
|
||||
echo "$BUILD/waits.keys"
|
||||
}
|
||||
|
||||
# Assembles what is on standard input, runs it, and leaves the picture in $BUILD/<name>.ppm.
|
||||
# A second argument names a keyboard file to feed it.
|
||||
run() {
|
||||
local name="$1"
|
||||
cat > "$BUILD/$name.asm"
|
||||
"$ASM" "$BUILD/$name.asm" -o "$BUILD/$name.bin" >"$BUILD/$name.log" 2>&1 || {
|
||||
echo "could not assemble $name"; sed 's/^/ /' "$BUILD/$name.log"; return 1; }
|
||||
"$EMU" --fast --screen "$BUILD/$name.ppm" "$BUILD/$name.bin" > "$BUILD/$name.out" 2>&1
|
||||
if [ -n "${2:-}" ]; then
|
||||
"$EMU" --fast --keyboard "$2" --screen "$BUILD/$name.ppm" "$BUILD/$name.bin" \
|
||||
> "$BUILD/$name.out" 2>&1
|
||||
else
|
||||
"$EMU" --fast --screen "$BUILD/$name.ppm" "$BUILD/$name.bin" > "$BUILD/$name.out" 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
# One pixel out of a PPM, as "r,g,b".
|
||||
@@ -478,6 +492,39 @@ coloured cursorblink 0 0 "0,0,0" \
|
||||
&& result ok "the cursor blinks off again" "half a second later, dark" \
|
||||
|| result no "the cursor blinks off again" "got $(pixel cursorblink 0 0)"
|
||||
|
||||
# ---- Blinking while the machine is stopped ----
|
||||
#
|
||||
# THE MACHINE IS NOT RUNNING while it waits for a key, and that is exactly when somebody is
|
||||
# looking at the cursor. Time still has to reach the devices: a display controller does not
|
||||
# stop blinking because the processor is waiting on a keyboard, any more than a disk stops
|
||||
# turning. Waiting is charged as idle cycles and the devices are told as it happens, so the
|
||||
# phase below is a pure function of how long nobody typed for.
|
||||
#
|
||||
# Key mode, so nothing is echoed and the cursor stays in the corner where it can be seen.
|
||||
BLINKER='#Program
|
||||
start:
|
||||
INIA 0x05
|
||||
OUTA 0x02
|
||||
INA 0x00
|
||||
HALT
|
||||
#Vectors
|
||||
Boot start'
|
||||
|
||||
echo "$BLINKER" | run blinkon "$(waiting 4)" || exit 1
|
||||
coloured blinkon 0 0 "216,216,216" \
|
||||
&& result ok "the cursor is lit while waiting" "sixty thousand cycles in" \
|
||||
|| result no "the cursor is lit while waiting" "got $(pixel blinkon 0 0)"
|
||||
|
||||
echo "$BLINKER" | run blinkoff "$(waiting 40)" || exit 1
|
||||
coloured blinkoff 0 0 "0,0,0" \
|
||||
&& result ok "and dark half a second later" "the machine's clock, not the host's" \
|
||||
|| result no "and dark half a second later" "got $(pixel blinkoff 0 0)"
|
||||
|
||||
echo "$BLINKER" | run blinkagain "$(waiting 70)" || exit 1
|
||||
coloured blinkagain 0 0 "216,216,216" \
|
||||
&& result ok "and lit again after that" "which is what blinking is" \
|
||||
|| result no "and lit again after that" "got $(pixel blinkagain 0 0)"
|
||||
|
||||
# And what scrolled off the top is still in the map, which is scrollback nothing had to keep.
|
||||
{ printf '#Program\nstart:\n'
|
||||
say "A"
|
||||
|
||||
Reference in New Issue
Block a user