Skip to content

Commit f9e94c8

Browse files
Bump common-bios version and fix scrolling.
1 parent f0be8ec commit f9e94c8

File tree

2 files changed

+198
-43
lines changed

2 files changed

+198
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ codegen-units = 1
3030
opt-level = "s"
3131

3232
[dependencies]
33-
neotron-common-bios = "0.1.0"
33+
neotron-common-bios = "0.4.0"
3434
r0 = "1.0"
3535
postcard = "0.5"
3636
serde = { version = "1.0", default-features = false }

src/lib.rs

Lines changed: 197 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -63,65 +63,49 @@ macro_rules! println {
6363
#[derive(Debug)]
6464
struct VgaConsole {
6565
addr: *mut u8,
66-
width: u8,
67-
height: u8,
68-
row: u8,
69-
col: u8,
66+
width: isize,
67+
height: isize,
68+
row: isize,
69+
col: isize,
7070
}
7171

7272
impl VgaConsole {
7373
const DEFAULT_ATTR: u8 = (2 << 3) | (1 << 0);
7474

7575
fn move_char_right(&mut self) {
7676
self.col += 1;
77-
if self.col == self.width {
78-
self.col = 0;
79-
self.move_char_down();
80-
}
8177
}
8278

8379
fn move_char_down(&mut self) {
8480
self.row += 1;
85-
if self.row == self.height {
86-
self.scroll_page();
87-
self.row = self.height - 1;
88-
}
89-
}
90-
91-
fn read(&self) -> (u8, u8) {
92-
let offset =
93-
((isize::from(self.row) * isize::from(self.width)) + isize::from(self.col)) * 2;
94-
let glyph = unsafe { core::ptr::read_volatile(self.addr.offset(offset)) };
95-
let attr = unsafe { core::ptr::read_volatile(self.addr.offset(offset + 1)) };
96-
(glyph, attr)
9781
}
9882

99-
fn find_start_row(&mut self) {
100-
for row in 0..self.height {
101-
self.row = row;
102-
let g = self.read().0;
103-
if (g == b'\0') || (g == b' ') {
104-
// Found a line with nothing on it - start here!
105-
break;
106-
}
83+
fn scroll_as_required(&mut self) {
84+
if self.col == self.width {
85+
self.col = 0;
86+
self.row += 1;
87+
}
88+
if self.row == self.height {
89+
self.row = self.height - 1;
90+
self.scroll_page();
10791
}
10892
}
10993

11094
fn write(&mut self, glyph: u8, attr: Option<u8>) {
111-
let offset =
112-
((isize::from(self.row) * isize::from(self.width)) + isize::from(self.col)) * 2;
95+
let offset = ((self.row * self.width) + self.col) * 2;
11396
unsafe { core::ptr::write_volatile(self.addr.offset(offset), glyph) };
11497
if let Some(a) = attr {
11598
unsafe { core::ptr::write_volatile(self.addr.offset(offset + 1), a) };
11699
}
117100
}
118101

119102
fn scroll_page(&mut self) {
103+
let row_len_bytes = self.width * 2;
120104
unsafe {
121105
core::ptr::copy(
122-
self.addr.offset(isize::from(self.width * 2)),
106+
self.addr.offset(row_len_bytes),
123107
self.addr,
124-
usize::from(self.width) * usize::from(self.height - 1) * 2,
108+
(row_len_bytes * (self.height - 1)) as usize,
125109
);
126110
// Blank bottom line
127111
for col in 0..self.width {
@@ -131,6 +115,148 @@ impl VgaConsole {
131115
self.col = 0;
132116
}
133117
}
118+
119+
/// Convert a Unicode Scalar Value to a font glyph.
120+
///
121+
/// Zero-width and modifier Unicode Scalar Values (e.g. `U+0301 COMBINING,
122+
/// ACCENT`) are not supported. Normalise your Unicode before calling
123+
/// this function.
124+
fn map_char_to_glyph(input: char) -> u8 {
125+
// This fixed table only works for the default font. When we support
126+
// changing font, we will need to plug-in a different table for each font.
127+
match input {
128+
'\u{0000}'..='\u{007F}' => input as u8,
129+
'\u{00A0}' => 255, // NBSP
130+
'\u{00A1}' => 173, // ¡
131+
'\u{00A2}' => 189, // ¢
132+
'\u{00A3}' => 156, // £
133+
'\u{00A4}' => 207, // ¤
134+
'\u{00A5}' => 190, // ¥
135+
'\u{00A6}' => 221, // ¦
136+
'\u{00A7}' => 245, // §
137+
'\u{00A8}' => 249, // ¨
138+
'\u{00A9}' => 184, // ©
139+
'\u{00AA}' => 166, // ª
140+
'\u{00AB}' => 174, // «
141+
'\u{00AC}' => 170, // ¬
142+
'\u{00AD}' => 240, // SHY
143+
'\u{00AE}' => 169, // ®
144+
'\u{00AF}' => 238, // ¯
145+
'\u{00B0}' => 248, // °
146+
'\u{00B1}' => 241, // ±
147+
'\u{00B2}' => 253, // ²
148+
'\u{00B3}' => 252, // ³
149+
'\u{00B4}' => 239, // ´
150+
'\u{00B5}' => 230, // µ
151+
'\u{00B6}' => 244, // ¶
152+
'\u{00B7}' => 250, // ·
153+
'\u{00B8}' => 247, // ¸
154+
'\u{00B9}' => 251, // ¹
155+
'\u{00BA}' => 167, // º
156+
'\u{00BB}' => 175, // »
157+
'\u{00BC}' => 172, // ¼
158+
'\u{00BD}' => 171, // ½
159+
'\u{00BE}' => 243, // ¾
160+
'\u{00BF}' => 168, // ¿
161+
'\u{00C0}' => 183, // À
162+
'\u{00C1}' => 181, // Á
163+
'\u{00C2}' => 182, // Â
164+
'\u{00C3}' => 199, // Ã
165+
'\u{00C4}' => 142, // Ä
166+
'\u{00C5}' => 143, // Å
167+
'\u{00C6}' => 146, // Æ
168+
'\u{00C7}' => 128, // Ç
169+
'\u{00C8}' => 212, // È
170+
'\u{00C9}' => 144, // É
171+
'\u{00CA}' => 210, // Ê
172+
'\u{00CB}' => 211, // Ë
173+
'\u{00CC}' => 222, // Ì
174+
'\u{00CD}' => 214, // Í
175+
'\u{00CE}' => 215, // Î
176+
'\u{00CF}' => 216, // Ï
177+
'\u{00D0}' => 209, // Ð
178+
'\u{00D1}' => 165, // Ñ
179+
'\u{00D2}' => 227, // Ò
180+
'\u{00D3}' => 224, // Ó
181+
'\u{00D4}' => 226, // Ô
182+
'\u{00D5}' => 229, // Õ
183+
'\u{00D6}' => 153, // Ö
184+
'\u{00D7}' => 158, // ×
185+
'\u{00D8}' => 157, // Ø
186+
'\u{00D9}' => 235, // Ù
187+
'\u{00DA}' => 233, // Ú
188+
'\u{00DB}' => 234, // Û
189+
'\u{00DC}' => 154, // Ü
190+
'\u{00DD}' => 237, // Ý
191+
'\u{00DE}' => 232, // Þ
192+
'\u{00DF}' => 225, // ß
193+
'\u{00E0}' => 133, // à
194+
'\u{00E1}' => 160, // á
195+
'\u{00E2}' => 131, // â
196+
'\u{00E3}' => 198, // ã
197+
'\u{00E4}' => 132, // ä
198+
'\u{00E5}' => 134, // å
199+
'\u{00E6}' => 145, // æ
200+
'\u{00E7}' => 135, // ç
201+
'\u{00E8}' => 138, // è
202+
'\u{00E9}' => 130, // é
203+
'\u{00EA}' => 136, // ê
204+
'\u{00EB}' => 137, // ë
205+
'\u{00EC}' => 141, // ì
206+
'\u{00ED}' => 161, // í
207+
'\u{00EE}' => 140, // î
208+
'\u{00EF}' => 139, // ï
209+
'\u{00F0}' => 208, // ð
210+
'\u{00F1}' => 164, // ñ
211+
'\u{00F2}' => 149, // ò
212+
'\u{00F3}' => 162, // ó
213+
'\u{00F4}' => 147, // ô
214+
'\u{00F5}' => 228, // õ
215+
'\u{00F6}' => 148, // ö
216+
'\u{00F7}' => 246, // ÷
217+
'\u{00F8}' => 155, // ø
218+
'\u{00F9}' => 151, // ù
219+
'\u{00FA}' => 163, // ú
220+
'\u{00FB}' => 150, // û
221+
'\u{00FC}' => 129, // ü
222+
'\u{00FD}' => 236, // ý
223+
'\u{00FE}' => 231, // þ
224+
'\u{00FF}' => 152, // ÿ
225+
'\u{0131}' => 213, // ı
226+
'\u{0192}' => 159, // ƒ
227+
'\u{2017}' => 242, // ‗
228+
'\u{2500}' => 196, // ─
229+
'\u{2502}' => 179, // │
230+
'\u{250C}' => 218, // ┌
231+
'\u{2510}' => 191, // ┐
232+
'\u{2514}' => 192, // └
233+
'\u{2518}' => 217, // ┘
234+
'\u{251C}' => 195, // ├
235+
'\u{2524}' => 180, // ┤
236+
'\u{252C}' => 194, // ┬
237+
'\u{2534}' => 193, // ┴
238+
'\u{253C}' => 197, // ┼
239+
'\u{2550}' => 205, // ═
240+
'\u{2551}' => 186, // ║
241+
'\u{2554}' => 201, // ╔
242+
'\u{2557}' => 187, // ╗
243+
'\u{255A}' => 200, // ╚
244+
'\u{255D}' => 188, // ╝
245+
'\u{2560}' => 204, // ╠
246+
'\u{2563}' => 185, // ╣
247+
'\u{2566}' => 203, // ╦
248+
'\u{2569}' => 202, // ╩
249+
'\u{256C}' => 206, // ╬
250+
'\u{2580}' => 223, // ▀
251+
'\u{2584}' => 220, // ▄
252+
'\u{2588}' => 219, // █
253+
'\u{2591}' => 176, // ░
254+
'\u{2592}' => 177, // ▒
255+
'\u{2593}' => 178, // ▓
256+
'\u{25A0}' => 254, // ■
257+
_ => b'?',
258+
}
259+
}
134260
}
135261

136262
impl core::fmt::Write for VgaConsole {
@@ -144,12 +270,9 @@ impl core::fmt::Write for VgaConsole {
144270
self.col = 0;
145271
self.move_char_down();
146272
}
147-
b if b <= '\u{00FF}' => {
148-
self.write(b as u8, None);
149-
self.move_char_right();
150-
}
151273
_ => {
152-
self.write(b'?', None);
274+
self.scroll_as_required();
275+
self.write(Self::map_char_to_glyph(ch), None);
153276
self.move_char_right();
154277
}
155278
}
@@ -285,22 +408,27 @@ pub extern "C" fn main(api: &'static bios::Api) -> ! {
285408
let config = Config::load().unwrap_or_else(|_| Config::default());
286409

287410
if config.has_vga_console() {
411+
// Try and set 80x50 mode for that authentic Windows NT bootloader feel
412+
(api.video_set_mode)(bios::video::Mode::new(
413+
bios::video::Timing::T640x400,
414+
bios::video::Format::Text8x8,
415+
));
416+
// Work with whatever we get
288417
let mode = (api.video_get_mode)();
289418
let (width, height) = (mode.text_width(), mode.text_height());
290419

291420
if let (Some(width), Some(height)) = (width, height) {
292-
let mut vga = VgaConsole {
421+
let vga = VgaConsole {
293422
addr: (api.video_get_framebuffer)(),
294-
width: width as u8,
295-
height: height as u8,
423+
width: width as isize,
424+
height: height as isize,
296425
row: 0,
297426
col: 0,
298427
};
299-
vga.find_start_row();
300428
unsafe {
301429
VGA_CONSOLE = Some(vga);
302430
}
303-
println!("Configured VGA console");
431+
println!("Configured VGA console {}x{}", width, height);
304432
}
305433
}
306434

@@ -312,6 +440,33 @@ pub extern "C" fn main(api: &'static bios::Api) -> ! {
312440

313441
// Now we can call println!
314442
println!("Welcome to {}!", OS_VERSION);
443+
println!("Copyright © Jonathan 'theJPster' Pallant and the Neotron Developers, 2022");
444+
445+
for region_idx in 0..=255 {
446+
match (api.memory_get_region)(region_idx) {
447+
bios::Result::Ok(region) => {
448+
println!("Region {}: {}", region_idx, region);
449+
}
450+
_ => {
451+
// Ran out of regions (we assume they are consecutive)
452+
break;
453+
}
454+
}
455+
}
456+
457+
// Some text, to force the console to scroll.
458+
for i in 0..50 {
459+
for _x in 0..50 - i {
460+
print!(".");
461+
}
462+
println!("{}", i);
463+
// An awfully crude delay loop. We all the API to ensure the loop isn't
464+
// optimised away.
465+
for _delay in 0..2_000_000 {
466+
let _ver = (api.api_version_get)();
467+
}
468+
}
469+
315470
panic!("Testing a panic...");
316471
}
317472

0 commit comments

Comments
 (0)