@@ -63,65 +63,49 @@ macro_rules! println {
6363#[ derive( Debug ) ]
6464struct 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
7272impl 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
136262impl 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