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