Raspberry Pi Screen03

实验目标

在图形界面上实现文本,以及一个命令行的功能。

背景补充

字符串及其编码

我们都知道计算机可以将字符显示到屏幕上,同时我们也知道计算机无法直接处理文本信息,因为它只认识bit和byte,并在数字的基础上做运算,所以实际上我们需要制定的是一种映射关系,使得计算机能将屏幕上显示的内容与内存中的信息联系起来。所以在我们录入信息的时候可以看做我们将文本加密成一种计算机可识别的信息,反过来显示的时候就是计算机的特定信息解密成可显示的文本,这其中的加密与解密的秘钥就是我们所说的编码,一种编码对应一种加解密方式,也就是说当你使用了错误的编码那么所得到的结果就注定是一种错误的乱码。

由于自然语言的多种多样,导致了编码时的难以统一,在现在网络的大环境下,必须要用同一的标准也就是说,在计算机里的同一个数字要对应同一个字符,尤其是面对多语音的混合文档。所以就像该书所说:

Everything you thought you knew about strings is wrong.

ASCII

ASCII是专门为英语设计的,也是计算机非常流行的一种编码方式,使用一个字节的低7位(共8位),剩余的1位被用来制定其它语言的字符或者特殊符号,但是标准不是很统一。

Unicode - UTF32

UTF32的设想是用4个字节来表示所有自然语言的字符,不存在二义性,比如说U+0041总是代表'A',即使这种语言没有'A'这个字符。但问题是,对于某些字符来说(比如说英语),4个字节是一种大大的浪费,这对空间的占用不可忽视,虽然说这种编码方式可以准确全面的定位到所有的字符,但是在绝大多数的使用场景中,都不会用到这么多种字符。

Unicode - UTF16

UTF16就是缩减到2个字节,对于盲区的字符用其他方法索引实现,这样一来就能大大减少空间使用。但是UTF32与UTF16都有一个很大的问题就是,对于计算机不同的大小端存储方式,可能会造成数据混乱。这里引入了Byte Order Mark(字节顺序标记),如果一个文档以FFEE开头则说明是单向,以FEFF开头则说明是反向文档。

Unicode - UTF8

人们对于UTF16的空间存储造成的浪费以及对于盲区字符的困扰没有满足,重新设计UTF8,这是一种变长的编码系统,对于不同的字符选择合适大小的存储空间,但是查询的索引可能复杂度高于前两者。

参考资料1

参考资料2

字体显示

早期的字体显示是用可以类比位图,这样的缺点就是我们需要给同一个字符设置许多种不同的大小来满足需求,很显然这样是非常愚蠢的一种做法,后来我们用向量来表示不同的字体,这样我们存储一个字符实际上就是存储这个字符的表述信息,比如说字母'o'我们就可以描述成一个圈。(尽管向量描述是一个优秀的方法,但是在本次实验中我们任然采用第一种位图的方法,因为实现起来相对容易一些),在原文中给了一个字母A的例子

可以看到,每一排都是8位,非0即1,每一排都可以对应一个特有的序列,我们用16进制表示

  1. 00
  2. 00
  3. 00
  4. 10
  5. 28
  6. 28
  7. 28
  8. 44
  9. 44
  10. 7C
  11. C6
  12. 82
  13. 00
  14. 00
  15. 00
  16. 00

代码分析

drawCharacter

这个实际上的逻辑就是根据传入的具体字符,得到上述表示的每一行像素的8位表示,然后再通过起始的x与y坐标进行绘制,原文中给出伪代码与汇编对照看,容易理解。

drawStrings

画出一个字符串实际上就是多次画出其包含的每一个字符,除此之外我们还需要考虑的是什么时候能换行与结束。实际上我们在检查边界条件代码与上面drawCharacter的代码结合起来就可以了。(汇编代码中有一处是替换掉了loop循环中的乘法运算,因为位图的固定大小优势使得我们可以这样做)

命令行绘制

我们首先要了解实验在ARM架构中的数据格式,整理翻译如下

  1. 数据是在「tag」标签中止的。
  2. 总共有9种标签,「core」内核,「mem」内存,「videotext」可视图文,「ramdisk」虚拟内存盘,「intrd2」初始RAM磁盘,「serial」串口,「revision」校验,「videolfb」「cmdline」命令行。
  3. 标签只能出现一次但「core」是缺省标签。
  4. 标签地址是从0x100依次排列的。
  5. 在标签的末尾总是包含两个全0的字节。
  6. 大小是4的整数倍
  7. 标签总是以其大小为开始的,这个大小也包含其本身。
  8. 实际上标签是以从1到9的序号来代表他们的。
  9. 数据格式总是跟着一个5441(hex)的半字。
  10. 字中的数据长度+2总是能符合要求的
  11. 「core」既可以是2也可以是5的长度,如果是2那么没有数据,如果是5则代表有3个字。
  12. 「mem」4个字的长度,数据和总长度是在首地址的。
  13. 「cmdline」包含一个空的中止字符串,这个内核的一个重要特点。

在我们的实验中只有「core」「mem」「cmdline」出现。

首先初始化将1-9标签都设为 .int 0

FindTag

在这个函数中,首先检查标签范围,然后检查地址并将其设置为0x100,接下来在loop循环中依次获取tag的数据即可。

Hello World

mov r0,#9
bl FindTag
ldr r1,[r0]
lsl r1,#2
sub r1,#8
add r0,#8
mov r2,#0
mov r3,#0
bl DrawString
loop$:
b loop$

利用FindTag找到9号「cmdline」标签计算出长度等信息,然后传入参数,以及初始化,画出字符,大功告成。