实现putchar put_str put_int

1.在lib/kernel/print.S 文件中实现put_char()

2.思路

①我们前面在全局描述符表GDT中定义的第三个描述符,就是我们的显存段描述符,我们往显存段中写入内容,便会输出到屏幕上。
②如果接受到的这个字符是回车/换行/删除键,那么需要特殊处理
③如果当前整个屏幕满了,那么需要整体往上挪一行,把最后一行空出来
④默认是80*25的
⑤每次都需获取光标位置,来进行接下来的操作
⑥访问CRT controller寄存器组的的寄存器,先往端口地址为0x03d4的Address Register寄存器中写入寄存器的索引,然后再从端口地址为0x03d5的Data Register寄存器中读写数据

3.代码put_char

TI_GDT  EQU  0
RPL0  	EQU    0 
SELECTOR_VIDEO	EQU (0x0003<<3) + TI_GDT + RPL0
 //显存段描述符

[BITS 32]
SECTION .text

;/*******put char**********/
global put_char
put_char:
	PUSHAD			;save all registers
	MOV AX, SELECTOR_VIDEO
	MOV GS, AX

	;获取当前光标的位置
	;High 8 bit
	MOV DX, 0x03d4
	MOV AL, 0x0e
	OUT DX, AL
	MOV DX, 0x03d5
	IN  AL, DX
	MOV AH, AL

	;Low 8 bit
	MOV DX, 0x03d4
	MOV AL, 0x0f
	OUT DX, AL
	MOV DX, 0x03d5
	IN  AL, DX

	MOV BX, AX		;保存当前的光标位置
	
	;获取栈中那个 字符参数
	MOV ECX, [ESP+36]

	CMP CL, 0xd
	JZ  .is_carriage_return

	CMP CL, 0xa    ;换行
	JZ  .is_line_feed

	CMP CL, 0x8    ;退格 也就是删除键
	JZ  .is_backspace
	JMP .put_other


.is_backspace://如果是删除键
	DEC BX				;cursor--
	SHL BX, 1
	MOV byte [GS:BX], 0x20		;0x20 = space
	INC BX
	MOV byte [GS:BX], 0x07
	SHR BX, 1
	JMP .set_cursor



.put_other:
	SHL BX, 1
	MOV [GS:BX], CL			;CL is Ascii
	INC BX
	MOV byte [GS:BX], 0x07          ;black background white font
	SHR BX, 1
	INC BX
	CMP BX, 2000			;line end
	JL  .set_cursor


.is_line_feed:				;\n \r
.is_carriage_return:
	MOV DX, 0
	MOV AX, BX
	MOV SI, 80
	DIV SI
	SUB BX, DX


.is_carriage_return_end:
	ADD BX, 80
	CMP BX, 2000
.is_line_feed_end:
	jl .set_cursor


 
	


.roll_screen:				;start addr 0xc00b8000  all is 2000
	CLD				;DF = 0
	MOV ECX, 960			;2000-80 = 1920 1920*2 = 3840 Bytes
					;3840/4 = 960
	MOV ESI, 0xc00b80a0		;a0 = 160 = 80*2Bytes
	MOV EDI, 0xc00b8000
	REP MOVSD

;/*******Clear End Line****/
	MOV EBX, 3840
	MOV ECX, 80
	
.cls:
	MOV word [GS:EBX], 0x0720	;black background white font
	ADD EBX, 2
	LOOP .cls
	MOV BX, 1920 			;last line
	
.set_cursor://写入新的光标位置

	;Set High 8 bit
	MOV DX, 0x03d4
	MOV AL, 0x0e
	OUT DX, AL
	MOV DX, 0x03d5
	MOV AL, BH
	OUT DX, AL

	;Set Low 8 bit
	MOV DX, 0x03d4
	MOV AL, 0x0f
	OUT DX, AL
	MOV DX, 0x03d5
	MOV AL, BL
	OUT DX, AL

.put_char_down:
	popad
	ret

4.put_str代码

global put_str
put_str:

	PUSH EBX			;EBX作为字符串的首地址 ECX提取出每个字符
	PUSH ECX			;只用到了这两个寄存器 

	MOV ECX, 0		
	MOV EBX, [ESP+12]
	
.goon:
	MOV CL, [EBX]
	CMP CL, 0			; 0 字符串结束标志
	JZ  .str_over

	PUSH ECX
	CALL put_char
	ADD ESP, 4
	
	INC  EBX
	JMP  .goon	

.str_over:
	POP ECX
	POP EBX

	RET

5.put_int代码

;/**put_int****/
global put_int
put_int:
	
	PUSHAD			;里面已经保存EBP了 CALL这个函数的时候 自动保存EIP
	MOV  EBP,  ESP

	MOV  EAX,  [EBP+4*9] ; 8register+EIP
	MOV  EDX,  EAX
	MOV  EDI,  7		  ;存放在buf中的偏移量
	MOV  ECX,  8		  ;分八次处理
	MOV  EBX,  put_int_buffer  ;字符缓冲区

.16based_4bits:
	
	AND  EDX, 0x0000000F  ;每四个二进制位 是16进制的1位
	CMP  EDX, 9
	
	JG   .isA2F			;如果大于9的话 那么就是A-F 
	ADD  EDX, '0'		;没有大于9 那么直接加上'0'
	JMP  .store         ;存储到缓冲区


.isA2F:
	SUB EDX, 10
	ADD EDX, 'A'
.store:
	MOV [EBX+EDI], DL	;EBX+EDI 是buf数组+偏移量 DL是转化成的16进制数
	DEC EDI
	SHR EAX, 4			;每次求出最低四位的16进制形式
	MOV EDX, EAX
	LOOP .16based_4bits

.ready_to_print:
	MOV EDI,  0
.skip_prefix_0:			;跳过前导0
	
	CMP EDI,  8			;已经是第9次比较了 而且前面全是0
	je  .full0

.go_on_skip:
	MOV CL, [put_int_buffer+EDI]
	INC EDI
	CMP CL, '0'
	JE  .skip_prefix_0
	
	DEC EDI
	JMP .put_each_num	;发现第一个不为0的 直接输出后面全部的

.full0:
	MOV CL, '0'

.put_each_num:
	PUSH ECX
	CALL put_char
	ADD ESP, 4
	INC EDI
	MOV CL, [put_int_buffer+EDI]
	CMP EDI, 8
	JL  .put_each_num
	POPAD
	RET

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值