diff options
| author | Tianhao Wang <shrik3@riseup.net> | 2023-03-15 18:28:41 +0100 |
|---|---|---|
| committer | Tianhao Wang <shrik3@riseup.net> | 2023-03-15 18:28:41 +0100 |
| commit | 4f316e84f86501270a292ea6868706660fee6b9f (patch) | |
| tree | 3244ba51866fa68f7d3a2186780286e69269b79b /src | |
| parent | 8a229f6467390c26ff1263df84896e1450fc9b76 (diff) | |
usable printf, with some ptr magic
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib.rs | 19 | ||||
| -rw-r--r-- | src/machine/cgascr.rs | 193 | ||||
| -rw-r--r-- | src/machine/mem.rs | 1 | ||||
| -rw-r--r-- | src/machine/mod.rs | 1 |
4 files changed, 168 insertions, 46 deletions
@@ -12,12 +12,17 @@ fn panic(_info: &PanicInfo) -> ! { #[no_mangle] pub extern "C" fn _entry() -> ! { - let scr = CGAScreen::new(25,80); - // scr.show(0,0,'X',0x0f); - // scr.show(0,79,'X',0x0f); - // scr.show(24,0,'X',0x0f); - // scr.show(24,79,'X',0x0f); - // scr.test(); - scr.setpos(10, 10); + let mut scr = CGAScreen::new(); + scr.show_coners(); + scr.setattr(0x1f); + scr.clear(); + scr.show_coners(); + + scr.print("--RuStuBs--\n"); + scr.print(" _._ _,-'\"\"`-._ ~Meow\n"); + scr.print(" (,-.`._,'( |\\`-/|\n"); + scr.print(" `-.-' \\ )-`( , o o)\n"); + scr.print(" `- \\`_`\"'-\n"); + scr.print("it works!\n"); loop {} } diff --git a/src/machine/cgascr.rs b/src/machine/cgascr.rs index dd019d7..a529b8b 100644 --- a/src/machine/cgascr.rs +++ b/src/machine/cgascr.rs @@ -1,48 +1,156 @@ use crate::arch::x86_64::io_port::*; use crate::arch::x86_64::misc::*; +use core::{slice,ptr,str}; +// I would consider these cga parameters constant. +// the scroll() and clear() works with the assumption +// that the CGAScreen memory buffer is 64-bit aligned +// luckily it is. +// if any changes, you'd better hope the assumption still +// holds +// For each character, it takes 2 byte in the buffer +// (one for char and one for attribute) +// Therefore the MAX_COLS should be a multiple of 4 +const MAX_COLS:usize = 80; +const MAX_ROWS:usize = 25; const CGA_BUFFER_START:*mut u8 = 0xb8000 as *mut u8; +const CGA_BUFFER_BYTE_SIZE:usize = MAX_COLS * MAX_ROWS *2; + + +// THESE TWO ARE USED TO DO BATCH OPERATIONS ON CGA BUFFER +// MEMORY, HOPEFULLY MAKE IT FASTER. +// I.E. SETTING 4 CHARACTERS AT ONCE. +const CGA_BUFFER_START_64:*mut u64 = 0xb8000 as *mut u64; +const CGA_BUFFER_QWORD_SIZE:usize = CGA_BUFFER_BYTE_SIZE / 8; +const CGA_BUFFER_QWORDS_PER_ROW:usize = MAX_COLS / 4; + const IR_PORT:u16 = 0x3d4; const DR_PORT:u16 = 0x3d5; #[allow(dead_code)] -pub struct CGAScreen{ - pub max_cows:u32, - pub max_rows:u32, +pub struct CGAScreen <'a>{ + pub cga_mem:&'a mut [u8], + cursor_r: usize, + cursor_c: usize, + attr: u8 } #[allow(dead_code)] -impl CGAScreen{ - pub fn new(rows:u32, cols:u32) -> Self { - Self {max_rows:rows, max_cows:cols} +impl <'a> CGAScreen<'a>{ + pub fn new() -> Self { + Self {cga_mem: unsafe{slice::from_raw_parts_mut(CGA_BUFFER_START, 2*MAX_COLS*MAX_ROWS)}, + cursor_r:0, + cursor_c:0, + attr:0x0f + } } - - - fn cal_offset(&self,row:u32, col:u32) -> u32{ - col + row*self.max_cows + + #[inline(always)] + fn cal_offset(&self,row:usize, col:usize) -> usize{ + col + row*MAX_COLS } - // this function should be the only one that "directly touches" - // the memory by address. - // and since it's unsafe, it shouldn't be public - pub fn show(&self, row:u32, col:u32, c:char, attr:u8){ + pub fn show(&self, row:usize, col:usize, c:char, attr:u8){ let index = self.cal_offset(row, col); unsafe{ *CGA_BUFFER_START.offset(index as isize * 2) = c as u8; *CGA_BUFFER_START.offset(index as isize * 2 + 1) = attr; } + } + + pub fn putchar(&mut self, ch:char){ + if ch == '\n'{ + self.cursor_r += 1; + self.cursor_c = 0; + self._check_scroll(); + }else{ + self.show(self.cursor_r, self.cursor_c,ch,self.attr); + self.cursor_c += 1; + if self.cursor_c>= MAX_COLS { + self.cursor_c = 0; + self.cursor_r += 1; + self._check_scroll(); + } + } + self.setpos(self.cursor_r, self.cursor_c); + } + + fn _check_scroll(&mut self ){ + if self.cursor_r >= MAX_ROWS { + self.scroll(1); + self.cursor_r -= 1; + } + } + + pub fn scroll(&self, lines: u32) { + // TODO + // sanity check + if lines >= MAX_COLS as u32{ + self.clear(); + } + + if lines == 0 { + return; + } + // behold the magic ... (oh fuck me) + let mut i:usize = lines as usize - 1; + loop{ + if i == MAX_ROWS {break;} + let offset_src = (i*CGA_BUFFER_QWORDS_PER_ROW) as isize; + let offset_dist = offset_src - (lines*CGA_BUFFER_QWORDS_PER_ROW as u32) as isize; + unsafe{ + ptr::copy_nonoverlapping( + CGA_BUFFER_START_64.offset(offset_src), + CGA_BUFFER_START_64.offset(offset_dist), + CGA_BUFFER_QWORDS_PER_ROW); + } + i += 1; + } + + i = MAX_ROWS - lines as usize; + loop{ + if i == MAX_ROWS {break;} + self.clearline(i); + i += 1; + } + // clear the remaining lines: + } + + pub fn clear(&self){ + // remember to swap the endian.. + let b : u8 = self.attr; + let mut base:u64 = (b as u64) << 8; + base += base << 16; + base += base << 32; + + + for i in 0..CGA_BUFFER_QWORD_SIZE{ + unsafe{*CGA_BUFFER_START_64.offset(i as isize) = base} + } + } + + fn clearline(&self, line:usize){ + + let b : u8 = self.attr; + let mut base:u64 = (b as u64) << 8; + base += base << 16; + base += base << 32; + let start_offset_qw:isize = (line as isize) * CGA_BUFFER_QWORDS_PER_ROW as isize; + let end_offset_qw:isize = start_offset_qw + CGA_BUFFER_QWORDS_PER_ROW as isize; + unsafe{ + for i in start_offset_qw..end_offset_qw{ + *CGA_BUFFER_START_64.offset(i) = base; + } + } + } - // pub fn putchar(&self, ch:char){ - // - // } - pub fn setpos(&self, row:u32, col:u32){ + pub fn setpos(&mut self, row:usize, col:usize){ // io ports for instruction register and data register let offset = self.cal_offset(row,col); - // set lower byte outb(IR_PORT, 15 as u8); delay(); @@ -53,10 +161,18 @@ impl CGAScreen{ delay(); outb(DR_PORT, (offset >> 8) as u8); delay(); + self.cursor_r = row; + self.cursor_c = col; + } + pub fn getpos_xy(&self, row:& mut u32, col:& mut u32){ + let offset = Self::getpos_offset(); + *row = offset % MAX_COLS as u32; + *col = offset / MAX_COLS as u32; } - pub fn getoffset() -> u32 { + #[allow(arithmetic_overflow)] + pub fn getpos_offset() -> u32 { // read higher byte outb(IR_PORT, 14 as u8); let mut offset = inb(DR_PORT); @@ -67,30 +183,29 @@ impl CGAScreen{ offset as u32 } - pub fn getpos(&self, row:& mut u32, cow:& mut u32){ - let offset = Self::getoffset(); - *row = offset % self.max_cows; - *cow = offset / self.max_cows; - } - // Sanity Check of the cgascreen pub fn test(&self){ - let mut r = 0; - let mut c = 0; - - let mut counter = 0; - while r<self.max_rows { - while c<self.max_cows { - let ch = (counter & 0xff) as u8; - self.show(r,c,ch as char, ch); - counter += 1; - c+=1; - } - r+=1; - c=0; + // TODO + + } + + pub fn show_coners(&self){ + self.show(0,0,0xda as char,self.attr); + self.show(0,79,0xbf as char,self.attr); + self.show(24,0,0xc0 as char,self.attr); + self.show(24,79,0xd9 as char,self.attr); + } + + pub fn print(&mut self, s:&str){ + for c in s.bytes(){ + self.putchar(c as char); } + } + + pub fn setattr(&mut self, attr:u8){ + self.attr = attr; } diff --git a/src/machine/mem.rs b/src/machine/mem.rs new file mode 100644 index 0000000..a5641a1 --- /dev/null +++ b/src/machine/mem.rs @@ -0,0 +1 @@ +// TODO implment 64 chunk (speedy) memcpy diff --git a/src/machine/mod.rs b/src/machine/mod.rs index 4622e0b..19adb3a 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1 +1,2 @@ pub mod cgascr; +pub mod mem; |
