首页 > 其他分享 >《操作系统真相还原》实验记录1.2——print.S打印函数

《操作系统真相还原》实验记录1.2——print.S打印函数

时间:2024-12-21 20:20:46浏览次数:4  
标签:字符 打印函数 1.2 Register char put 寄存器 print 光标

一、print.S文件说明

  1. put_char 函数(每次只打印一个字符)是各种打印函数的核心

1.1 功能说明

  1. put_char 函数的处理流程
    1. 备份寄存器现场;
    2. 获取光标坐标值,光标坐标值是下一个可打印字符的位置;
      1. 为了在光标处打印字符,需要读取光标坐标寄存器,获取光标坐标值。
    3. 获取待打印的字符;
    4. 判断字符是否为控制字符:
      1. 若是回车符、换行符、退格符三种控制字符之一,则进入相应的处理流程;
      2. 否则,其余字符都被粗暴地认为是可见字符,进入输出流程处理;
    5. 判断是否需要滚屏;
    6. 更新光标坐标值,使其指向下一个打印字符的位置;
    7. 恢复寄存器现场,退出;

1.2 原理说明

  1. put_char 的打印原理是直接写显存;
  2. 在 32 位保护模式下对内存的操作是“段基址(选择子):段内偏移量”,因此需要使用到视频段选择子,我们使用段寄存器 gs 来存储视频段选择子。

二、前置知识点

  1. 显卡操作只用到了CRT Controller Registers 分组中的寄存器;
  2. CRT controller 寄存器组的 Address Register 的端口地址默认为0x03D4,Data Register 的端口地址0x03D5。
  3. 计算机工程师把数据结构中数组的知识用到了硬件中。他们把每一个寄存器分组视为一个寄存器数组,提供一个寄存器用于指定数组下标,再提供一个寄存器用于对索引所指向的数组元素(也就是寄存器)进行输入输出操作。这样用这两个寄存器就能够定位寄存器数组中的任何寄存器。
  4. 这两个寄存器就是各组中的 Address Register 和 Data Register。
    1. Address Register 作为数组的索引(下标);
    2. Data Register 作为寄存器数组中该索引对应的寄存器,它相当于所对应的寄存器的窗口,往此窗口读写的数据都作用在索引所对应的寄存器上;
    3. 对这类分组的寄存器操作方法是先在 Address Register 中指定寄存器的索引值,用来确定所操作的寄存器是哪个,然后在Data Register 寄存器中对所索引的寄存器进行读写操作;

三、代码展示

汇编代码

TI_GDT equ 0
RPL0 equ 0
SELECTOR_VIDEO equ (0x0003<<3) + TI_GDT + RPL0 ;create SELECTOR_VIDEO.

[bits 32]
section .text
;---------------------put_char--------------
;The function's behavior:write one char from stack to the address where the cursor point.
;-------------------------------------------
global put_char ;extern document can invoke this function.
put_char:
    pushad   ;pushad:push all double.Back the environment of all "double byte registers" in 32 mode(totlally have numbers of 8).
    mov ax, SELECTOR_VIDEO
    mov gs, ax    ;we can't push number to fragment register directly.

;-----------get the cursor's address--------
;first: get the high 8bit.
    mov dx, 0x03d4
    mov al, 0x0e  ;Cursor Location High Register
    out dx, al   ;designate offset of register group.
    mov dx, 0x03d5
    in al, dx
    mov ah, al
;second: get the low 8bit.
    mov dx, 0x03d4
    mov al, 0x0f   ;Cursor Location Low Register
    out dx, al
    mov dx, 0x03d5
    in al, dx
;store cursor's address to register of bx.
    mov bx, ax
;get the string we want to print.
    mov ecx, [esp + 36] ;pushad us 4 × 8 = 32byte,the return address use 4byte,so the string's address is under esp + 36.

    cmp cl, 0xd  ;Carriage Return's ASCLL is 0xd
    jz .is_carriage_return
    cmp cl, 0xa  ;Line feed's ASCLL is 0xa
    jz .is_line_feed
    cmp cl, 0x8  ;backspace's ASCLL is 0x8
    jz .is_backspace
    jmp .put_other

.is_backspace:
    dec bx     ;bx - 1,and the bx is cursor's value.
    shl bx, 1  ;make the cursor's value to real address in video memory.

    mov byte [gs:bx], 0x20  ;0x20:the ASCLL of space.
    inc bx     ;bx + 1  ;bx(real address) is point to the char's attribute
    mov byte [gs:bx], 0x07  ;black background and white font color.
    shr bx, 1  ;make the real address in video memory to cursor's value,and forget the remainder.
    jmp .set_cursor
.put_other:
    shl bx, 1
    mov byte [gs:bx], cl
    inc bx
    mov byte [gs:bx], 0x07
    shr bx, 1
    inc bx
.is_line_feed:
.is_carriage_return:
    xor dx, dx
    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
;_____________Pay attention : this code is not achieving Scroll!________________________________________
.set_cursor:
    mov dx, 0x03d4
    mov al, 0x0e
    out dx, al
    mov dx, 0x03d5
    mov al, bh
    out dx, al

    mov dx, 0x03d4
    mov al, 0x0f
    out dx, al
    mov dx, 0x03d5
    mov al, bl
    out dx, al
.put_char_done:
    popad  ;is the otherside of pushad
    ret    ;return from put_char function.

C主函数

#include "print.h"

void main(void) {
	put_char('k');
	put_char('e');
	put_char('r');
	put_char('n');
	put_char('e');
	put_char('l');
	put_char('\n');
	put_char('1');
	put_char('2');
	put_char('\b');
	put_char('3');
	while(1);
}

标签:字符,打印函数,1.2,Register,char,put,寄存器,print,光标
From: https://www.cnblogs.com/Yu-Xing-Hai/p/18621123/print_S

相关文章

  • 【k8s集群应用】kubeadm1.20高可用部署(3master)
    文章目录Kubeadm-K8S1.20-高可用集群部署Kubernetes环境准备1.基础配置2.修改主机名3.修改hosts文件4.时间同步5.Linux资源限制6.升级内核7.调整内核参数8.加载ip_vs模块Kubernetes集群部署在所有节点上安装Docker在所有节点上安装kubeadm、kubele......
  • 11.21
    软件设计                 石家庄铁道大学信息学院 实验 20:备忘录模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容: 1、理解备忘录模式的动机,掌握该模式的结构;2、能够利用备忘录模式解决实际问题。 [实验任务一]:多次撤销改进课堂上的“用......
  • 11.22
    软件设计                 石家庄铁道大学信息学院 实验21:观察者模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:1、理解观察者模式的动机,掌握该模式的结构;2、能够利用观察者模式解决实际问题。 [实验任务一]:股票提醒当股票的价格上涨或......
  • 11.25
    软件设计                 石家庄铁道大学信息学院 实验 22:状态模式本次实验属于模仿型实验,通过本次实验学生将掌握以下内容: 1、理解状态模式的动机,掌握该模式的结构;2、能够利用状态模式解决实际问题。 [实验任务一]:银行账户用Java代码模拟实现课堂......
  • 东方通TongWeb7.0.4.9M4部署SuperMap iServer 11.2.1
    一、软件版本操作系统:CentOSLinuxrelease7.5.1804(Core)JDK:11.0.18东方通:TongWeb7.0.4.9M4SuperMapiServer:11.2.1JDK和TongWeb软件分享:链接:https://pan.baidu.com/s/1HGDTPnPID0PEOMbg3FjTVQ?pwd=bh8v提取码:bh8v东方通软件许可请从其官网申请二、东方通......
  • 11.25~12.15 总结
    题目有点多,这里就不写算法相关内容了(其实也没搞完)。NOIP前主要为了增加一点调试能力去写了大模拟,但是好像用处不是很大。NOIP场上主要的问题是半场开始比较懈怠,以及没有严格测试程序(虽然这次运气比较好没有挂T3和T2的大部分分数)。必须在Linux下测试程序和所有大样例。场......
  • 11.25 每日总结(适配器模式)
    今天学习适配器模式马上要设计模式考试了,ε=(´ο`*)))唉 定义:适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。 定义: 适配器模式将某个类......
  • 11.29 每日总结(学习机器学习)
    今天一直在搞机器学习作业。真难啊,学习时长:4小时 1、实验目的深入理解决策树、预剪枝和后剪枝的算法原理,能够使用Python语言实现带有预剪枝和后剪枝的决策树算法C4.5算法的训练与测试,并且使用五折交叉验证算法进行模型训练与评估。2、实验内容(1)从scikit-learn库中加载iri......
  • 11.22 每日总结(单例模式)
    今天学习单例模式单例模式定义:确保一个类最多只有一个实例,并提供一个全局访问点单例模式可以分为两种:预加载和懒加载 预加载顾名思义,就是预先加载。再进一步解释就是还没有使用该单例对象,但是,该单例对象就已经被加载到内存了。publicclassPreloadSingleton{publi......
  • 11.26
    测量和实验是所有改善程序性能尝试的基础。本内容及将介绍两种测量性能的工具软件:分析器和计时器软件。我将讨论如何设计性能测量实验,使得测量结果更有指导意义,而不是误导我们。最基本和最频繁地执行的软件性能测量会告诉我们“需要多长时间”。执行函数需要多长时间?从磁盘读取配......