那个点阵字库数组这么大,占地方,难看。而且要换字体也不方便,还得重新制作。还是直接把现有的字库文件作为一个资源文件比较好,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();
}
忙活了这么多天,总算看到字了,曙光啊,激动啊。。。。