【云驻共创】小而全mini系统:深入理解计算机系统之路,掌握从CPU设计到操作系统开发的全流程
前言
在计算机系统学习中,我们常陷入“知识碎片化”和“理论脱离实践”的困境。如何用最小成本掌握核心原理?
本文详细介绍了湖南大学博士生导师杨科华教授在计算机专业教学中构建的实践教学体系,通过“小、全、缓、连”四个核心理念,帮助读者深入理解计算机系统原理,并逐步掌握从CPU设计到操作系统开发的全流程。
一、整体问题
1.1 计算机类核心实践课程面临困难
目前在实践教学过程中其实存在着不少的困难和问题,主要有以下几点:
- 理论与实践脱节,课堂知识与实践环节无法对应
- 工业级软件/硬件非常复杂,容易产生劝退的效果
- 完整的实践案例涉及的技术栈多,容易顾此失彼
- 过程重要性 vs. 结果重要性
1.2 “小、全、缓、联”四大理念
为了让同学在学习时更有效率,让大家能够更加轻松且愉快的开始计算机专业的知识学习之旅。杨教授在设计这个实践体系的时候,就秉承这样的一个理念。
- 小:每个系统都控制规模,可以在一个学期内完成学习
- 全:每个系统都包括相应的基本原理
- 缓:系统内部进行细化,拆解成多个 小模块,减缓知识坡度
- 联:各个系统之间都有联系,包含软硬件协同等基本思想

第一个是小,就是要求就是每个系统都控制规模,暂时不去考虑这个可靠性、运行性能、功耗等内容,专注于这个原理验证。一般我们是想在一个学期,也就是大概3到4个月的这样一个教学周期内,通过课程授课和实践动手,可以完成一个系统。
第二个是全,就是麻雀虽小五脏俱全。我们的系统虽然是个小系统,但是都是能够真正运行,真正解决问题,讲清楚原理的一个系统。
第三个是缓,就是就算是小系统也能拆解。我们要能够让绝大多数的计算机专业,能够考上大学的同学,每一个地方就是在一节课或者两节课,也就说最多一个半小时就能让同学们能够真正做出点东西。他有正反馈,有成就感,有多巴胺的分泌,从而就能够形成这种正反馈,能够一步一步的往前走。
最后一个就是联,我们开发的小系统,有的是硬件,有的是软件,但绝不是泾渭分明,而是相互之间有联系的。我们尽量去挖掘每一个知识点与前面所学知识的联系,同时又为后面的知识点做准备。当然也强调和融入了软件协同等基本思想。
二、hnuVSPM
2.1 hnuVSPM的“小、全、缓、联”
第一个是一个小,hnuVSPM也就是湖南大学非常简单原型机。这个CPU非常的小,硬件上我们只有七个寄存器,其中是有四个通用寄存器,一个是数据寄存器,还有一个指令寄存器,还有一个标志为寄存器。内存空间只有256个字节指令也只有12条。这12条指令如下:

那么这12条指令大家看出来这个其实也非常容易理解。包括:4条move指令、1条立即的传送指令、1条加法指令、1条减法指令、2条跳转指令、1个无条件跳转、1个有条件跳转、1个输入、1个输出。所以这就是我们在这种设计的时候,对于同学来讲就是非常容易去理解。
我们从全的方面来讲,虽然我们很小,但个能是齐全的。在教学的时候,我们会从两个层面来说明,一个是我们现在用的笔记本电脑、平板、手机都是冯若伊曼体系结构。我们这一个设计的这个原型机,它实际上也有输入输出,也有运算存储和控制,所以它是一个全的一个系统。另外这个里面只有做加法和减法,但是我们有跳转指令,那么乘法和除法也可以。

在缓这个方面,我们实际上是用了八个实验,逐步实现个CPU这是我们实验指导数得的目录。
首先第一个实验就是首先熟悉鲲鹏Pro开发板的运行环境。然后用两个实验来实现这个组合逻辑部件,再用两个实验来实现时序部件,然后再用一个实验来实现这个控制制部件进程集成和测试。我们湖南大学的同学在大二一期的时候,绝大多数同学都能够在一个时期内完成这些实验来实现CPU。

2.2 hnuVSPM的实现细节
下面我们介绍一下hnuVSPM的具体的实习细节。
首先这个是我们老师给的这个圆型机的一个结构构架图,那么描述要生成哪些部件?这些部件又如何去连接?当然初学者暂时不允许逛其中的细节,他有个整体的印象即可以。从这些部件开始实现,比如说我们这个打横圈的这个多路复印器,也叫二选一部件。
以这个为例,我们用两种方式实现。一是通过画图和搭积木的图形化方法(如图中下方所示),从逻辑文开始搭建这种具有二选一些部件。

还有一个就是右边这种就是我们用微等硬件描述也来搭建这个模块。在搭好以后,如何在学习怎么去进行一个调试和测试。这样一个一个的搭建起来,然后连接在一起,也就实现了整个的CPU。

为了让学生更加准确的理解这个中间过程,我们也开发了一个动画演示工具。就是用于显示每条指令执行时候各个部件的这种工作状态,总线上数据的传输情况。大家可以看到,现在当然我是在修改这个指令集,这个可以稍微加快一点,做完以后,实际上在这个指令完成以后,保存好,然后再点击运行。大家可以看到这个时候每一个执行的时候,这个总线上和每一个部件的输入输出,以及每一个数据的这么一个执行过程。当然这个地方是可以暂停,大家是可以调试。通过这样的方式,就能够更加准确的明白这个CPU的原理。

在CPU完成之后,我们有这种用这个观察波形的方式来进行验证。但最好还是实际运行一个代码,看看能够完美的执行了这个功能。左边是一个声源程序,当然这个声音源代码,这个CPU是不认识的,认识的只是汇编和机械指令。因此我们需要把这一个代码要转成这么一些汇编或者信息指令。不过现在还没有这个编译器,我们只能人肉编译一下,自己手动的把左边这个代码转成右边的这些内容。
这个代码它实际上是输入一个值以后计算它的累加和。

每一步执行时候,它会分别对这个计算器会有什么影响?执行的时候到了哪里,这个地是什么样子?
每一步执行的时候,当前运行的指令,CPU的计成器变化情况都可以这外看到。你要更好的了解了此优的这个底层性机制。
我们另外还开发了一个就是为了贴近实际的运行逻辑,开发了这个原型机的模拟器。学生可以在载入这个指令后分布运行,然后通过这种方式输入不停的命令来查看内存。

我们在计算机系统这门课,可以学习怎么来调试这个程序的运行。在这里有了这个基础,后面的这个就很容易去理解了。当然如果有条件的话,我们是可以把CPU烧录到香橙派鲲鹏Pro开发板,这样一来就相当于一个物理上的CPU。我们可以看一下,我们把刚才那一个累加和的程序,已经和CPU一起烧录到了这个上面。这样就我们可以真实来看一下这个运行的结果。

2.3 搭台阶式教学
第一个台阶就是用Logisim或Digtal等开源工具,然后用搭积木方式来实现一个简单的CPU。
这个对于初学者非常的友好。因为他只需要有基本的数学基础和逻辑代数基础,他就可以加上一点点时序电路的知识就可以完成。这个就相当于在给小学生做编程培训的时候,一般来讲不会直接C语言。所以这个也是说对于一般的同学,你就直接用这个搭积木方式来搭。

有了基础以后,我们可以使用Verilog或VHDL等硬件描述语言编写代码,定义硬件电路。也能够为后续实现更为复杂的CPU打下基础。

第三个台阶就是我们把设计好的电路烧录到FPGA上,实现一个物理意义上真正的运行的CPU。
因为前面两个都是说在这个软件上进行模拟。如果想要实现在FPGA上,你要初步开始有一点中断处理机制,还要学会怎么样进行硬件调试。当然还可以进行更高深的功耗分析等等。

有了这个三个的基础,实际上我们开始就是进行各种扩展。
还是前面那个例子,我们只有加法、减法和条件跳转指令,当然可以用这个指令来组合成一个乘法操作,但是我也可以增加一个硬件电路专门来做乘法。把这个加进来以后,指令集要怎么扩充?整个的数据通路图、数据结构图怎么改?具体怎么实现?控制逻辑怎么改?都需要考虑。
在这个基础上,这个台阶这一块就要进行完成。同时有了这样的基础,实际上就可以从CPU设计人员的角度来分析不同实际的CPU的硬件结构,还有不同实际CPU的指令集,这些对应关系和我为什么要这样去设计。

第五个台阶实际上就是说我们就能够根据这个指令及硬件设置的信息,要熟练的生成CPU的架构图,运用硬件描述来完成。
因为你已经有了前面的基础,那我们就可以开始尝试了用这个原型就是性能提升更提升。简单来说,刚才我们做的都是单周期的CPU,在每支线程指令的时候,这个电路部件都是轮流休息的。
如果说能够让这些电路部件减少休息时间,性能也能够得到提升,这就是多周期和流水线技术的基本思路。
我们在湖南大学的这一个整个实验过程中,也增加了实验九和实验十,也就稍微进行一点扩展。当然了,这个里面也涉及了非常多的技术。一般就是比优秀的学余类的学生来进行这样的一些操作。整的来说我们的目标是让初学者从零开始实现自己的CPU。

三、miniCC工具链
下面我们来实现这个软件部分,也就是说是miniCC的一个编译工具链。它的作用是能够将一个C语言,当然也可以是Java或者Python语言这种简单的能够编译成各个不同平台的可执行程序。
同样也从“小、全、缓、联”几方面来讲。
3.1 miniCC的“小、全、缓、联”
首先是小。我们这个命令信息编译根据链的整个代码是一万行左右,并且都是Java语言,从头开始编写,结构清晰易于理解。
左边这个是我们这个编译器的一个最简单的版本,它就只支持整数的定义,只有顺序语句、分支判断语句、循环语句的C语言进行处理。整个只有两千余行代码。
我们是基于javaCC开始的编写,只有七个类,所以需要自己写。其他的都是基于javaCC的自动生成。那么有了javaCC框架支持,学生就只用关注于C语言的语法规则描述,暂时不用去管这个词法分析、语法分析以及智能机生成等等细节。也就是说对于学生来讲,虽然编译器是大三才学。但是在大二学这个的时候,学生只要稍微学习一点正则表达式的知识,就可以来实现一个C语言执行的编译器。

第二个是全。我们这个虽然比较简单,只有1万多行代码,但实际上跟GCC一样。我们这个miniCC也是包含了整个过程的支持。同时我所生成的汇编代码是能够被GCC再来跟它是兼容的。miniCC对GCC生成,是同样格式的中间文件。所以可以看到miniCC产生的汇编代码,可以GCC去编译、汇编和链接才会运行。或者是编译和汇编都有miniCC的处理,然后由GCC负责链接,这样能够逐步实现迅速的对照和验证。所以我们的miniCC是能够对C语言代码进行全流程的处理。

为了更好的缓一点,就是让每一个学生在半个小时或者1个小时能够有所收获,我们也在头歌平台上搭建了一个实验平台。把两千余行代码最简单版本的开成了28关,用闯关的方式,每一关都做一点点任务,并且都是可以独立运行看到成果的。所以对于这个编译器来讲,它实际上并不需要你去先去学边缘理。而是说只要你有一点代码的基础,就可以跟着这个指导去完成一个简单的编译器。其他的模块我们也都按照这个方式进行拆解。
当然我联是指我们做miniCC的初心就是要跟原型机联系起来。因为GCC等工业级编译器,根本就不知道我们开发了自己的原型机,所以也不可能支持将C语言代码转换到我们原型机上能执行的信息指令,那我们就只能自己来。因此我们就把miniCC也严格按照编译、汇编、链接程序,把C语言代编译到我们的原型机上能够运行的一个指令。同时因为VSPM有鲲鹏的香橙派,有之前的这个口袋猫,模拟器,所以我们这个代码在这个上面都是能运行。
因为这是一个非常简单的原型机,所以它的汇编和链接都是非常简单,但过程还是一致的。学生在学这里的时候,他还是需要去回顾我们原型机的原理和实现思路。

3.2 miniCC的编译过程
首先是编译器,把C语言编译成四元组。
这个时候如果输入A,那么它对应的第一个四元组就是int。
然后c=0,就是第二个四元组,然后for循环对应了多个四元组。这里面有复制、跳转等等。

因为都是我们自己写的代码,每一个转成几条汇编指令,或者单独的一个汇编指令分别是什么意思?我们都把它以注释的方式都生成了。这样一来,通过使用这个编译器我们能够更加清楚的知道C语言代码是怎么转成的四元组,四元组又怎么转成了汇编代码。每一条汇编代码分别代表什么意思?哪几条汇编指令组合起来就正好实现了一个四元组?就更容易学习和理解。

我们也可以把四元组转换到其他平台上。比如下面就是一个C语言的一个表达式计算语句,这一个表达计算语句就转成了七个四元组。而这七个四元组我们又转到了X86+Ubuntu的例子。

下面是我们把汇编指令转成这个机器指令的结果。可以看到所有的汇编指令都转到了这个机器指令,上面的0074等等,都是一条条的汇编指令转到机器指令的这个过程。右边是把这个汇编指令打包转成一个可执行文件的结果。可以看到,我们用miniCC按照操作系统规范,能够正确的将机器指令进行打包,让组装成一个可直接运行的代码。

3.3 搭台阶式教学
miniCC工具链是一个比较复杂的工具链。我们还是按照一步一个台阶的教这个方式来进行教学。
第一个台阶,最简单的编译器,输入的是一个C语言的子集,它只包括整数、赋值、分支、循环。
基于javaCC编写,只需要学生理解少量的正则表达式,就能写出一个简单的编译器。这个代码大2000行左右,分成28关。我们再用大约几百行代码,就能够把这个编译器产生的四元组转成我们原型机上的汇编或者机器指令。就能够与hnuVSPM对接,编译后的指令可以在vspm上运行并给出正确的结果。

第二个台阶,我们刚才写的这个编译器,有同学说太简单了,那么我们就在进行两方面的编辑的扩展。
- 增加对数组、指针、函数的支持
- 不基于javaCC,直接从头写一个较为完整的编译器
这样一来,对原型机的这个概念以及前面讲的CPU的功能扩展,学生就能派上用场了。

第三个台阶,是汇编器和链接器,我们要在真实的环境下进行实现。
因为所有代码都是自己写的,所以不管来个什么样的平台,我们都能处理。
除了Ubuntu、鲲鹏,实际上还有两个自制的操作系统。

第四个台阶,我们要求学生在基于香橙派鲲鹏Pro开发板上面的毕昇编译器的优化技术进行分析。包括循环优化增强等等,要求学生在这个上面嵌入到对译器进行实现。

第五个台阶,我们要对链接器进行优化。
在链接时,要考虑这个动态链接和静态链接、重定位优化、函数内联以及全局优化等等知识。
像动态链接和静态链接,一直是我们课程教学的一个难点和重点。如果说没有实验的支撑,只是一些理论学习,那么这个就很难去讲清楚,学生也不理解为什么要这样进行分类。如果学生能够做到这一步的话,那么这些知识可以非常容易的去理解。因为你自己都去做了,那你就当然就能够理解为什么要这样去搞。

四、miniEuler
多个程序同时在视频上运行是什么样的方式?接下来,我们用miniEuler来讲清楚这个问题。
4.1 miniEuler的“小、全、缓、联”
openEuler是华为的一个开源操作系统,代码量非常的多。它也是百万甚至千万行级别的这么一个操作系统。它有一个嵌入式的实时内核,它虽然是七年级的内核,但代码也是数万行到十万几十万行,这显然也是不适合来进行教学的。
所以我们将其进行了裁剪,只记保留开发操作系统所涉及到的核心关键技术,将需要浏览和学习的代码总量控制在八千多行左右。每次学实验学生需要动手去实现去完成,大概是几行到几百行左右。通过这样的过程,从零开始构建了一个操作系统。在这个过程中理清了这个技术的体系与脉络,然后建立了知识的连接。

从全的角度来讲,我们虽然只要去做这几行代码,但是miniEuler是一个可真正运行的操作系统,覆盖操作系统核心技术,包括系统调用、任务管理、内存管理、IO管理等核心技术。
当然了,我们miniEuler也是可运行在香橙派鲲鹏Pro开发板上的。我们通过外置的烧卡烧录进去以后,就可以插进去以后,通过拨码就可以设置它可以在启动的时候进行正常启动。

作为一个教学案例,我们是希望学生能够从零开始,从简单到复杂不断的扩展,最后构建一个完整的系统。
目前分成九个实验,每一步做完以后,学生都可以在开发板上直接运行。当然我们这九个实验,湖南大学的学生做每个实验,大概都是需要2到4个小时左右。
所以为什么前面我们要求学生还是要能掌握到这个台阶?就是因为在这里你可以了解中断机制和实验五关于时钟的机制。因为我们的简单原型机实际上是没有中断和时钟的。如果前面你会扩展,那么到这一步还是能够很容易的过渡的。

我们可以看到,我们这几个实验实际上是一个集大成者。它不仅是涉及到我们的数字电路设计,同时还包括计算机系统。这个计算机系统实际上就包括了我们的miniCC的概念的理解。所以我们看到这几个实验,它贯通了前后前序和后续过程,不仅需要去理解这个CPU的底层运行机制,还需要与编译工具链对接。甚至还要根据操作系统的这种特性,每次改一点东西,都要把编译器进行一个更多的扩展。

总结
以一个计算机专业的同学的角度而言,如果成功的实现了自己的CPU,并且陈零开发了编译器、汇编器、链接器,而构建还构建了一个完整的操作系统,那么他就能够更高效的识别,更且去消除系统中的缺陷,能够更好的进行系统的性能优化。这个经历也将使得他更能够更加自信的深入理解计算机系统的底层原理,编写出更稳健、更可靠、更安全的程序。同时他也将在解决复杂问题和设计复杂问题是复杂系统方面展现出更全面的能力,更有效率、更有底气、更为全面也是湖南大学一直在追求的境界。
通过杨科华教授分享的“小而全”的实践教学体系,让学生能够融会贯通计算机系统的各个层面,从硬件到软件全面掌握。提高学生识别和消除系统缺陷的能力,优化系统性能,编写更稳健、可靠的程序。培养学生的复杂系统设计能力,使其在未来工作中更具效率和底气。
与诸君共勉。
本文参与华为云社区【内容共创】活动第28期。
- 点赞
- 收藏
- 关注作者
评论(0)