我正在尝试用c创建一个内核,并且我在创建新行时遇到了困难。例如,在向屏幕写入一个句子后,我会添加一个新行。
这是我的示例代码。我想把这些字符串写在两行上。那么,如何将光标移动到新行呢?非常感谢您的帮助
static char* const VGA_MEMORY = (char*) 0xb8000;
static const int VGA_WIDTH = 80;
static const int VGA_HEIGHT = 25;
static unsigned int cursor_pos = 0;
unsigned int i = 0;
char* str = "HELLO WORLD";
char* str1 = "TEST !";
while (str[i]!=' ')
{
char ch = str[i];
VGA_MEMORY[cursor_pos] = ch;
VGA_MEMORY[cursor_pos+1] = 0x07;
cursor_pos += 2;
i += 1;
}
i = 0;
while (str[i]!=' ')
{
char ch = str1[i];
VGA_MEMORY[cursor_pos] = ch;
VGA_MEMORY[cursor_pos+1] = 0x07;
cursor_pos += 2;
i += 1;
}
期望输出:
HELLO WORLD
TEST !
您只需到新行的第一个字符:VGA_WIDTH * line_number
.
VGA存储器只是一个字符网格。控制代码(所以新行)没有意义,它们用于更高级别的协议,以移动到正确的位置。
注意:通常有其他符号代替新行和其他控制代码。实际上VGA内存中的字符不是字符,而是活动字体的字符索引。
注意:在你的程序中,你必须有一个光标位置_x
和_y
(或_col
/_row
),而不仅仅是一个整数。
如果写入屏幕缓冲区,则不需要写入新行。相反,您只需要将光标移动到下一行:
cursor_pos = ((cursor_pos + (VGA_WIDTH-1)*2) / (VGA_WIDTH*2)) * (VGA_WIDTH*2);
这只是将光标位置四舍五入到VGA_WIDTH*2
那么如何将光标移动到新行呢?
绝对最小(最坏)方法如下:
i = 0;
while (str[i]!=' ') {
char ch = str1[i];
if(ch == 'n') {
cursor_pos = (cursor_pos / VGA_WIDTH + 1) * VGA_WIDTH;
} else {
VGA_MEMORY[cursor_pos] = ch;
VGA_MEMORY[cursor_pos+1] = 0x07;
cursor_pos += 2;
}
i += 1;
}
这样做的第一个问题是,如果光标已经在屏幕底部,它将以"索引越界"结束。并将超过帧缓冲区结束的内存丢弃。
要解决这个问题,您需要检测条件(例如if(cursor_pos >= VGA_WIDTH * VGA_HEIGHT * 2) {
)并决定要做什么-忽略所有新字符,绕到屏幕顶部(例如cursor_pos = 0;
),或滚动屏幕。
滚动屏幕可能看起来像:
i = 0;
while (str[i]!=' ') {
char ch = str1[i];
if(ch == 'n') {
cursor_pos = (cursor_pos / VGA_WIDTH + 1) * VGA_WIDTH;
if(cursor_pos >= VGA_WIDTH * VGA_HEIGHT * 2) {
memmove(VGA_MEMORY, &VGA_MEMORY[VGA_WIDTH * 2], (VGA_HEIGHT - 1) * VGA_WIDTH * 2);
cursor_pos -= VGA_WIDTH * 2;
}
} else {
VGA_MEMORY[cursor_pos] = ch;
VGA_MEMORY[cursor_pos+1] = 0x07;
cursor_pos += 2;
}
i += 1;
}
这是相对可怕的-从VGA内存读取很慢(最好在RAM中有一个缓冲区),这意味着没有办法再看到任何从屏幕顶部消失的文本。
解决这些问题的一种方法是将新字符串附加到内存中的内核日志中,然后显示日志中最后(最多)的VGA_HEIGHT行;以便稍后可以查看整个日志(和/或写入磁盘)。这创造了用更快的"再次从内存中打印日志中的所有内容"取代慢速memmove()
的可能性,从更新的屏幕顶部指针开始";方法。