我在文本模式下更新光标位置的功能有问题 函数定义和声明是
#include <sys/io.h>
signed int VGAx = 0,VGAy=0;
void setcursor()
{
uint16_t position = VGAx+VGAy*COLS;
outb(0x0f, 0x03d4);
outb((position<<8)>>8,0x03d5);
outb(0x0e,0x03d4);
outb(position>>8,0x03d5);
}
和文件sys / io.h
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm ("inb %0, %%al":"=rm"(value):"a"(port));
return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %%al, $0"::"rm"(value), "a"(port));
}
在使用该功能之前,光标有时会闪烁下划线,有时候在使用该功能后没有出现没有光标出现
这是运行的主要功能
#include <vga/vga.h>
int kmain(){
setcursor()
setbgcolor(BLACK);
clc();
setforecolor(BLUE);
terminal_write('h');
setcursor();
return 0;
}
我尝试使用此功能
void enable_cursor() {
outb(0x3D4, 0x0A);
char curstart = inb(0x3D5) & 0x1F; // get cursor scanline start
outb(0x3D4, 0x0A);
outb(0x3D5, curstart | 0x20); // set enable bit
}
提供here但我收到此错误
inline asm: operand type mismatch for 'in'
任何帮助表示赞赏
修改
我试图修正错误的inb
和outb
:
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %%al, $0"::"Nd"(value), "a"(port));
}
我想这是正确的定义,但仍然没有光标显示
编辑2
我按照给定的答案将io.h
文件定义为以下
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %0, %1"::"a"(value), "Nd"(port));
}
我想提一下,我还将enable_cursor();
添加到kmain的开头,现在编译时错误已修复,但没有出现光标(这是主要问题)
编辑3 我想指出,如果任何人想要访问问题中没有的代码片段,那么整个代码的版本可以在gihub上获得
答案 0 :(得分:4)
inb
的此代码不正确:
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm ("inb %0, %%al":"=rm"(value):"a"(port));
return value;
}
它有一些问题:
inb
的参数被反转。查看inb
的{{3}}。请记住,在AT&amp; T语法(您在GNU汇编程序代码中使用)中,操作数是相反的。指令集参考以英特尔格式显示它们。DX
寄存器或inb / outb的直接8位值的正确约束是Nd
。有关约束Nd
的解释,请参阅我的Stackoverflow instruction set reference。=rm
表示可用的寄存器或内存地址不正确。在你的情况下它应该是=a
。 您的代码应该是:
static inline unsigned char inb (unsigned short int port)
{
unsigned char value;
asm volatile ("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
outb
的汇编程序模板不正确:
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %%al, $0"::"rm"(value), "a"(port));
}
有几个问题:
DX
寄存器或inb / outb的直接8位值的正确约束是Nd
。有关约束Nd
的解释,请参阅我的Stackoverflow answer。rm
不正确。在你的情况下它应该是a
。有关outb
代码应该类似于:
static inline void outb(unsigned char value, unsigned short int port)
{
asm volatile ("outb %0, %1"::"a"(value), "Nd"(port));
}
我必须查找关于光标的VGA寄存器,并在光标开始寄存器上找到instruction set reference,其中包含:
Cursor Start Register (Index 0Ah) ------------------------------------------------- | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ------------------------------------------------- | | | CD | Cursor Scan Line Start | -------------------------------------------------
CD - 光标禁用
此字段控制是否显示文本模式光标。值是:
0 - 启用光标
1 - 光标已禁用
光标扫描线开始
重要的是,当 bit 5 设置时,光标禁用。在 github setcursor
函数中,您可以执行以下操作:
outb(curstart | 0x20, 0x3D5);
curstart | 0x20
设置 第5位(0x20 = 0b00100000)。如果你想清除 第5位和启用光标,那么你按位 NEGATE (〜)位掩码和按位 AND (&amp;)与curstart
。它应该是这样的:
outb(curstart & ~0x20, 0x3D5);
正确启用光标后,它会将光标呈现为当前所在特定视频位置的前景色(属性)。我注意到的一件事是你的clc
程序会这样做:
vga_deref_80x24(VGAx,VGAy) = \
vga_encode_80x24(' ',BgColor,BgColor);
要注意的是,您要将前景色和背景色的属性设置为BgColor
。如果在调用bgcolor
之前将clc
设置为黑色,则会在黑色背景上闪烁黑色下划线光标,使其在任何屏幕位置都不可见。要使光标可见,它必须位于前景和背景为不同颜色的屏幕位置。查看是否有效的一种方法是将代码更改为:
vga_deref_80x24(VGAx,VGAy) = \
vga_encode_80x24(' ',BgColor,ForeColor);
我认为您使用编码vga_encode_80x24(' ',BgColor,BgColor);
清除它是一个错误我认为您的意思是使用vga_encode_80x24(' ',BgColor,ForeColor);
现在在kmain
函数中,您需要在调用clc
之前设置 ForeColor 和 BgColor ,并且它们的颜色必须不同光标可见。你有这个代码:
setbgcolor(BLACK);
clc();
setforecolor(BLUE);
现在应该是:
setbgcolor(BLACK);
setforecolor(BLUE);
clc();
现在,如果光标在屏幕上未写入的位置上的任何位置呈现,它将在黑色背景上闪烁蓝色下划线。
这应解决您的光标问题。但是,我注意到您还在VGA encode vga_encode_80x24(' ',BgColor,BgColor);
和scrolldown
功能中使用terminal_control
。我认为这也是一个错误,我认为你应该使用encode vga_encode_80x24(' ',BgColor,ForeColor);
。您似乎确实在terminal_write
中正确设置了它。
如果要在任何位置更改光标的颜色,可以编写一个更改光标位置下的前景属性而不更改背景颜色的函数。确保两个属性(前景色和背景色)不同,以使光标可见。如果你想隐藏光标,你可以为光标当前所在的屏幕位置设置相同颜色的前景色和背景色。