Skip to content

Commit 95d5112

Browse files
committed
Add an ANSI format start-up logo.
Also make the boot-up much faster - if you want to read the details, press Escape to pause the boot. And we now set the same default mode as the OS, so no monitor resync is required between the BIOS and the OS.
1 parent 7136644 commit 95d5112

File tree

5 files changed

+419
-61
lines changed

5 files changed

+419
-61
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ embedded-sdmmc = { version = "0.5", default-features = false, features = [
6161
"defmt-log"
6262
] }
6363

64+
[build-dependencies]
65+
neotron-common-bios = "0.8.0"
66+
6467
[[bin]]
6568
name = "neotron-pico-bios"
6669
test = false

build.rs

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use std::fs::File;
1313
use std::io::Write;
1414
use std::path::PathBuf;
1515

16+
use neotron_common_bios::video::{Attr, TextBackgroundColour, TextForegroundColour};
17+
1618
fn main() {
1719
// Put `memory.x` in our output directory and ensure it's
1820
// on the linker search path.
@@ -55,4 +57,343 @@ fn main() {
5557

5658
// Write the file
5759
std::fs::write(out.join("version.txt"), output).expect("writing version file");
60+
61+
let logo = std::fs::read_to_string("src/logo.ansi").expect("Can't open logo file");
62+
let mut output = Vec::new();
63+
let mut iter = logo.chars();
64+
let mut attr = Attr::new(
65+
TextForegroundColour::WHITE,
66+
TextBackgroundColour::BLACK,
67+
false,
68+
);
69+
let mut width = 0;
70+
loop {
71+
let Some(ch) = iter.next() else {
72+
break;
73+
};
74+
if ch == '\u{001b}' {
75+
// ANSI escape
76+
if iter.next() == Some('[') {
77+
// CSI
78+
let mut bright = false;
79+
let mut accumulator = 0;
80+
loop {
81+
let next_ch = iter.next();
82+
match (next_ch, accumulator) {
83+
// Bright
84+
(Some(';' | 'm'), 1) => {
85+
bright = true;
86+
accumulator = 0;
87+
}
88+
// Background
89+
(Some(';' | 'm'), 40) => {
90+
attr.set_bg(TextBackgroundColour::BLACK);
91+
accumulator = 0;
92+
}
93+
(Some(';' | 'm'), 41) => {
94+
attr.set_bg(TextBackgroundColour::DARK_RED);
95+
accumulator = 0;
96+
}
97+
(Some(';' | 'm'), 42) => {
98+
attr.set_bg(TextBackgroundColour::DARK_GREEN);
99+
accumulator = 0;
100+
}
101+
(Some(';' | 'm'), 43) => {
102+
attr.set_bg(TextBackgroundColour::YELLOW);
103+
accumulator = 0;
104+
}
105+
(Some(';' | 'm'), 44) => {
106+
attr.set_bg(TextBackgroundColour::BLUE);
107+
accumulator = 0;
108+
}
109+
(Some(';' | 'm'), 45) => {
110+
attr.set_bg(TextBackgroundColour::DARK_MAGENTA);
111+
accumulator = 0;
112+
}
113+
(Some(';' | 'm'), 46) => {
114+
attr.set_bg(TextBackgroundColour::DARK_CYAN);
115+
accumulator = 0;
116+
}
117+
(Some(';' | 'm'), 49) => {
118+
// Default
119+
attr.set_bg(TextBackgroundColour::BLACK);
120+
accumulator = 0;
121+
}
122+
// Foreground
123+
(Some(';' | 'm'), 30) => {
124+
attr.set_fg(TextForegroundColour::BLACK);
125+
accumulator = 0;
126+
}
127+
(Some(';' | 'm'), 31) => {
128+
attr.set_fg(TextForegroundColour::DARK_RED);
129+
accumulator = 0;
130+
}
131+
(Some(';' | 'm'), 32) => {
132+
attr.set_fg(TextForegroundColour::DARK_GREEN);
133+
accumulator = 0;
134+
}
135+
(Some(';' | 'm'), 33) => {
136+
attr.set_fg(TextForegroundColour::YELLOW);
137+
accumulator = 0;
138+
}
139+
(Some(';' | 'm'), 34) => {
140+
attr.set_fg(TextForegroundColour::BLUE);
141+
accumulator = 0;
142+
}
143+
(Some(';' | 'm'), 35) => {
144+
attr.set_fg(TextForegroundColour::DARK_MAGENTA);
145+
accumulator = 0;
146+
}
147+
(Some(';' | 'm'), 36) => {
148+
attr.set_fg(TextForegroundColour::DARK_CYAN);
149+
accumulator = 0;
150+
}
151+
(Some(';' | 'm'), 37) => {
152+
attr.set_fg(TextForegroundColour::GREY);
153+
accumulator = 0;
154+
}
155+
156+
(Some(';' | 'm'), 0) => {
157+
attr.set_fg(TextForegroundColour::GREY);
158+
attr.set_bg(TextBackgroundColour::BLACK);
159+
bright = false;
160+
accumulator = 0;
161+
}
162+
163+
(Some('0'), _) => {
164+
accumulator *= 10;
165+
}
166+
(Some('1'), _) => {
167+
accumulator *= 10;
168+
accumulator += 1;
169+
}
170+
(Some('2'), _) => {
171+
accumulator *= 10;
172+
accumulator += 2;
173+
}
174+
(Some('3'), _) => {
175+
accumulator *= 10;
176+
accumulator += 3;
177+
}
178+
(Some('4'), _) => {
179+
accumulator *= 10;
180+
accumulator += 4;
181+
}
182+
(Some('5'), _) => {
183+
accumulator *= 10;
184+
accumulator += 5;
185+
}
186+
(Some('6'), _) => {
187+
accumulator *= 10;
188+
accumulator += 6;
189+
}
190+
(Some('7'), _) => {
191+
accumulator *= 10;
192+
accumulator += 7;
193+
}
194+
(Some('8'), _) => {
195+
accumulator *= 10;
196+
accumulator += 8;
197+
}
198+
(Some('9'), _) => {
199+
accumulator *= 10;
200+
accumulator += 9;
201+
}
202+
(code, acc) => {
203+
panic!(
204+
"Invalid ANSI sequence detected: code={:?}, acc={:?}",
205+
code, acc
206+
);
207+
}
208+
}
209+
if next_ch == Some('m') {
210+
// sequence is finished
211+
if bright {
212+
match attr.fg() {
213+
TextForegroundColour::DARK_RED => {
214+
attr.set_fg(TextForegroundColour::BRIGHT_RED);
215+
}
216+
TextForegroundColour::DARK_GREEN => {
217+
attr.set_fg(TextForegroundColour::BRIGHT_GREEN);
218+
}
219+
TextForegroundColour::YELLOW => {
220+
attr.set_fg(TextForegroundColour::BRIGHT_YELLOW);
221+
}
222+
TextForegroundColour::BLUE => {
223+
attr.set_fg(TextForegroundColour::BRIGHT_BLUE);
224+
}
225+
TextForegroundColour::DARK_MAGENTA => {
226+
attr.set_fg(TextForegroundColour::BRIGHT_MAGENTA);
227+
}
228+
TextForegroundColour::DARK_CYAN => {
229+
attr.set_fg(TextForegroundColour::BRIGHT_CYAN);
230+
}
231+
TextForegroundColour::GREY => {
232+
attr.set_fg(TextForegroundColour::WHITE);
233+
}
234+
_ => {
235+
// Do nothing
236+
}
237+
}
238+
}
239+
break;
240+
}
241+
}
242+
}
243+
} else if ch == '\n' {
244+
if width < 80 {
245+
// Only emit a new-line if we are not at the end of the line already
246+
output.push(attr.as_u8());
247+
output.push(b'\n');
248+
}
249+
width = 0;
250+
} else {
251+
width += 1;
252+
output.push(attr.as_u8());
253+
output.push(map_char_to_glyph(ch));
254+
};
255+
}
256+
std::fs::write(out.join("logo.bytes"), output).expect("writing logo file");
257+
}
258+
259+
/// Convert a Unicode Scalar Value to a font glyph.
260+
///
261+
/// Zero-width and modifier Unicode Scalar Values (e.g. `U+0301 COMBINING,
262+
/// ACCENT`) are not supported. Normalise your Unicode before calling
263+
/// this function.
264+
fn map_char_to_glyph(input: char) -> u8 {
265+
// This fixed table only works for the default font. When we support
266+
// changing font, we will need to plug-in a different table for each font.
267+
match input {
268+
'\u{0000}'..='\u{007F}' => input as u8,
269+
'\u{00A0}' => 255, // NBSP
270+
'\u{00A1}' => 173, // ¡
271+
'\u{00A2}' => 189, // ¢
272+
'\u{00A3}' => 156, // £
273+
'\u{00A4}' => 207, // ¤
274+
'\u{00A5}' => 190, // ¥
275+
'\u{00A6}' => 221, // ¦
276+
'\u{00A7}' => 245, // §
277+
'\u{00A8}' => 249, // ¨
278+
'\u{00A9}' => 184, // ©
279+
'\u{00AA}' => 166, // ª
280+
'\u{00AB}' => 174, // «
281+
'\u{00AC}' => 170, // ¬
282+
'\u{00AD}' => 240, // SHY
283+
'\u{00AE}' => 169, // ®
284+
'\u{00AF}' => 238, // ¯
285+
'\u{00B0}' => 248, // °
286+
'\u{00B1}' => 241, // ±
287+
'\u{00B2}' => 253, // ²
288+
'\u{00B3}' => 252, // ³
289+
'\u{00B4}' => 239, // ´
290+
'\u{00B5}' => 230, // µ
291+
'\u{00B6}' => 244, // ¶
292+
'\u{00B7}' => 250, // ·
293+
'\u{00B8}' => 247, // ¸
294+
'\u{00B9}' => 251, // ¹
295+
'\u{00BA}' => 167, // º
296+
'\u{00BB}' => 175, // »
297+
'\u{00BC}' => 172, // ¼
298+
'\u{00BD}' => 171, // ½
299+
'\u{00BE}' => 243, // ¾
300+
'\u{00BF}' => 168, // ¿
301+
'\u{00C0}' => 183, // À
302+
'\u{00C1}' => 181, // Á
303+
'\u{00C2}' => 182, // Â
304+
'\u{00C3}' => 199, // Ã
305+
'\u{00C4}' => 142, // Ä
306+
'\u{00C5}' => 143, // Å
307+
'\u{00C6}' => 146, // Æ
308+
'\u{00C7}' => 128, // Ç
309+
'\u{00C8}' => 212, // È
310+
'\u{00C9}' => 144, // É
311+
'\u{00CA}' => 210, // Ê
312+
'\u{00CB}' => 211, // Ë
313+
'\u{00CC}' => 222, // Ì
314+
'\u{00CD}' => 214, // Í
315+
'\u{00CE}' => 215, // Î
316+
'\u{00CF}' => 216, // Ï
317+
'\u{00D0}' => 209, // Ð
318+
'\u{00D1}' => 165, // Ñ
319+
'\u{00D2}' => 227, // Ò
320+
'\u{00D3}' => 224, // Ó
321+
'\u{00D4}' => 226, // Ô
322+
'\u{00D5}' => 229, // Õ
323+
'\u{00D6}' => 153, // Ö
324+
'\u{00D7}' => 158, // ×
325+
'\u{00D8}' => 157, // Ø
326+
'\u{00D9}' => 235, // Ù
327+
'\u{00DA}' => 233, // Ú
328+
'\u{00DB}' => 234, // Û
329+
'\u{00DC}' => 154, // Ü
330+
'\u{00DD}' => 237, // Ý
331+
'\u{00DE}' => 232, // Þ
332+
'\u{00DF}' => 225, // ß
333+
'\u{00E0}' => 133, // à
334+
'\u{00E1}' => 160, // á
335+
'\u{00E2}' => 131, // â
336+
'\u{00E3}' => 198, // ã
337+
'\u{00E4}' => 132, // ä
338+
'\u{00E5}' => 134, // å
339+
'\u{00E6}' => 145, // æ
340+
'\u{00E7}' => 135, // ç
341+
'\u{00E8}' => 138, // è
342+
'\u{00E9}' => 130, // é
343+
'\u{00EA}' => 136, // ê
344+
'\u{00EB}' => 137, // ë
345+
'\u{00EC}' => 141, // ì
346+
'\u{00ED}' => 161, // í
347+
'\u{00EE}' => 140, // î
348+
'\u{00EF}' => 139, // ï
349+
'\u{00F0}' => 208, // ð
350+
'\u{00F1}' => 164, // ñ
351+
'\u{00F2}' => 149, // ò
352+
'\u{00F3}' => 162, // ó
353+
'\u{00F4}' => 147, // ô
354+
'\u{00F5}' => 228, // õ
355+
'\u{00F6}' => 148, // ö
356+
'\u{00F7}' => 246, // ÷
357+
'\u{00F8}' => 155, // ø
358+
'\u{00F9}' => 151, // ù
359+
'\u{00FA}' => 163, // ú
360+
'\u{00FB}' => 150, // û
361+
'\u{00FC}' => 129, // ü
362+
'\u{00FD}' => 236, // ý
363+
'\u{00FE}' => 231, // þ
364+
'\u{00FF}' => 152, // ÿ
365+
'\u{0131}' => 213, // ı
366+
'\u{0192}' => 159, // ƒ
367+
'\u{2017}' => 242, // ‗
368+
'\u{2500}' => 196, // ─
369+
'\u{2502}' => 179, // │
370+
'\u{250C}' => 218, // ┌
371+
'\u{2510}' => 191, // ┐
372+
'\u{2514}' => 192, // └
373+
'\u{2518}' => 217, // ┘
374+
'\u{251C}' => 195, // ├
375+
'\u{2524}' => 180, // ┤
376+
'\u{252C}' => 194, // ┬
377+
'\u{2534}' => 193, // ┴
378+
'\u{253C}' => 197, // ┼
379+
'\u{2550}' => 205, // ═
380+
'\u{2551}' => 186, // ║
381+
'\u{2554}' => 201, // ╔
382+
'\u{2557}' => 187, // ╗
383+
'\u{255A}' => 200, // ╚
384+
'\u{255D}' => 188, // ╝
385+
'\u{2560}' => 204, // ╠
386+
'\u{2563}' => 185, // ╣
387+
'\u{2566}' => 203, // ╦
388+
'\u{2569}' => 202, // ╩
389+
'\u{256C}' => 206, // ╬
390+
'\u{2580}' => 223, // ▀
391+
'\u{2584}' => 220, // ▄
392+
'\u{2588}' => 219, // █
393+
'\u{2591}' => 176, // ░
394+
'\u{2592}' => 177, // ▒
395+
'\u{2593}' => 178, // ▓
396+
'\u{25A0}' => 254, // ■
397+
_ => b'?',
398+
}
58399
}

src/logo.ansi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
╔══════════════════════════════════════════════════════════════════════════════╗
2+
║ ██ █ █████ █████ █████ ████ █████ ██ █ ║
3+
║ ▓ ▓ ▓ ▓ ▓ ▓  ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ║
4+
║ ▓ ▓ ▓ ▓▓▓▓ ▓ ▓  ▓ ▓▓▓▓ ▓ ▓ ▓ ▓ ▓ ║
5+
║ ▒ ▒▒ ▒ ▒ ▒  ▒ ▒ ▒ ▒ ▒ ▒ ▒▒ ║
6+
║ ▒ ▒ ▒▒▒▒▒ ▒▒▒▒▒  ▒ ▒ ▒ ▒▒▒▒▒ ▒ ▒ ║
7+
╚══════════════════════════════════════════════════════════════════════════════╝

0 commit comments

Comments
 (0)