]> git.lizzy.rs Git - loadnothing.git/blob - stage2/src/vga.rs
22499b79add55a6fe44342b791562f18e53489af
[loadnothing.git] / stage2 / src / vga.rs
1 use core::ops::{AddAssign, Deref, DerefMut, Shl, Sub};
2
3 use volatile::Volatile;
4
5 #[allow(dead_code)]
6 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
7 #[repr(u8)]
8 pub enum Color {
9     Black = 0,
10     Blue = 1,
11     Green = 2,
12     Cyan = 3,
13     Red = 4,
14     Magenta = 5,
15     Brown = 6,
16     LightGray = 7,
17     DarkGray = 8,
18     LightBlue = 9,
19     LightGreen = 10,
20     LightCyan = 11,
21     LightRed = 12,
22     Pink = 13,
23     Yellow = 14,
24     White = 15,
25 }
26
27 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
28 #[repr(transparent)]
29 pub struct ColorCode(u8);
30
31 impl ColorCode {
32     pub fn new(foreground: Color, background: Color) -> ColorCode {
33         ColorCode((background as u8).shl(4) | (foreground as u8))
34     }
35 }
36
37 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
38 #[repr(C)]
39 struct ScreenChar {
40     ascii_character: u8,
41     color_code: ColorCode,
42 }
43
44 impl Deref for ScreenChar {
45     type Target = ScreenChar;
46
47     fn deref(&self) -> &Self::Target {
48         self
49     }
50 }
51
52 impl DerefMut for ScreenChar {
53     fn deref_mut(&mut self) -> &mut Self::Target {
54         self
55     }
56 }
57
58 const BUFFER_WIDTH: usize = 80;
59 const BUFFER_HEIGHT: usize = 25;
60
61 #[repr(transparent)]
62 struct Buffer {
63     chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
64 }
65
66 pub struct Writer {
67     row_position: usize,
68     column_position: usize,
69     color_code: ColorCode,
70     buffer: &'static mut Buffer,
71 }
72
73 impl Writer {
74     #[inline(always)]
75     pub fn write_byte(&mut self, byte: u8) {
76         match byte {
77             b'\n' => self.new_line(),
78             byte => {
79                 if self.column_position >= BUFFER_WIDTH {
80                     self.new_line();
81                 }
82
83                 let row = self.row_position;
84                 let col = self.column_position;
85
86                 let color_code = self.color_code;
87                 self.buffer.chars[row][col].write(ScreenChar {
88                     ascii_character: byte,
89                     color_code,
90                 });
91
92                 self.column_position.add_assign(1);
93             },
94         }
95     }
96
97     #[inline(always)]
98     pub fn write_string(&mut self, s: &str) {
99         for byte in s.bytes() {
100             match byte {
101                 // Printable ASCII character or \n
102                 0x20..=0x7e | b'\n' => self.write_byte(byte),
103                 // Not printable, write error char instead
104                 _ => self.write_byte(0xfe),
105             }
106         }
107     }
108
109     #[inline(always)]
110     fn new_line(&mut self) {
111         if self.row_position >= BUFFER_HEIGHT {
112             for row in 1..BUFFER_HEIGHT {
113                 for col in 0..BUFFER_WIDTH {
114                     let character = self.buffer.chars[row][col].read();
115                     self.buffer.chars[row.sub(1)][col].write(character);
116                 }
117             }
118
119             self.clear_row(BUFFER_HEIGHT.sub(1));
120         }
121
122         self.row_position.add_assign(1);
123         self.column_position = 0;
124     }
125
126     fn clear_row(&mut self, row: usize) {
127         let blank = ScreenChar {
128             ascii_character: b' ',
129             color_code: self.color_code,
130         };
131
132         for col in 0..BUFFER_WIDTH {
133             self.buffer.chars[row][col].write(blank);
134         }
135     }
136 }
137
138 pub fn test_print() {
139     let mut writer = Writer {
140         row_position: 1,
141         column_position: 0,
142         color_code: ColorCode::new(Color::Yellow, Color::Black),
143         buffer: unsafe { &mut *(0xb8000 as *mut Buffer) },
144     };
145
146     writer.write_string("Hello Stage2!");
147 }