Sure, I'll edit this in a second. The VGA class is mostly the C++ version of James's. I'll release the Vesa and vm86 drivers when I post the next release on OS Development
Code:#include <base/types.h> #include <base/io.h> #include <base/tasks.h> #include <display/base.h> #include <display/vga.h> void vga::init(void) { this->background = 0; this->foreground = 15; this->video_memory = (u16int *)0xB8000; this->cursor_x = 0; this->cursor_y = 0; this->clear(); } void vga::clear(void) { u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F); u16int blank = 0x20 /* space */ | (attributeByte << 8); int i; for (i = 0; i < 80*25; i++) { this->video_memory[i] = blank; } this->cursor_x = 0; this->cursor_y = 0; this->move(); } void vga::putc(char c) { // The background colour is black (0), the foreground is white (15). u8int backColour = this->background; u8int foreColour = this->foreground; // The attribute byte is made up of two nibbles - the lower being the // foreground colour, and the upper the background colour. u8int attributeByte = (backColour << 4) | (foreColour & 0x0F); // The attribute byte is the top 8 bits of the word we have to send to the // VGA board. u16int attribute = attributeByte << 8; u16int *location; // Handle a backspace, by moving the cursor back one space if (c == 0x08 && this->cursor_x) { this->cursor_x--; } // Handle a tab by increasing the cursor's X, but only to a point // where it is divisible by 8. else if (c == 0x09) { this->cursor_x = (this->cursor_x+8) & ~(8-1); } // Handle carriage return else if (c == '\r') { this->cursor_x = 0; } // Handle newline by moving cursor back to left and increasing the row else if (c == '\n') { this->cursor_x = 0; this->cursor_y++; } // Handle any other printable character. else if(c >= ' ') { location = this->video_memory + (this->cursor_y*80 + this->cursor_x); *location = c | attribute; cursor_x++; } // Check if we need to insert a new line because we have reached the end // of the screen. if (this->cursor_x >= 80) { this->cursor_x = 0; this->cursor_y ++; } // Scroll the screen if needed. scroll(); // Move the hardware cursor. this->move(); } void vga::colors(int foreground, int background) { this->foreground = foreground; this->background = background; } void vga::move(void) { u16int cursorLocation = this->cursor_y * 80 + this->cursor_x; outb(0x3D4, 14); // Tell the VGA board we are setting the high cursor byte. outb(0x3D5, cursorLocation >> 8); // Send the high cursor byte. outb(0x3D4, 15); // Tell the VGA board we are setting the low cursor byte. outb(0x3D5, cursorLocation); // Send the low cursor byte. } void vga::scroll(void) { // Get a space character with the default colour attributes. u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F); u16int blank = 0x20 /* space */ | (attributeByte << 8); // Row 25 is the end, this means we need to scroll up if(this->cursor_y >= 25) { // Move the current text chunk that makes up the screen // back in the buffer by a line int i; for (i = 0*80; i < 24*80; i++) { this->video_memory[i] = this->video_memory[i+80]; } // The last line should now be blank. Do this by writing // 80 spaces to it. for (i = 24*80; i < 25*80; i++) { this->video_memory[i] = blank; } // The cursor should now be on the last line. this->cursor_y = 24; } } void vga::puts(const char *frm,...) { __builtin_va_list list; __builtin_va_start(list, frm); for(; *frm != '\0'; frm++) { if(*frm == '%') { frm++; if(*frm == 'i') this->putdec(__builtin_va_arg(list,int)); else if(*frm == 'u') this->puthex(__builtin_va_arg(list,int)); else if(*frm == 's') this->_puts(__builtin_va_arg(list, char *)); else if(*frm == 'c') this->putc(__builtin_va_arg(list, int)); else if(*frm == 'y') this->background = __builtin_va_arg(list,int); else if(*frm == 'z') this->foreground = __builtin_va_arg(list,int); else if(*frm == 'x') this->cursor_x = __builtin_va_arg(list,int); else if(*frm == '%') this->putc('%'); } else if(*frm == '\n') this->putc('\n'); else this->putc(*frm); } } void vga::_puts(char *c) { int i = 0; while (c[i]) { this->putc(c[i++]); } } void vga::putdec(u32int n) { if (n == 0) { this->puts("%c",'0'); return; } s32int acc = n; char c[32]; int i = 0; while (acc > 0) { c[i] = '0' + acc%10; acc /= 10; i++; } c[i] = 0; char c2[32]; c2[i--] = 0; int j = 0; while(i >= 0) { c2[i--] = c[j++]; } this->puts("%s",c2); } void vga::puthex(u32int n) { s32int tmp; this->puts("0x"); char noZeroes = 1; int i; for (i = 28; i > 0; i -= 4) { tmp = (n >> i) & 0xF; if (tmp == 0 && noZeroes != 0) { continue; } if (tmp >= 0xA) { noZeroes = 0; this->puts("%c",tmp-0xA+'a' ); } else { noZeroes = 0; this->puts("%c", tmp+'0' ); } } tmp = n & 0xF; if (tmp >= 0xA) { this->puts("%c",tmp-0xA+'a'); } else { this->puts("%c",tmp+'0'); } }
Really interesting implementation there. Unfortunately it doesn't provide complete control over VGA graphics, as mine will when I'm done. I'll post it when I finish, probably sometime next week if I don't get too much homework. The problem with my implementation is that it's more confusing to use, I think.
Not sure what you mean by control - I do have VGA register wrappers as well which give me complete control of the card - or are you talking about graphics mode vs text mode?
Yeah, that's what I meant. Nothing to change the modes, unchain, change the palette, etc.
Anyway, when learning assembly language it's good to start simple and then work your way up.
When the x86 starts it has to be in REAL MODE, 16bit mode. Then you have to switch to 32 or 64 Protected Mode. Learning 16-bit is good in several ways.
* If you are writing an operating system(Ex:working on linux kernel)
* If you are writing an Dos Emulator or similar.
* If you are writing some Hardware functions that only work in 16-bit mode. For example bios updates.
* To learn
There are several system calls to write output depending on the operating system. On POSIX systems the system call is INT 0x80 giving EAX=0x04 and EBX=0x01
Int 0x10 it's not actually a Dos system call. It's a bios system call. Dos relied on the BIOS calls for most operations.
POSIX(*inux and *BSD) and Windows(I think) don't allow direct access to the hardware, so they have their own system calls.
Have a look at kpgen at sourceforge
Neither Emacs or Vi are my primary editors...
..and I'm not ashamed!!!
Dude you are worthless. There is no reason to compile your C code as 16-bit.
Like I said, LEARN 16-BIT ASSEMBLY.
Learn2Read.
It's possible with some devices to do so on Windows.
Yes. I though so. I remember that there are several Manufacters that provide BIOS upgrade trough a windows application.
That's one of the reason's I prefer POSIX systems. One can make a virus to wipe out the bios from windows and pretty make your board garbage.
I think windows Vista has protections but I really don't know if they are implemented at low level(kernel), or if they are High Level.
Have a look at kpgen at sourceforge
Neither Emacs or Vi are my primary editors...
..and I'm not ashamed!!!
There are currently 1 users browsing this thread. (0 members and 1 guests)
Bookmarks