2 Star 6 Fork 4

稀风 / KOS

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
print.c 8.77 KB
一键复制 编辑 原始数据 按行查看 历史
#include <print.h>
#include <stdarg.h>
// 光标位置
static U16 CursorPosX;
static U16 CursorPosY;
// 字体颜色
static U08 FontColor;
// 用于数值 0 ~ 15 转成对应的字符 '0' ~ 'F'
static const U08 IntToStr[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
/******************************************************************************
* 函数名称: E_RET SetCursorPos(U16 x, U16 y)
* 功能说明: 设置光标位置
* 输入参数: U16 x --横坐标
    U16 y --纵坐标
* 输出参数: 无
* 函数返回: E_OK:成功; E_ERR:失败
* 其它说明: 无
******************************************************************************/
E_RET SetCursorPos(U16 x, U16 y)
{
U16 bx_c = 0;
// 对传入的坐标进行合法性检查
if(x >= SCREEN_WIDTH || y >= SCREEN_WIDTH)
return E_ERR;
CursorPosX = x;
CursorPosY = y;
// 光标位置须按照 bx = (80 * y + x) 公式转换一下放入 bx 寄存器中
bx_c = 80 * y + x;
asm volatile(
// 设置光标高 8 位:先把数据 0x0E 写入端口 0x03D4,然后把 bh 写入端口 0x03D5
"movw %0, %%bx\n"
"movw $0x03D4, %%dx\n"
"movb $0x0E, %%al\n"
"outb %%al, %%dx\n"
"movw $0x03D5, %%dx\n"
"movb %%bh, %%al\n"
"outb %%al, %%dx\n"
// 设置光标低 8 位:先把数据 0x0F 写入端口 0x03D4,然后把 bl 写入端口 0x03D5
"movw $0x03D4, %%dx\n"
"movb $0x0F, %%al\n"
"outb %%al, %%dx\n"
"movw $0x03D5, %%dx\n"
"movb %%bl, %%al\n"
"outb %%al, %%dx\n"
:
: "b"(bx_c) // 相当于:bx = bx_c,等号左边是汇编中的寄存器 bx,等号右边是 C 代码中的变量
: "ax", "dx" // 告诉 gcc 编译器,ax,dx 寄存器被内嵌汇编使用,需要 gcc 自动添加保护和恢复操作(入栈和出栈)
// 明明 ax, bx, dx 三个寄存器都被使用了,为什么这里却只有 ax 和 dx 寄存器?
// "b"(bx_c) 中使用约束名 "b" 时 gcc 就已经自动对 bx 进行保护和恢复操作,所以这里就不需要重复了
);
return E_OK;
}
/******************************************************************************
* 函数名称: void SetFontColor(E_FONT_COLOR color)
* 功能说明: 设置字体颜色
* 输入参数: E_FONT_COLOR color --字体颜色
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void SetFontColor(E_FONT_COLOR color)
{
FontColor = color;
}
/******************************************************************************
* 函数名称: void PrintChar(U08 ch)
* 功能说明: 打印一个字符
* 输入参数: U08 ch --要打印的字符
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void PrintChar(U08 ch)
{
U32 edi_c = (80 * CursorPosY + CursorPosX) * 2;
U08 ah_c = FontColor;
U08 al_c = ch;
// 每打印一个字符,光标都往后移动一个位置
CursorPosX++;
// 如果光标达到最大横坐标值了,则设置光标到下一行起始位置
if(CursorPosX >= SCREEN_WIDTH)
{
CursorPosX = 0;
CursorPosY++;
}
if('\n' == al_c || '\r' == al_c) // 遇到换行,则光标位置设置成下一行的起始位置处
{
CursorPosX = 0;
CursorPosY++;
}
else
{
// 打印一个字符
asm volatile(
"movl %0, %%edi\n" // edi:显存中的偏移量
"movb %1, %%ah\n" // 显示属性
"movb %2, %%al\n" // 要打印的字符
"movw %%ax, %%gs:(%%edi)" // 把显示数据放入显存
:
: "D"(edi_c), "r"(ah_c), "r"(al_c) // %0 替换成 edi_c,"D" 表示使用 edi 寄存器; %1 替换成 ah_c; %2 替换成 al_c;
: "ax"
);
}
// 更新光标位置
SetCursorPos(CursorPosX, CursorPosY);
}
/******************************************************************************
* 函数名称: E_RET PrintString(U08 *str)
* 功能说明: 打印字符串
* 输入参数: U08 *str --要打印的字符串
* 输出参数: 无
* 函数返回: E_OK:成功; E_ERR:失败
* 其它说明: 无
******************************************************************************/
E_RET PrintString(U08 const *str)
{
// 检查 *str 是否为空
if(NULL == str)
return E_ERR;
while(*str)
PrintChar(*str++);
return E_OK;
}
/******************************************************************************
* 函数名称: void PrintIntDec(S32 num)
* 功能说明: 以十进制的方式打印一个整型数
* 输入参数: S32 num --要打印的整型数
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void PrintIntDec(S32 num)
{
// 如果 num 为负数,则先把负号 '-' 打印出来; num = -num: 取一个负数的绝对值
if(num < 0)
{
PrintChar('-');
num = -num;
}
if(num < 10) // 递归出口条件
PrintChar(IntToStr[num]);
else
{
PrintIntDec(num / 10);
PrintIntDec(num % 10);
}
}
/******************************************************************************
* 函数名称: void PrintIntHex(S32 num)
* 功能说明: 以十六进制的方式打印一个整型数
* 输入参数: S32 num --要打印的整型数
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void PrintIntHex(S32 num)
{
U08 print[12] = { 0 }; // 初始化时必须清零,最大占 12 字节,比如 "-0x12345678\0"
U08 i = 0;
U08 tmp = 0;
if(num >= 0) // 正数
{
print[0] = '0';
print[1] = 'x';
for(i = 9; i >= 2; i--)
{
tmp = num & 0xF;
num = num >> 4;
print[i] = IntToStr[tmp];
}
}
else // 负数
{
print[0] = '-';
print[1] = '0';
print[2] = 'x';
num = -num; // 将负数取绝对值(去掉负号)
for(i = 10; i >= 3; i--)
{
tmp = num & 0xF;
num = num >> 4;
print[i] = IntToStr[tmp];
}
}
PrintString(print);
}
/******************************************************************************
* 函数名称: void ClearScreen(void)
* 功能说明: 清空屏幕
* 输入参数: 无
* 输出参数: 无
* 函数返回: 无
* 其它说明: 无
******************************************************************************/
void ClearScreen(void)
{
U32 i = 0;
SetCursorPos(0, 0);
for(i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++)
PrintChar(' ');
SetCursorPos(0, 0);
}
/******************************************************************************
* 函数名称: E_RET printk(const char * fmt, ...)
* 功能说明: 通用打印
* 输入参数: const char * fmt --输出格式, 目前支持的格式:
%c: 字符
%s: 字符串
%x: 十六进制
%d: 十进制
    ... --可变参数
* 输出参数: 无
* 函数返回: E_OK:成功; E_ERR:失败
* 其它说明: 无
******************************************************************************/
E_RET printk(const char * fmt, ...)
{
va_list args;
va_start(args, fmt);
// 遍历字符串 fmt
for(; *fmt; ++fmt)
{
// 寻找格式转换字符 '%', 如果不是 '%', 则直接打印出来
if(*fmt != '%')
{
PrintChar(*fmt);
continue;
}
// 如果找到了 '%', 则取 '%' 后的第一个字符
++fmt;
switch (*fmt) // 根据 '%' 后的字符类型采取不同的打印接口
{
case 'c': // 字符
PrintChar((U08)va_arg(args, U32));
break;
case 's': // 字符串
PrintString(va_arg(args, U08 *));
break;
case 'x': // 十六进制
PrintIntHex(va_arg(args, U32));
break;
case 'd': // 十进制
PrintIntDec(va_arg(args, U32));
break;
default:
return E_ERR;
break;
}
}
va_end(args);
return E_OK;
}
1
https://gitee.com/thin-wind/KOS.git
git@gitee.com:thin-wind/KOS.git
thin-wind
KOS
KOS
main

搜索帮助