那个点阵字库数组这么大,占地方,难看。而且要换字体也不方便,还得重新制作。还是直接把现有的字库文件作为一个资源文件比较好,loadre 到内存就行。
字库暂时放到内存 0x10000处
; const.inc ; 常量 ; 四彩 ; 2015-12-12 %ifndef _CONSTANT_INC %define _CONSTANT_INC ; ======================================================================================== ; 内存中 0x0500 ~ 0x7BFF 段(29.75 KB)和 0x7E00 ~ 0x9FBFF 段(607.5 KB)可自由使用。 ; 引导扇区段在加载完 Loader 后也可使用,即整个 0x500 ~ 0x9FBFF 段(637.25 KB)都可自由使用。 ; STACKSIZE equ 0x1000 ; 堆栈大小 SEGMENTOFGPARAM equ 0x50 ; 存放全局数据的段基址 SEGMENTOFTEMP equ 0x7E ; 临时数据被加载到内存的段基址 SEGMENTOFFONT equ 0x1000 ; 点阵字库被加载到内存的段基址 SEGMENTOFLOADER equ 0x9000 ; LOADER.SYS 被加载到内存的段基址 SEGMENTOFKERNEL equ 0x8000 ; KERNEL.EXE 被加载到内存的段基址 KERNELENTRYPHYADDR equ 0x30400 ; kernel 的程序入口的物理地址 ; 必须与 Makefile 中 -Ttext 参数的值相等 ; **************************************************************************************** %endif
; loader.asm ; 加载程序 ; 四彩 ; 2015-12-12 ; ======================================================================================== ; ---------------------------------------------------------------------------------------- ; 头文件 %include "./boot/inc/const.inc" %include "./boot/inc/FAT12.inc" %include "./boot/inc/PMode.inc" %include "./boot/inc/ELF.inc" ; ---------------------------------------------------------------------------------------- org STACKSIZE jmp RMode_main ; **************************************************************************************** ;========================================================================================= [SECTION .data] ; ---------------------------------------------------------------------------------------- ; 地址范围描述符结构(Address Range Descriptor Structure) struc T_AddrRngDscStruc ; 字段名 ;偏移 长度 说明 .dwBaseAddrLow resd 1 ; 0x00 4 基地址的低 32 位 .dwBaseAddrHigh resd 1 ; 0x04 4 基地址的高 32 位(未使用,为 0) .dwLengthLow resd 1 ; 0x08 4 长度(字节)的低32位 .dwLengthHigh resd 1 ; 0x0C 4 长度(字节)的高32位(未使用,为 0) .dwType resd 1 ; 0x10 4 地址类型:1 = 可用段, 2 = 正用或保留段, endstruc ; 全局变量结构 struc T_Global_Param ; 字段名 ;偏移 长度 说明 .dwMemorySize resd 1 ; 0x00 4 内存总容量 .dwPhyAddrOfVideo resd 1 ; 0x04 4 显存基址 .wScreenX resw 1 ; 0x08 2 分辨率 X .wScreenY resw 1 ; 0x0A 2 分辨率 Y .bBitsPerPixel resb 1 ; 0x0C 1 颜色数 endstruc ; ---------------------------------------------------------------------------------------- ; 出错提示信息及 kernel 文件名 strCheckMemoryFail db "Failed to check memory", 0 strNotSupportVESA db "Not support VESA", 0 strNotFoundFile db "Not found ", 0 FileNameOfKernel db "KERNEL SYS", 0 ; kernel 文件名(8 + 3 格式) FileNameOfFont db "ASC16 ", 0 ; 点阵字库文件名 ; ---------------------------------------------------------------------------------------- tArds istruc T_AddrRngDscStruc ; 地址范围描述符结构实体 times T_AddrRngDscStruc_size db 0 iend ; ---------------------------------------------------------------------------------------- ; GDT ; Loader 把全部内存都作为一个段使用,分为两类:代码段、数据段 ; 基址 界限 属性 Desc_Begin : Descriptor 0, 0, 0 ; 空描述符 Desc_Code : Descriptor 0, 0xFFFFF, DA_CS_ER + DA_32 + DA_4K ; 代码段 Desc_Data : Descriptor 0, 0xFFFFF, DA_DS_RW + DA_32 + DA_4K ; 数据段 Desc_End : ; ---------------------------------------------------------------------------------------- ; GDTPtr GDTPtr dw Desc_End - Desc_Begin - 1 ; 界限 dd SEGMENTOFLOADER * 0x10 + Desc_Begin ; 基址 ; ---------------------------------------------------------------------------------------- ; 选择子 SelectorCode equ Desc_Code - Desc_Begin SelectorData equ Desc_Data - Desc_Begin ; **************************************************************************************** ; ======================================================================================== [SECTION .code16] [BITS 16] ; 实模式代码段:取得内存容量、复制 kernel 到内存、设定画面模式、开启保护模式 ; ---------------------------------------------------------------------------------------- RMode_main: ; 初始化寄存器 mov ax, cs mov ds, ax mov ss, ax mov ax, STACKSIZE mov bp, ax mov sp, ax ; 获取内存信息 ; BIOS 中断 int 0x15 ; 入口参数:eax = 0xE820 功能号 ; ebx = ARDS 所需的后续值,第一个为 0 ; es : di = 内存缓冲区基址,指向一个地址范围描述符结构(ARDS) ; ecx = ARDS 的大小,通常 BIOS 总是填充 20 字节的信息到 ARDS 中 ; edx = “SMAP” 的 ASCII 码(0x0534D4150) ; 出口参数:CF 置 1 表明调用出错,否则无错 ; eax = "SMAP" 的 ASCII 码 ; ebx = 下一 ARDS 所需的后续值,如果为 0 则说明已到最后一个 ARDS。 push SEGMENTOFGPARAM pop fs xor ebx, ebx mov di, tArds .MemChkLoop: mov eax, 0xE820 mov ecx, T_AddrRngDscStruc_size mov edx, 0x534D4150 int 15h jnc .MemChkOK mov si, strCheckMemoryFail call PrintStr jmp $ .MemChkOK: mov eax, [tArds + T_AddrRngDscStruc.dwLengthLow] ; 累加内存总容量 add [fs : T_Global_Param.dwMemorySize], eax cmp ebx, 0 jne .MemChkLoop ; 复制 Kernel 到内存 mov si, FileNameOfKernel ; 寻找 call SearchFile cmp ax, 0 jnz .LoadKernel mov si, strNotFoundFile call PrintStr mov si, FileNameOfKernel call PrintStr jmp $ .LoadKernel: push SEGMENTOFKERNEL ; 复制 pop es xor bx, bx call LoadFile ; 复制字库到内存 mov si, FileNameOfFont call SearchFile cmp ax, 0 jnz .LoadFont mov si, strNotFoundFile call PrintStr mov si, FileNameOfFont call PrintStr jmp $ .LoadFont: push SEGMENTOFFONT pop es xor bx, bx call LoadFile ; 设置图形模式 push SEGMENTOFTEMP ; 取得 VBE 信息 pop es xor di, di mov ax, 0x4F00 int 0x10 mov di, 0x200 mov ax, 0x4F01 ; 取得 800*600*16 模式信息 mov cx, 0x114 int 0x10 cmp ax, 0x004F jz .Support mov si, strNotSupportVESA call PrintStr jmp $ .Support: mov ax, 0x4F02 ; 设置画面模式 mov bx, 0x4114 ; 800 * 600,16 位色,线性帧缓冲区 int 0x10 ; 保存显存相关信息到全局变量 mov eax, [es : 0x200 + 0x28] mov [fs : T_Global_Param.dwPhyAddrOfVideo], eax mov ax, [es : 0x200 + 0x12] mov [fs : T_Global_Param.wScreenX], ax mov ax, [es : 0x200 + 0x14] mov [fs : T_Global_Param.wScreenY], ax mov al, [es : 0x200 + 0x19] mov [fs : T_Global_Param.bBitsPerPixel], al ; 开启保护模式 lgdt [GDTPtr] ; 加载 GDT in al, 0x92 ; 打开地址线 A20 or al, 0b10 out 0x92, al mov eax, cr0 ; 置保护模式标志位 or eax, 1 mov cr0, eax jmp dword SelectorCode : (SEGMENTOFLOADER * 0x10 + PMode_main) ; 跳转至保护模式代码段 ; ---------------------------------------------------------------------------------------- ; 包含 FAT12 子函数 IncludeFAT12Function SEGMENTOFTEMP ; **************************************************************************************** ; ======================================================================================== [SECTION .code32] [BITS 32] ; 保护模式代码段,由实模式跳入:重定位 kernel,跳转到 kernel ; ---------------------------------------------------------------------------------------- PMode_main: ; 初始化寄存器 mov ax, SelectorData mov ds, ax mov ss, ax mov es, ax mov fs, ax mov gs, ax mov eax, SEGMENTOFLOADER * 0x10 + STACKSIZE mov ebp, eax mov esp, eax ; 装载 kernel 各段(重定位) xor ecx, ecx mov cx, [SEGMENTOFKERNEL * 0x10 + Tag_ELF_Header.e_phnum] ; 段数 mov esi, [SEGMENTOFKERNEL * 0x10 + Tag_ELF_Header.e_phoff] ; 指向程序头表 add esi, SEGMENTOFKERNEL * 0x10 .Load: mov eax, [esi + Tag_Program_Header.p_type] ; 只装载可装载段 cmp eax, PT_LOAD jnz .NotNeedLoad push dword[esi + Tag_Program_Header.p_filesz] mov eax, [esi + Tag_Program_Header.p_offset] add eax, SEGMENTOFKERNEL * 0x10 push eax push dword[esi + Tag_Program_Header.p_vaddr] call memcpy add esp, 3 * 4 .NotNeedLoad: add esi, Tag_ELF_Header.e_phentsize loop .Load ; 跳转至 kernel(修改 cs 和 eip) jmp SelectorCode : KERNELENTRYPHYADDR ; ---------------------------------------------------------------------------------------- ; 函数功能:内存复制 ; void memcpy(void *pDest, void *pSrc, DWORD dwSize); ; 入口参数:es : pDest = 目标内存地址 ; ds : pSrc = 源内存地址 ; dwSize = 数据长度(字节) ; 出口参数:无 memcpy: push ebp mov ebp, esp push esi push edi push ecx mov edi, [ebp + 2 * 4] ; pDest mov esi, [ebp + 3 * 4] ; pSrc mov ecx, [ebp + 4 * 4] ; dwSize jecxz .Return .Copy: lodsb stosb loop .Copy .Return: pop ecx pop edi pop esi mov esp, ebp pop ebp ret ; ****************************************************************************************
显示文字其实也是画图,把显示文字的函数也放到 graphics.c 里,只是头文件单列出来
/* graphics.c 图形相关全局变量及函数 函数被分配到两个头文件:graphics.h(绘图)、io.h(文字) 四彩 2015-12-12 */ #include "../lib/include/stddef.h" #include "../lib/include/string.h" #include "../kernel/include/graphics.h" #include "../kernel/include/io.h" // ======================================================================================= // 全局参数 // --------------------------------------------------------------------------------------- // 图形函数相关全局参数 static unsigned short *pVideo, Color = 0; // 显存地址和当前颜色 static unsigned short Screen_X, Screen_Y; // 屏幕分辨率 static unsigned char BytePerPix; // 每个像素占用的位数 // --------------------------------------------------------------------------------------- // 文字函数相关全局参数 static unsigned char *pFont; // 点阵字库的物理内存地址 static unsigned char WidthPerChar, HeightPerChar; // 每个字符的宽度和高度 // *************************************************************************************** // ======================================================================================= // 函数 // --------------------------------------------------------------------------------------- // 图形部分 /* 画一条线 */ void line(unsigned x0, unsigned y0, unsigned x1, unsigned y1) { int x, y; if(x0 == x1) for(y = y0; y <= y1; y++) pVideo[Screen_X * y + x] = Color; else if(x0 < x1) for(x = x0; x <= x1; x++) { y = ((x - x0) * y1 + (x1 - x) * y0) / (x1 - x0); pVideo[Screen_X * y + x] = Color; } else // if(x0 > x1) for(x = x1; x <= x0; x++) { y = ((x0 - x) * y1 + (x - x1) * y0) / (x0 - x1); pVideo[Screen_X * y + x] = Color; } } /* 画一个方框并填色 */ void rectangle(unsigned x0, unsigned y0, unsigned x1, unsigned y1) { unsigned x, y; for(y = y0; y <= y1; y++) for(x = x0; x <= x1; x++) pVideo[Screen_X * y + x] = Color; } // --------------------------------------------------------------------------------------- // 文字部分 /* 函数功能:显示一个字符 参数表:x, y = 屏幕起始坐标 ch = 字符 返回值:无 */ void putc(unsigned x, unsigned y, char ch) { int i, j, k; k = HeightPerChar * ch; for(i = 0; i < HeightPerChar; i++) for(j = 0; j < WidthPerChar; j++) if(pFont[k + i] & (1 << (7 - j))) pVideo[Screen_X * (y + i) + x + j] = Color; } /* 函数功能:显示字符串 参数表:x, y = 屏幕起始坐标 str = 字符串 返回值:无 */ void puts(unsigned x, unsigned y, char *str) { int i, j, k; while(*str != NUL) { k = HeightPerChar * (*str); for(i = 0; i < HeightPerChar; i++) for(j = 0; j < WidthPerChar; j++) if(pFont[k + i] & (1 << (7 - j))) pVideo[Screen_X * (y + i) + x + j] = Color; str++; x += WidthPerChar; } } // --------------------------------------------------------------------------------------- // 设置参数部分 /* 初始化图形参数 */ void InitGraphics(GRAPHICS_PARAM *ptGraphics) { pVideo = (unsigned short *)ptGraphics->dwPhyAddrOfVideo; Screen_X = ptGraphics->wScreenX; Screen_Y = ptGraphics->wScreenY; BytePerPix = ptGraphics->bBitsPerPixel; } /* 设置颜色 */ void SetColor(unsigned color) { Color = color; } /* 函数功能:设置字体 参数表:addr = 点阵字库的物理内存地址 width = 点阵字的宽度(像素) height = 点阵字的高度(像素) 返回值:无 */ void SetFont(unsigned addr, unsigned char width, unsigned char height) { pFont = (unsigned char *)addr; WidthPerChar = width; HeightPerChar = height; } // --------------------------------------------------------------------------------------- // 输出当前参数部分 unsigned GetScreenX() { return Screen_X; } unsigned GetScreenY() { return Screen_Y; } // ***************************************************************************************
/* io.h 输入输出函数,输出部分的实现在 graphics.c 内 四彩 2015-12-12 */ #ifndef _IO_H #define _IO_H /* 函数功能:显示一个字符 参数表:x, y = 屏幕起始坐标 ch = 字符 返回值:无 */ void putc(unsigned x, unsigned y, char ch); /* 函数功能:显示字符串 参数表:x, y = 屏幕起始坐标 str = 字符串 返回值:无 */ void puts(unsigned x, unsigned y, char *str); /* 函数功能:设置字体 参数表:addr = 点阵字库的物理内存地址 width = 点阵字的宽度(像素) height = 点阵字的高度(像素) 返回值:无 */ void SetFont(unsigned addr, unsigned char width, unsigned char height); #endif
用到几个处理字符串的函数,自己实现就行 —— C语言干这个手到擒来。顺手把可能会用到的都实现了
/* string.h 字符串处理函数 四彩 2015-12-12 */ #ifndef _STRING_H #define _STRING_H /* 函数功能:内存复制 参数表:pDst = 目标内存地址 pSrc = 源内存地址 nSzie = 要复制的长度(字节单位) 返回值:指向目标内存地址的指针 */ void *memcpy(void *pDst, const void *pSrc, unsigned int nSzie); /* 函数功能:取字符串长度 参数表:pStr = 字符串地址 返回值:字符串长度 */ unsigned strlen(const char *pStr); /* 函数功能:字符串比较 参数表:pStr1 = 字符串 1 地址 pStr2 = 字符串 2 地址 返回值:当 pStr1 < pStr2 时,返回为负数 当 pStr1 = pStr2 时,返回值 0 当 pStr1 > pStr2 时,返回正数 */ int strcmp(const char *pStr1, const char *pStr2); /* 函数功能:复制字符串 参数表:pDst = 目标字符串地址 pSrc = 源字符串地址 返回值:指向目标字符串的指针 */ char *strcpy(char *pDst, const char *pSrc); /* 函数功能:合并字符串 参数表:pDst = 目标字符串地址 pSrc = 源字符串地址 返回值:指向目标字符串的指针 */ char *strcat(char *pDst, const char *pSrc); /* 函数功能:反转字符串 参数表:string = 字符串的地址 返回值:指向字符串的指针 */ char *strrev(char *string); /* 函数功能:将整数转换为字符串 参数表:value = 欲转换的数据 string = 目标字符串的地址 radix = 转换后的进制数 返回值:指向字符串的指针 */ char *itoa(int value, char *string, int radix); /* 函数功能:将无符号整数转换为字符串 参数表:value = 欲转换的数据 string = 目标字符串的地址 radix = 转换后的进制数 返回值:指向字符串的指针 */ char *utoa(unsigned value, char *string, int radix); #endif
/* string.c 字符串处理函数 四彩 2015-12-12 */ #include "../lib/include/string.h" #include "../lib/include/stddef.h" /* 函数功能:内存复制 参数表:pDst = 目标内存地址 pSrc = 源内存地址 nSzie = 要复制的长度(字节单位) 返回值:指向目标内存地址的指针 */ void *memcpy(void *pDst, const void *pSrc, unsigned nSzie) { // 不清楚来源结构,只能逐字节复制 unsigned char *p1 = (unsigned char *)pDst; unsigned char *p2 = (unsigned char *)pSrc; // 若目标内存与源内存完全一致,则无需复制 if(p1 == p2 || NULL == p1 || NULL == p2) return(pDst); // 若目标内存与源内存无重叠,或目标内存尾部与源内存头部重叠,则顺序复制 else if(p1 >= (p2 + nSzie) || p1 < p2) while(nSzie--) *p1++ = *p2++; // 若目标内存头部与源内存尾部重叠,则逆序复制 else // if(p1 > p2 && p1 < (p2 + nSzie)) { p1 += nSzie - 1; p2 += nSzie - 1; while(nSzie--) *p1-- = *p2--; } return pDst; } /* 函数功能:取字符串长度 参数表:pStr = 字符串地址 返回值:字符串长度 */ unsigned strlen(const char *pStr) { unsigned len = 0; if(NULL == pStr) return 0; while(NUL != *pStr) { pStr++; len++; } return len; } /* 函数功能:字符串比较 参数表:pStr1 = 字符串 1 地址 pStr2 = 字符串 2 地址 返回值:当 pStr1 < pStr2 时,返回为负数 当 pStr1 = pStr2 时,返回值 0 当 pStr1 > pStr2 时,返回正数 */ int strcmp(const char *pStr1, const char *pStr2) { // 转无符号,进行 ASCII 编码比较 unsigned char *s1 = (unsigned char *)pStr1, *s2 = (unsigned char *)pStr2; if(pStr1 == pStr2) // 包含了两个都是空指针的情况 return 0; else if(NULL == pStr1 && NULL != pStr2) return -1; else if(NULL != pStr1 && NULL == pStr2) return 1; for(; *s1 == *s2; ++s1, ++s2) if(NUL == *s1) return 0; return(*s1 < *s2 ? -1 : 1); } /* 函数功能:复制字符串 参数表:pDst = 目标字符串地址 pSrc = 源字符串地址 返回值:指向目标字符串的指针 */ char *strcpy(char *pDst, const char *pSrc) { char *p1 = pDst; if(NULL == pDst || NULL == pSrc) return pDst; while(NUL != (*p1++ = *pSrc++)); return pDst; } /* 函数功能:合并字符串 参数表:pDst = 目标字符串地址 pSrc = 源字符串地址 返回值:指向目标字符串的指针 */ char *strcat(char *pDst, const char *pSrc) { char *p1 = pDst; if(NULL == pDst || NULL == pSrc) return pDst; while(NUL != *p1) p1++; while(NUL != (*p1++ = *pSrc++)); return pDst; } /* 函数功能:反转字符串 参数表:string = 字符串地址 返回值:指向字符串的指针 */ char *strrev(char *string) { char ch, *p1, *p2; // p1 指向 string 的头部 if(NULL == (p1 = p2 = string)) return NULL; // p2 指向 string 的尾部 while(*p2) ++p2; p2--; // 头尾交换反转 while(p2 > p1) { ch = *p1; *p1++ = *p2; *p2-- = ch; } return string; } /* 函数功能:将整数转换为字符串 参数表:value = 欲转换的数据 string = 目标字符串的地址 radix = 转换后的进制数 返回值:指向字符串的指针 */ char *itoa(int value, char *string, int radix) { int i = 0, neg; char ch; if(NULL == string) return NULL; // 记录正负符号,并转为正数处理 if((neg = value) < 0) value = -value; // 从数字变为 ASCII 码 do { ch = value % radix; if(ch < 10) string[i++] = ch + '0'; else string[i++] = ch - 10 + 'A'; } while((value /= radix) > 0); // 正负符号 if(neg < 0) string[i++] = '-'; // 字符串以 0 结尾。 string[i] = NUL; // 反转(生成的时候是从个位开始的,是逆序的) return(strrev(string)); } /* 函数功能:将无符号整数转换为字符串 参数表:value = 欲转换的数据 string = 目标字符串的地址 radix = 转换后的进制数 返回值:指向字符串的指针 */ char *utoa(unsigned value, char *string, int radix) { int i = 0, neg; char ch; if(NULL == string) return NULL; // 从数字变为 ASCII 码 do { ch = value % radix; if(ch < 10) string[i++] = ch + '0'; else string[i++] = ch - 10 + 'A'; } while((value /= radix) > 0); // 进制符 if(16 == radix) { string[i++] = 'x'; string[i++] = '0'; } else if(8 == radix) { string[i++] = '0'; } else if(2 == radix) { string[i++] = 'b'; string[i++] = '0'; } // 字符串以 0 结尾。 string[i] = NUL; // 反转(生成的时候是从个位开始的,是逆序的) return(strrev(string)); }
stddef.h 这个文件就是定义了 NUL 和 NULL:
// 常量 // —— 空指针 NULL #ifndef NULL #define NULL ((void *)0) #endif // —— 字符串结尾符 NUL #ifndef NUL #define NUL '\0' #endif
kernel 里可以显示字符了,把几个参数显示出来先:
/* kernel.c 内核 whoozit 2012-12-12 */ #include "../lib/include/stddef.h" #include "../lib/include/string.h" #include "../kernel/include/PMode.h" #include "../kernel/include/graphics.h" #include "../kernel/include/io.h" // 全局变量结构 typedef struct tag_Global_param { unsigned int dwMemorySize; GRAPHICS_PARAM tGraphics; } GLOBAL_PARAM; // 存放全局变量的物理地址(const.inc 中的 SEGMENTOFGPARAM * 0x10) #define PHYADDROFGPARAM 0x500 // 存放点阵字库的物理地址(const.inc 中的 SEGMENTOFFONT * 0x10) #define PHYADDROFFONT 0x10000 // GDT 表存放的物理内存地址(就接在全局变量后面吧) #define PHYADDROFGDT (PHYADDROFGPARAM + sizeof(GLOBAL_PARAM)) // 引用汇编指令函数 extern void asm_hlt(); void c_main() { unsigned i, j; unsigned short Screen_X, Screen_Y; char string[80], number[33]; GLOBAL_PARAM g_Param; // 初始化 GDT 表 InitGdt(PHYADDROFGDT); // 取全局变量 memcpy((void *)&g_Param, (void *)(PHYADDROFGPARAM), sizeof(GLOBAL_PARAM)); // 初始化图形参数 InitGraphics(&(g_Param.tGraphics)); Screen_X = GetScreenX(); Screen_Y = GetScreenY(); // 画界面 SetColor(COLOR16_DEEPSKYBLUE); rectangle(0, 0, Screen_X - 1, Screen_Y - 1); SetColor(COLOR16_LIGHTGRAY); rectangle(0, Screen_Y - 28, Screen_X - 1, Screen_Y - 28); rectangle(0, Screen_Y - 26, Screen_X - 1, Screen_Y - 1); SetColor(COLOR16_WHITE); rectangle(0, Screen_Y - 27, Screen_X - 1, Screen_Y - 27); rectangle(3, Screen_Y - 24, 59, Screen_Y - 24); rectangle(2, Screen_Y - 24, 2, Screen_Y - 4); rectangle(2, Screen_Y - 3, 59, Screen_Y - 3); rectangle(60, Screen_Y - 24, 60, Screen_Y - 3); rectangle(Screen_X - 47, Screen_Y - 3, Screen_X - 4, Screen_Y - 3); rectangle(Screen_X - 3, Screen_Y - 24, Screen_X - 3, Screen_Y - 3); SetColor(COLOR16_DARKGRAY); rectangle(3, Screen_Y - 4, 59, Screen_Y - 4); rectangle(59, Screen_Y - 23, 59, Screen_Y - 5); rectangle(Screen_X - 47, Screen_Y - 24, Screen_X - 4, Screen_Y - 24); rectangle(Screen_X - 47, Screen_Y - 23, Screen_X - 47, Screen_Y - 4); // 设置点阵字库 SetFont(PHYADDROFFONT, 8, 16); SetColor(COLOR16_LIGHTVIOLET); puts(10, Screen_Y - 20, "BEGIN"); SetColor(COLOR16_YELLOW); putc(Screen_X - 40, Screen_Y - 20, 'O'); putc(Screen_X - 30, Screen_Y - 20, 'K'); // 显示变量 SetColor(COLOR16_BLACK); strcpy(string, "Memory = "); strcat(string, utoa(g_Param.dwMemorySize, number, 10)); puts(10, 10, string); strcpy(string, "PhyAddrOfVideo = "); strcat(string, utoa(g_Param.tGraphics.dwPhyAddrOfVideo, number, 16)); puts(10, 30, string); strcpy(string, "Screen_X = "); strcat(string, utoa(Screen_X, number, 10)); puts(10, 50, string); strcpy(string, "Screen_Y = "); strcat(string, utoa(Screen_Y, number, 10)); puts(10, 70, string); strcpy(string, "BitsPerPixel = "); strcat(string, utoa(g_Param.tGraphics.bBitsPerPixel, number, 10)); puts(10, 90, string); while(1) asm_hlt(); }
忙活了这么多天,总算看到字了,曙光啊,激动啊。。。。