babyos (六)—— 显示ASCII字符和汉字

注:本程序为原创,若发现bug,万望指出,若有问题,欢迎交流,转载请指明出处。若能有助于一二访客,幸甚。

本以为要在裸机上显示个汉字是极难的,没想到亲自动手做一下,也不甚难做。“天下事有难易乎?为之,则难者亦易矣,不为,则易者亦难亦” 古人诚不我欺。

参考:

http://blog.sina.com.cn/s/blog_8c7bf19701010rhn.html

《30天自制操作系统》


0.实验结果:



1.测试点阵字体ASC16和HZK16

关于点阵字体ASC16、HZK16详见上述参考的博客,此一篇足矣。

下面是我的测试代码(当时只为测试,随手写的):

/*************************************************************************
	> File:		test.c
	> Describe:	尝试使用点阵字体显示ASCII 码和汉字
	> Author:	孤舟钓客
	> Mail:		guzhoudiaoke@126.com 
	> Time:		2013年01月01日 星期二 00时47分17秒
 ************************************************************************/

#include <stdio.h>

unsigned char font_asc[4096];
unsigned char font_hzk[267616];

int load_asc()
{
	FILE *fp;
	
	fp = fopen("./resource/font/ASC16", "rb");
	if (fp == NULL)
	{
		printf ("read ASC16 file failed!");
		return 0;
	}

	fread(font_asc, 1, 4096, fp);
	fclose(fp);

	return 1;
}

int load_hzk()
{
	FILE *fp;
	
	fp = fopen("./resource/font/HZK16", "rb");
	if (fp == NULL)
	{
		printf ("read HZK16 file failed!");
		return 0;
	}

	fread(font_hzk, 1, 267616, fp);
	fclose(fp);

	return 1;
}

int disp_asc(unsigned char c)
{
	unsigned char *pc = font_asc + (int)c * 16;

	int i, j;
	for (i = 0; i < 16; i++)
	{
		unsigned char test_bit = 128;
		for (j = 0; j < 8; j++)
		{
			if (*pc & test_bit)
				printf("*");
			else
				printf(" ");

			test_bit >>= 1;
		}
		printf("\n");
		pc++;
	}

	return 1;
}

int disp_hzk(unsigned char ch[3])
{
	unsigned char qu_no	 = ch[0] - 0xa0;
	unsigned char wei_no = ch[1] - 0xa0;
	unsigned long offset = (94*(qu_no-1) + (wei_no-1)) * 32;
	unsigned char *pc = font_hzk + offset;
	
	int i, j;
	for (i = 0; i < 32; i++)
	{
		unsigned char test_bit = 128;
		for (j = 0; j < 8; j++)
		{
			if (*pc & test_bit)
				printf("@");
			else
				printf(" ");

			test_bit >>= 1;
		}

		pc++;
		if (i & 1)
			printf("\n");
	}
	
	return 1;
}

int main()
{
	if (!load_asc() || !load_hzk())
	{
		printf("load font error!");
		return 0;
	}

	unsigned char c = 'G';
	disp_asc(c);

	unsigned char hz[3] = "钓";
	disp_hzk(hz);
	disp_hzk("客");

	return 0;
}
结果:



2.增加Babyos kernel 扇区数,将点阵字体加载到内存

本blog只为记录开发过程,以供日后参考,所以不会每次贴所有代码,只贴新的内容,前面若有更改,会指出。

在此过程中,修改两个地方:

1)增加kernel扇区后发现系统不能正常运行。后又发现最多只能支持128个扇区。经bochs单步调试若干次,最后发现每读一个扇区后bx增加512,会导致读入128个扇区后溢出,也就是超出了一个段64KB寻址的能力,所以导致后面的内容覆盖前面的内容,以至于系统不能正常运行。改为每次增加es:

read_kernel:
	movw	$0x1000,			%si		
	movw	%si,				%es		# ES:BX 为缓冲区地址
	xorw	%bx,				%bx
	movw	$0x01,				%di		# 相对扇区号
1:	
	movw	%di,				%ax		# 将相对扇区号传给AX作为参数
	call	read_a_sect

	addw	$512>>4,			%si
	movw	%si,				%es
	incw	%di
	cmpw	$KERNEL_SECT_NUM+1,	%di
	jne		1b

	ret
2)在init.c中简单定一个了一个指向前面的VIDEO_INFO的结构体指针,发现结果不对。调试发现结构体内存对齐问题。于是简单增加了两个显示模式的参数。

video_mode:								# 显示模式
	.short	0
screen_x:								# 水平分辨率
	.short	0 
screen_y:								# 垂直分辨率
	.short	0	
bits_per_pixel:
	.byte	0
memory_model:
	.byte	0
video_ram:								# video_ram地址
	.long	0
当然,也可以修改init.c中结构体的定义中的内存对齐方式。


3.显示

load.s中最后调用init,进入C语言文件init.c中定义的init()函数。

init.c本不应有下面的代码,但目前只为测试正确性,所以没有考虑代码的组织,后面这部分代码将会重新组织到其他文件中。

/*************************************************************************
	> File:		init.c
	> Author:	孤舟钓客
	> Describe:	主要完成初始化工作
				0.绘制矩形,测试C直接写显存以及测试保存的VIDEO_INFO正确性
				1.测试显示ASCI字符
				2.测试显示汉字
				3.显示ASCII与汉字混合的字符串
	> Mail:		guzhoudiaoke@126.com 
	> Time:		2013年01月01日 星期二 17时25分24秒
 ************************************************************************/

#include "include/types.h"
#include "include/kernel.h"

typedef struct struct_video_info {
	WORD	video_mode;
	WORD	screen_x;
	WORD	screen_y;
	BYTE	bits_per_pixel;
	BYTE	memory_model;
	BYTE*	p_vram;
} struct_video_info;

const struct_video_info* p_video_info = (struct_video_info*)(VIDEO_INFO_ADDR);
COLOR current_color = 6;


static void fill_rectangle(WORD left, WORD right, WORD top, WORD bottom)
{
	BYTE* p_vram = p_video_info->p_vram + top*p_video_info->screen_x;

	int row, col;
	for (row = top; row < bottom; row++) 
	{
		for (col = left; col < right; col++)
			p_vram[col] = current_color;
		p_vram += 800;
	}
}

void display_asc(char ch, int x, int y)
{
	BYTE* p_asc = (BYTE*)(FONT_ASC_ADDR) + ch * 16;
	BYTE* p_vram = p_video_info->p_vram + y*p_video_info->screen_x;

	int i, j;
	for (i = 0; i < 16; i++)
	{
		BYTE test_bit = 128;
		BYTE* p_cur_vram = p_vram+x;
		
		for (j = 0; j < 8; j++)
		{
			if (*p_asc & test_bit)
				p_cur_vram[j] = 3;
			else
				p_cur_vram[j] = 0;

			test_bit >>= 1;
		}
		
		p_asc++;
		p_vram += p_video_info->screen_x;
	}
}

void display_hzk(char ch[3], int x, int y)
{
	BYTE qu_no  = (BYTE)ch[0] - 0xa0;
	BYTE wei_no = (BYTE)ch[1] - 0xa0;
	DWORD offset= (94*(qu_no-1) + (wei_no-1)) * 32;

	BYTE* p_hzk = (BYTE*)(FONT_HZK_ADDR) + offset;
	BYTE* p_vram = p_video_info->p_vram + y*p_video_info->screen_x;

	int i, j, k;
	for (i = 0; i < 16; i++)
	{
		for (j = 0; j < 2; j++)
		{
			BYTE test_bit = 128;
			BYTE* p_cur_vram = p_vram+x+j*8;
		
			for (k = 0; k < 8; k++)
			{
				if (*p_hzk & test_bit)
					p_cur_vram[k] = 3;
				else
					p_cur_vram[k] = 0;

				test_bit >>= 1;
			}
		
			p_hzk++;
		}
		p_vram += p_video_info->screen_x;
	}
}

void test_vram(void)
{
	int i;
	BYTE* p = p_video_info->p_vram;
	for (i = 800*15; i < 800*20; i++)
		*(p+i) = 2;
}


void show_logo(int x, int y)
{
	BYTE* p_vram = p_video_info->p_vram + y*p_video_info->screen_x;
	BYTE* p_logo = (BYTE*)(LOGO_ADDR);
	
	int i, j;
	for (i = 0; i < LOGO_CY; i++)
	{
		BYTE* p_cur = p_vram + x;
		for (j = 0; j < LOGO_CX; j++)
		{
			if (p_logo[j] != 0xff)
				p_cur[j] = 4;
			else
				p_cur[j] = 0;
		}
		p_vram += p_video_info->screen_x;
		p_logo += LOGO_CX;
	}
}

/* 实现一个简陋的打印字符串程序,暂不能只能换行,过几天重写 */
void display_string(char* str, int x, int y)
{
	char* p = str;
	WORD cur_x = x, cur_y = y;
	char hzk[3];
	hzk[2] = '\0';

	while (*p != '\0')
	{
		if ((*p & 0x80) == 0)
		{
			display_asc(*p, cur_x, cur_y);
			cur_x += 8;
			p++;
		}
		else
		{
			hzk[0] = *p++;
			hzk[1] = *p++;
			display_hzk(hzk, cur_x, cur_y);
			cur_x += 16;
		}
	}
}

void init(void)
{
	test_vram();
	
	show_logo(400-128, 20);

	fill_rectangle(256, 512, 150, 200);

	display_asc('B', 300 + 8*0, 200);
	display_asc('a', 300 + 8*1, 200);
	display_asc('b', 300 + 8*2, 200);
	display_asc('y', 300 + 8*3, 200);
	display_asc(' ', 300 + 8*4, 200);
	display_asc('O', 300 + 8*5, 200);
	display_asc('S', 300 + 8*6, 200);

	display_hzk("孤", 358 + 16*0, 200);
	display_hzk("舟", 358 + 16*1, 200);
	display_hzk("钓", 358 + 16*2, 200);
	display_hzk("客", 358 + 16*3, 200);

	display_string("测试display_string 能不能行~", 300, 220);

	display_string("天下风云出我辈,", 300, 250+18*0);
	display_string("一入江湖岁月催。", 300, 250+18*1);
	display_string("皇图霸业谈笑中,", 300, 250+18*2);
	display_string("不胜人生一场醉。", 300, 250+18*3);
	display_string("只叹尘事如潮,",   300, 250+18*4);
	display_string("人如水!何时归!", 300, 250+18*5);
	display_string("提剑跨骑挥鬼蜮,", 300, 250+18*6);
	display_string("白骨如山鸟惊飞。", 300, 250+18*7);
	display_string("尘事如潮人如水,", 300, 250+18*8);
	display_string("只叹江湖几人回。", 300, 250+18*9);
	display_string("夜雨八方战孤城,", 300, 250+18*10);
	display_string("平明剑气看刀声。", 300, 250+18*11);
	display_string("侠骨千年寻不见,", 300, 250+18*12);
	display_string("碧血红叶醉秋风。", 300, 250+18*13);
}

胡思乱想一下后面的任务——憧憬一下而已,实现顺序没仔细考虑,能否实现也没考虑:

1)绘制一个简单的界面

2)重新组织这些代码

3)实现一个稍微优雅些的kprintf 函数

4)中断和异常

5)键盘、鼠标、时钟中断

6)任务切换

7)输入(要实现输入中文难道要自己写个输入法??这个毕业后去搜狗干两年该容易了。。。)

8)内存管理

9)系统调用

10)文件系统

11)终端

12)几个简单应用程序(写过好几次的拼图游戏一定得实现一个!)

13)其他待定


^_^,路曼曼其修远兮~慢慢来,Just for fun。在此中收获一份成就感,收获一份喜悦,足矣。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值