Files
AnachronautandClaude Opus 5 773b0f8add Put CosmOS on the screen without changing a line of it
The console is now a display controller as well as a port: it owns a font, keeps a cursor,
handles newline, carriage return, backspace and wrapping, and scrolls. That is an ordinary
kind of chip - it is what a video terminal's character generator did - and it is the reason
this rung needed no changes to CosmOS at all. CosmOS already writes bytes to port 0x00.

It writes to BOTH the screen and standard output, which is deliberate. A machine with a
screen and a serial line is an ordinary machine, the emulator's standard output is that
serial line, and one console drives both. It is also what keeps all 165 recorded results
passing under Voyager, and what makes --screen work on the plain SplitBit: there is one
console and it drives everything it has.

Scrolling moves the video device's origin and no memory. The row arriving at the bottom is
cleared because the map is a ring and it holds what was there 128 rows ago; the rows going
off the top are not, and that is a hundred rows of scrollback nothing had to keep. The test
reads the register back rather than looking at the screen, because a console blitting rows
instead would look identical and cost twelve percent of a frame for every line printed.

The font is vendored from Hatchet-GPU with a note saying where it came from, since that
repository is not part of this one. 135 glyphs in ASCII order, which is the thing that makes
it worth keeping - PETSCII's whole inconvenience was that its order was not ASCII's, so a
machine using it needed a translation table in front of every string. Here the machine
subtracts 32. It is stored one bit a pixel and expanded into tile memory at reset: 1,088
bytes against 16 kilobytes.

Voyager gets a keyboard. A window has no standard input, and a machine blocking on it inside
a frame would stop drawing and stop answering, so a front end with a window installs a hook
that the console calls while it has nothing: it keeps the window alive and hands back a key.
The hook has to tell "nobody has typed yet", which happens sixty times a second, apart from
"the window has gone", which is the end of input - one value for both would have made the
first keystroke look like a closed machine. In line mode the console echoes what it is
given, because there is no terminal behind a window to do it and that was always the
terminal's job.

Tests/video.sh grew from 14 checks to 26, half of them about the console rather than the
device: those programs ask the video device for nothing and write bytes to port 0x00 like
every SplitBit program always has. Verified by breaking two things - removing the scroll
failed exactly the two checks about scrolling, and removing the cursor advance failed
exactly the three that depend on it.

Two video checks had quietly depended on palette entry 0 being black, which stopped being
true the moment a machine woke up able to show text. They now set what they are about to
look at, and a new check pins the waking state itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW
2026-08-28 22:26:27 -04:00

158 lines
9.5 KiB
C

// font.c
// GENERATED ONCE from the Hatchet-GPU sprite sheet, and vendored here on purpose.
//
// Hatchet was an earlier attempt at a graphics system for this machine and is not part of
// this repository. What survives of it is this font: an 8x8 sheet in ASCII order, which is
// the thing that makes it worth keeping. PETSCII's whole inconvenience was that its order
// was not ASCII's, so a machine using it needed a translation table in front of every
// string. Here the machine subtracts 32 and is done.
//
// One bit a pixel, most significant bit leftmost, eight bytes a glyph. The screen wants
// eight bits a pixel, so the machine expands this into tile memory at reset rather than
// storing it expanded: 1,088 bytes here against 16 kilobytes there.
//
// Index 0 is ASCII 32, the space, and is blank. Everything through ASCII 126 is where
// ASCII says it is; after that come the drawn extras - box corners and junctions, arrows,
// the card suits - which have no ASCII to be in order with.
#include "font.h"
const unsigned char consoleFont[CONSOLE_FONT_GLYPHS * CONSOLE_FONT_BYTES] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 32 space
0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, // 33 '!'
0x00, 0x36, 0x36, 0x12, 0x00, 0x00, 0x00, 0x00, // 34 '"'
0x00, 0x24, 0x7E, 0x24, 0x24, 0x7E, 0x24, 0x00, // 35 '#'
0x00, 0x18, 0x3E, 0x58, 0x3C, 0x1A, 0x7C, 0x18, // 36 '$'
0x00, 0x62, 0x66, 0x0C, 0x18, 0x30, 0x66, 0x06, // 37 '%'
0x00, 0x38, 0x44, 0x48, 0x30, 0x4A, 0x44, 0x3A, // 38 '&'
0x00, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, // 39 '''
0x00, 0x1E, 0x38, 0x70, 0x70, 0x70, 0x38, 0x1E, // 40 '('
0x00, 0x78, 0x1C, 0x0E, 0x0E, 0x0E, 0x1C, 0x78, // 41 ')'
0x00, 0x00, 0x5A, 0x3C, 0x7E, 0x3C, 0x5A, 0x00, // 42 '*'
0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18, 0x18, // 43 '+'
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x10, // 44 ','
0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x00, 0x00, // 45 '-'
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, // 46 '.'
0x00, 0x03, 0x07, 0x0E, 0x1C, 0x38, 0x70, 0x60, // 47 '/'
0x00, 0x3C, 0x66, 0x4E, 0x5A, 0x72, 0x66, 0x3C, // 48 '0'
0x00, 0x18, 0x38, 0x18, 0x18, 0x18, 0x18, 0x7E, // 49 '1'
0x00, 0x3C, 0x66, 0x46, 0x0C, 0x18, 0x30, 0x7E, // 50 '2'
0x00, 0x3C, 0x66, 0x06, 0x0C, 0x06, 0x66, 0x3C, // 51 '3'
0x00, 0x3C, 0x6C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, // 52 '4'
0x00, 0x7E, 0x60, 0x7C, 0x0E, 0x66, 0x6E, 0x3C, // 53 '5'
0x00, 0x3C, 0x66, 0x60, 0x7C, 0x66, 0x66, 0x3C, // 54 '6'
0x00, 0x7E, 0x66, 0x66, 0x0E, 0x1C, 0x38, 0x30, // 55 '7'
0x00, 0x3C, 0x66, 0x66, 0x3C, 0x66, 0x66, 0x3C, // 56 '8'
0x00, 0x3E, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x06, // 57 '9'
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x00, // 58 ':'
0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x10, // 59 ';'
0x00, 0x0E, 0x1C, 0x38, 0x70, 0x38, 0x1C, 0x0E, // 60 '<'
0x00, 0x00, 0x3E, 0x3E, 0x00, 0x3E, 0x3E, 0x00, // 61 '='
0x00, 0x70, 0x38, 0x1C, 0x0E, 0x1C, 0x38, 0x70, // 62 '>'
0x00, 0x3C, 0x66, 0x06, 0x1C, 0x18, 0x00, 0x18, // 63 '?'
0x00, 0x3C, 0x66, 0x4E, 0x4E, 0x40, 0x60, 0x3C, // 64 '@'
0x00, 0x3E, 0x36, 0x63, 0x63, 0x7F, 0x63, 0x63, // 65 'A'
0x00, 0x7C, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x7C, // 66 'B'
0x00, 0x3E, 0x73, 0x60, 0x60, 0x60, 0x73, 0x3E, // 67 'C'
0x00, 0x7C, 0x66, 0x63, 0x63, 0x63, 0x66, 0x7C, // 68 'D'
0x00, 0x7E, 0x7E, 0x60, 0x78, 0x60, 0x7E, 0x7E, // 69 'E'
0x00, 0x7E, 0x7E, 0x60, 0x7C, 0x7C, 0x60, 0x60, // 70 'F'
0x00, 0x3E, 0x73, 0x60, 0x67, 0x63, 0x73, 0x3E, // 71 'G'
0x00, 0x63, 0x63, 0x63, 0x7F, 0x63, 0x63, 0x63, // 72 'H'
0x00, 0x7E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7E, // 73 'I'
0x00, 0x7F, 0x6C, 0x0C, 0x0C, 0x6C, 0x6C, 0x38, // 74 'J'
0x00, 0x67, 0x6E, 0x7C, 0x78, 0x7E, 0x66, 0x67, // 75 'K'
0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, // 76 'L'
0x00, 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, // 77 'M'
0x00, 0x63, 0x73, 0x7B, 0x7B, 0x6F, 0x67, 0x67, // 78 'N'
0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x66, 0x3C, // 79 'O'
0x00, 0x7E, 0x67, 0x63, 0x67, 0x7E, 0x60, 0x60, // 80 'P'
0x00, 0x3E, 0x77, 0x63, 0x63, 0x77, 0x3E, 0x07, // 81 'Q'
0x00, 0x7E, 0x67, 0x63, 0x66, 0x7C, 0x6E, 0x67, // 82 'R'
0x00, 0x3E, 0x77, 0x70, 0x3E, 0x07, 0x77, 0x3E, // 83 'S'
0x00, 0x7F, 0x6C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, // 84 'T'
0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x3E, // 85 'U'
0x00, 0x63, 0x63, 0x63, 0x77, 0x3E, 0x1C, 0x08, // 86 'V'
0x00, 0x63, 0x63, 0x63, 0x6B, 0x6B, 0x7F, 0x36, // 87 'W'
0x00, 0x66, 0x66, 0x3C, 0x18, 0x3C, 0x66, 0x66, // 88 'X'
0x00, 0x63, 0x77, 0x3E, 0x1C, 0x38, 0x70, 0x60, // 89 'Y'
0x00, 0x7F, 0x7F, 0x0E, 0x1C, 0x38, 0x7F, 0x7F, // 90 'Z'
0x00, 0x3E, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3E, // 91 '['
0x00, 0x60, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, // 92 '\'
0x00, 0x7C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, // 93 ']'
0x00, 0x08, 0x1C, 0x3E, 0x77, 0x63, 0x00, 0x00, // 94 '^'
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, // 95 '_'
0x00, 0x30, 0x38, 0x18, 0x00, 0x00, 0x00, 0x00, // 96 '`'
0x00, 0x00, 0x38, 0x06, 0x3E, 0x66, 0x66, 0x3B, // 97 'a'
0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x7C, // 98 'b'
0x00, 0x00, 0x3C, 0x66, 0x60, 0x60, 0x66, 0x3C, // 99 'c'
0x00, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x66, 0x3E, // 100 'd'
0x00, 0x00, 0x3C, 0x66, 0x7C, 0x60, 0x62, 0x3C, // 101 'e'
0x00, 0x1E, 0x30, 0x60, 0x7C, 0x60, 0x60, 0x60, // 102 'f'
0x00, 0x00, 0x3C, 0x66, 0x66, 0x3E, 0x06, 0x7C, // 103 'g'
0x00, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, // 104 'h'
0x00, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, // 105 'i'
0x00, 0x06, 0x00, 0x06, 0x06, 0x66, 0x66, 0x3C, // 106 'j'
0x00, 0x60, 0x66, 0x6C, 0x78, 0x7C, 0x64, 0x66, // 107 'k'
0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, // 108 'l'
0x00, 0x00, 0xC2, 0x66, 0x7E, 0x7E, 0x66, 0x66, // 109 'm'
0x00, 0x00, 0xEC, 0x76, 0x66, 0x66, 0x66, 0x66, // 110 'n'
0x00, 0x00, 0x3C, 0x66, 0x66, 0x66, 0x66, 0x3C, // 111 'o'
0x00, 0x00, 0x7C, 0x66, 0x66, 0x7C, 0x60, 0x60, // 112 'p'
0x00, 0x00, 0x3C, 0x66, 0x3C, 0x04, 0x19, 0x3E, // 113 'q'
0x00, 0x00, 0x60, 0x7C, 0x6C, 0x60, 0x60, 0x60, // 114 'r'
0x00, 0x00, 0x3C, 0x66, 0x30, 0x0C, 0x66, 0x3C, // 115 's'
0x00, 0x18, 0x18, 0x7E, 0x58, 0x18, 0x18, 0x18, // 116 't'
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3D, // 117 'u'
0x00, 0x00, 0x42, 0x66, 0x66, 0x76, 0x3C, 0x18, // 118 'v'
0x00, 0x00, 0x42, 0x66, 0x66, 0x7E, 0x7E, 0x24, // 119 'w'
0x00, 0x00, 0x66, 0x76, 0x38, 0x1C, 0x6E, 0x66, // 120 'x'
0x00, 0x00, 0x66, 0x66, 0x76, 0x3E, 0x06, 0x7C, // 121 'y'
0x00, 0x00, 0x7E, 0x66, 0x0C, 0x18, 0x32, 0x7E, // 122 'z'
0x00, 0x0E, 0x38, 0x30, 0x18, 0x30, 0x38, 0x0E, // 123 '{'
0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 124 '|'
0x00, 0x70, 0x1C, 0x0C, 0x18, 0x0C, 0x1C, 0x78, // 125 '}'
0x00, 0x00, 0x03, 0x3B, 0x6E, 0x60, 0x00, 0x00, // 126 '~'
0x00, 0x40, 0x60, 0x70, 0x78, 0x7C, 0x10, 0x00, // 127
0x00, 0x00, 0x00, 0x0F, 0x1F, 0x1C, 0x18, 0x18, // 128
0x00, 0x00, 0x00, 0xF0, 0xF8, 0x38, 0x18, 0x18, // 129
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 130
0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3C, 0x18, 0x18, // 131
0x18, 0x18, 0x38, 0xF8, 0xF8, 0x38, 0x18, 0x18, // 132
0xFF, 0xFF, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, // 133
0x03, 0x03, 0x07, 0xFF, 0xFF, 0x07, 0x03, 0x03, // 134
0x01, 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, // 135
0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, // 136
0xFF, 0xFF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 137
0xFF, 0xFF, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 138
0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 139
0x18, 0x18, 0x1C, 0x1F, 0x0F, 0x00, 0x00, 0x00, // 140
0x18, 0x18, 0x38, 0xF8, 0xF0, 0x00, 0x00, 0x00, // 141
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // 142
0x18, 0x18, 0x1C, 0x1F, 0x1F, 0x1C, 0x18, 0x18, // 143
0x18, 0x18, 0x3C, 0xFF, 0xFF, 0x00, 0x00, 0x00, // 144
0xC0, 0xC0, 0xE0, 0xFF, 0xFF, 0xE0, 0xC0, 0xC0, // 145
0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0xFF, 0xFF, // 146
0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, // 147
0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC0, 0x80, // 148
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xFF, 0xFF, // 149
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0xFF, 0xFF, // 150
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, // 151
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 152
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, // 153
0x00, 0x36, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x08, // 154
0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x08, 0x3E, // 155
0x00, 0x08, 0x1C, 0x3E, 0x7F, 0x3E, 0x1C, 0x08, // 156
0x00, 0x1C, 0x1C, 0x7F, 0x7F, 0x7F, 0x08, 0x3E, // 157
0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7E, 0x00, // 158
0x00, 0x3C, 0x66, 0x42, 0x42, 0x66, 0x3C, 0x00, // 159
0x00, 0x7E, 0x42, 0x42, 0x42, 0x42, 0x7E, 0x00, // 160
0x00, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x00, // 161
0x00, 0x02, 0x04, 0x44, 0x28, 0x28, 0x10, 0x00, // 162
0x08, 0x0C, 0x0E, 0xFF, 0xFF, 0x0E, 0x0C, 0x08, // 163
0x18, 0x18, 0x18, 0x18, 0xFF, 0x7E, 0x3C, 0x18, // 164
0x10, 0x30, 0x70, 0xFF, 0xFF, 0x70, 0x30, 0x10, // 165
0x18, 0x3C, 0x7E, 0xFF, 0x18, 0x18, 0x18, 0x18, // 166
};