本次课内容:
考虑一个简单的计算机系统: 程序直接在CPU上运行(无操作系统)
这三个抽象层次(程序, 指令集, CPU)都可以用状态机来理解!
C语言的组成
一个例子
/* 1 */ int main() {
/* 2 */ int x = 1;
/* 3 */ int y = 2;
/* 4 */ int z = x + y;
/* 5 */ printf("z = %d\n", z);
/* 6 */ return 0;
/* 7 */ }
main()
第一条语句开始执行吗?大家一定会觉得这是理所当然的, 至少很多C语言书籍都这么说
但怎么来动手验证一下呢?
好像还有个exit_group()
,
感觉从main()
函数返回之后也有宝藏
5.1.2 Execution environments
Two execution environments are defined: freestanding and hosted. In both cases,
program startup occurs when a designated C function is called by the execution
environment...
有一个概念叫执行环境
, 原来是它来调用一个专门的C函数
5.1.2.1 Freestanding environment
1. In a freestanding environment (in which C program execution may take place
without any benefit of an operating system), the name and type of the function
called at program startup are implementation-defined.
在独立环境下, 这个专门的C函数由具体实现来决定
5.1.2.2 Hosted environments
5.1.2.2.1 Program startup
1. The function called at program startup is named main...
在宿主环境下, 这个专门的C函数名称为main
2. ...
— If the value of argc is greater than zero, the string pointed to by argv[0]
represents the program name; ...
If the value of argc is greater than one, the strings pointed to by argv[1]
through argv[argc-1] represent the program parameters.
上次课提到的命令行参数=main()函数的参数
,
原来是有手册依据的
5.1.2.3 Program execution
2. Accessing a volatile object, modifying an object, modifying a file, or calling
a function that does any of those operations are all side effects, which are
changes in the state of the execution environment...
一些语句的操作会引起副作用, 从而导致执行环境状态的变化
虽然main()
函数不是真正的程序入口,
但足够用来理解状态机模型
C语言标准手册精确定义了C语言的每一处细节
大部分C语言的材料都没有覆盖到所有细节, 因此不要迷信书籍和博客
正确的学习方法:
开放讨论: 公司不一定完全按标准来实现
CPU如何设计是微结构层次的话题
但无论怎么设计, 总归是一个数字逻辑电路
// S = <A, B, C, D>
S0 = <0, 0, 0, 0>
S1 = <1, 0, 0, 0>
S2 = <1, 1, 0, 0>
S3 = <1, 1, 1, 0>
S4 = <1, 1, 1, 1>
S5 = <0, 1, 1, 1>
S6 = <0, 0, 1, 1>
S7 = <0, 0, 0, 1>
S8 = <0, 0, 0, 0> = S0
从状态机的视角来说, CPU和这个计数器并没有本质上的区别
课本上通常会给一个抽象的定义, 例如
指令集是软件和硬件之间的接口
这句话本身是对的, 但对初学者来说没什么实际意义
我们来进行这样的比喻: 指令集是一本手册规范, 使得
指令集手册定义了CPU执行指令的行为
就好比
C语言标准手册定义了C程序执行语句的行为
包云岗老师对文章《点评RISC-V芯片出货量突破100亿》的补充评论:
出自《从技术的角度来看,RISC-V 能对芯片发展、科技自主起到哪些作用?》
《俄数字发展部部长:将大力扶持国产 RISC-V 处理器发展》
推荐参加“一生一芯”补充基础知识, 零基础亦可学习
虚假的RISC-V手册 ❎
真正的RISC-V手册 ✅
《The RISC-V Reader》是一本科普读物, 并不是官方手册
We intend this slim book to work as both an introduction and a reference to RISC-V
for students and embedded systems programmers interested in writing RISC-V code.
我们打算将这本小书作为RISC-V的介绍和参考资料,供有兴趣编写RISC-V代码的学生和嵌入式系统程序员使用
翻译团队把书名翻译成《RISC-V手册》, 太误导新人了 😂
《The RISC-V Reader》的作者(David Patterson & Andrew Waterman)也来自RISC-V团队, 书的质量并不低
正确做法:
Q: RISC-V处理器的复位PC值是多少?
A: RTFM (《The RISC-V Reader》中找不到答案)
计算1+2+...+100
的指令序列
// PC: instruction | label: statement
0: li x1, 0 | pc0: x1 = 0;
1: li x2, 0 | pc1: x2 = 0;
2: li x3, 100 | pc2: x3 = 100;
3: addi x2, x2, 1 | pc3: x2 = x2 + 1;
4: add x1, x1, x2 | pc4: x1 = x1 + x2;
5: blt x2, x3, 3 | pc5: if (x2 < x3) goto pc3; // branch if less than
6: j 6 | pc6: goto pc6;
指令并没有想象中的那么神秘
指令的两种表示:
全称: 指令集体系结构(Instruction Set Architecture, ISA), 还有
这些都可以用状态机模型来描述行为
指令集手册通过定义状态机进行状态转移的规则, 来从概念上描述一台抽象计算机所具备的, 程序可以使用的功能
使用计算机底层功能的用户(系统程序员)无需了解具体的电路设计
编译器的工作: 将C程序的状态机\(S_c\)翻译成指令集的状态机\(S_{isa}\)
使得
\(s_{compile}(next(S_c, 语句))\)
\(= next(s_{compile}(S_c), e_{compile}(语句))\)
\(= next(S_{isa}, 指令序列)\)
说人话: C程序执行一条语句后的状态, 与抽象计算机执行编译后的指令序列后的状态,语义上是等价的
汇编课就这样上完了 😂
CPU微结构设计的工作: 根据指令集的状态机\(S_{isa}\)用电路实现CPU的状态机\(S_{cpu}\)
使得
\(s_{arch}(next(S_{isa}, 指令))\)
\(= next(s_{arch}(S_{isa}), e_{arch}(指令))\)
\(= next(S_{cpu}, 组合逻辑电路)\)
说人话: 抽象计算机执行一条指令后的状态, 与CPU在根据指令语义设计出的组合逻辑电路控制下的次态,语义上是等价的
程序和指令集都没有实体, 计算机的实体是电路, 如何联系它们?
机器永远是对的
计算机系统的行为是按照官方手册的描述精确发生的
程序 | 抽象计算机 | CPU | |
---|---|---|---|
状态 | \(\{<V, PC>\}\) | \(\{<R, M>\}\) | \(\{时序逻辑电路\}\) |
状态转移规则 | C语言语句的语义 | 指令的语义 | 组合逻辑电路 |
FM | C语言标准手册 | 指令集手册 | 架构设计文档 |