aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs19
-rw-r--r--src/machine/cgascr.rs193
-rw-r--r--src/machine/mem.rs1
-rw-r--r--src/machine/mod.rs1
4 files changed, 168 insertions, 46 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 0f005ae..9483130 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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;