first commit

This commit is contained in:
张乾
2024-10-16 10:18:29 +08:00
parent 9f7e624377
commit 4d66554867
131 changed files with 27252 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
因收到Google相关通知网站将会择期关闭。相关通知内容
温故知新 思考题参考答案(一)
你好,我是编辑小新。首先,祝你元旦快乐。
计算机基础的学习并非一蹴而就,希望课程里讲到的内容,像火种一样点燃你的学习探索兴趣。为了辅助你检验每节课的学习效果,我们留下了很多思考题。
今天这节答疑课,就是为了把思考题环节做个“闭环”,我们会公布每节课的参考答案。在对答案之前,还是建议你先自己尝试回答问题,哪怕只是大致整理一下思路,然后再对比看看老师给的思路,查漏补缺。
后面就是前四章,第一节课到第二十二节课的思考题参考答案,希望对你有帮助。
我在结束语里,看到有同学留言说:“学习计算机基础真的很开心,打通的感觉最为舒畅!”看到这样的留言,我和老师都非常开心。也非常欢迎学完一遍课程的同学常回来二刷、三刷,温故知新,有什么新的体会,也欢迎继续在留言区记录分享。
[第一节课]
Q为什么RISC的CPU能同时执行多条指令
A因为CPU内核中有多条指令流水线取指、译码、执行、访存、回写这些逻辑部件能同时和独立工作。
[第二节课]
Q为什么RISC-V要定义特权级
A因为RISC-V要支持操作系统和虚拟化它们需要管理资源需要用相应的特权来保护资源不被其它软件恶意使用。
[第三节课]
Q为什么很多特定算法用Verilog设计并且硬件化之后要比用软件实现的运算速度快很多
A因为Verilog设计的电路是并行执行的没有受到CPU流水线的限制所以速度会快很多。
[第四节课]
Q既然用Verilog很容易就可以设计出芯片的数字电路为什么我们国家还没有完全自主可控的高端CPU呢
A这是一个开放性的话题这里根据我的理解列举几点
芯片是一个需要技术积累的行业,从设计到生产,每一个环节都有技术壁垒,发展起来至少需要十到二十年。-
我国很多芯片行业起步晚在CPU方面国外早就有像Intel、AMD这样的公司形成垄断中国很难赶超Intel。-
芯片行业,品牌效应很重要,初创公司做出的芯片可能面临没人敢买的尴尬局面。-
芯片是一个很烧钱的且需要长期投入的行业,整个中国在集成电路方面的投入可能还不如国外一个大公司的投入多。-
5.高端芯片是需要一个成熟生态支撑的,需要软件和硬件配套使用,两个需要同步更新、互相促进,才能一直保持领先。
[第五节课]
Q今天我们讲到了RISC-V中的分支跳转指令JAL。想想看为什么要通过调整立即数的某些位从U-TYPE指令得到J-TYPE指令格式呢这样调整以后有什么好处
AJAL在立即数处编码了一个有符号偏移量这个偏移量加到pc上后形成跳转目标地址并将跳转指令后面的指令地址pc+4加载到rd跳转范围为±1MB这样就可以得到更大的跳转范围了。
[第六节课]
Q为什么要对指令进行预读取直接取指然后译码、执行不可以吗
A预读取是为了让流水线执行指令更高效特别是在执行分支跳转指令的时候预读取提供了简单的分支预测功能可以在发生跳转之前预测跳转方向并提前读取后续的指令。
[第七节课]
Q在6种指令格式中S型、J型和B型指令里的立即数是不连续的这是为什么
A为了让不同指令格式中尽可能多的字段信息保持位置重合降低译码难度同时减少硬件通路上mux数量从而减少硬件逻辑延迟。
[第八节课]
Q在ALU模块代码中为什么要把左移操作转换为右移进行处理
A把左移操作转换为右移操作可以复用右移操作的电路节省硬件电路的资源。
[第九节课]
Q除了数据冒险我们的CPU流水线是否还存在其它的冲突问题你想到解决方法了么
A流水线中除了数据冒险还可能存在结构冒险和控制冒险下节课我们将会讲解控制冒险。
[第十节课]
Q除了流水线停顿和分支预测方法是否还有其他解决控制冒险问题的办法
A控制冒险的第三种解决方法称为延迟转移也就是延迟转移顺序执行下一条指令并在该指令后执行分支。这需要用到汇编器对指令进行自动排序它会在延迟转移指令的后面放一条不受该分支影响的指令并且指令重新编排了后面的指令地址会发生变化。
[第十一节课]
Q计算机两大体系结构分别是冯诺依曼体系结构和哈弗体系结构请问我们的 MiniCPU属于哪一种体系结构呢
A哈弗结构是一种将程序指令存储和数据存储分开的存储器结构而冯·诺依曼结构的数据空间和地址空间不分开。显然我们的MiniCPU是把数据空间和地址空间分开的所以是哈弗结构。
[第十二节课]
Q请你说一说交叉编译的过程
A首先在主环境上用相应的编辑器写好源代码然后运行主环境上的交叉编译器对源代码进行编译最后生成目标平台的可执行程序。
[第十三节课]
Q处理环境变量后为什么要执行source ./.bashrc才会生效
Asource命令和“.”是一样的,所以也可以是. ./.bashrcsource命令与终端.bashrc脚本命令的区别是source是在当前bash环境下执行命令而运行脚本是启动一个子终端进程来执行其中的命令。这样如果把设置环境变量的命令写进.bashrc脚本文件中就只会影响子进程无法改变当前的bash环境。所以通过.bashrc脚本文件设置环境变量时需要source命令。
[第十四节课]
Q为什么C语言中为什么要有流程控制
A因为程序不能一直顺序执行如果没有分支和循环这是程序的三大流程结构。也正因如此我们才能实现各种算法你可以再想想图灵机就能明白了。
[第十五节课]
Q请问C语言函数如何传递结构体类型的参数呢
A如果结构体有多于8个成员的情况下前8个成员会被放在寄存器中剩下部分被存放在栈上sp指向第一个没有被存放在寄存器上的结构体成员。结构体中如果第i个成员是整型类型那么就存放在整型寄存器a(i)上如果第i个成员是浮点数类型那么就存放在浮点寄存器fa(i)上0<=i<=7
[第十六节课]
Q请写出机器码0x00000033对应的指令。
A0x00000033对应的指令是add x0x0x0
[第十七节课]
Q为什么指令编码中目标寄存器源寄存器1源寄存器2占用的位宽都是5位呢
A因为5位二进制数据就是2的5次方所能表示的编码范围是0~31正好索引RISC-V的32个通用寄存器。
[第十八节课]
Q既然已经有jal指令了为什么还需要jalr指令呢
A因为jal只能通过立即数传递跳转地址只能跳转±2k的地址空间如果想要跳转到更远的地址就得通过寄存器来传递跳转地址。
[第十九节课]
Q我们发现RISC-V指令集中没有大于指令和小于等于指令为什么呢
A因为实现大于指令和小于等于指令的功能只需要把小于指令和大于等于指令的两个操作数互换一下位置就行了。
[第二十节课]
Q请你尝试用LR、SC指令实现自旋锁。
A代码如下所示
/*********************************/
//lrsc.S
.text
.globl cas
#a0内存地址
#a1预期值
#a2所需值
#a0返回值如果成功则为0否则为1
cas:
lr.w t0, (a0) #加载以前的值
bne t0, a1, fail #不相等则跳转到fail
sc.w a0, a2, (a0) #尝试更新
jr ra #返回
fail:
li a0, 1 #a0 = 1
jr ra #返回
/*********************************/
//lock.c
//定义锁类型
typedef struct Lock
{
int LockVal; //锁值
}Lock;
//自旋锁初始化
void SpinLockInit(Lock* lock)
{
//锁值初始化为0
lock->LockVal = 0;
return;
}
//自旋锁加锁
void SpinLock(Lock* lock)
{
int status;
do
{
status = cas(&lock->LockVal, 0, 1); //加锁
}while(status); //循环加锁,直到成功
return;
}
//自旋锁解锁
void SpinUnLock(Lock* lock)
{
SpinLockInit(lock);//直接初始化 解锁
return;
[第二十一节课]
Q为什么加载字节与加载半字指令需要处理数据符号问题呢而加载字指令却不需要
A首先加载指令是从内存到寄存器。
其次加载到寄存器中的数据会参与运算,数据的运算就需要考虑数据的符号问题。
最后加载字指令是加载32位数据占用整个寄存器不需要处理符号位问题只需要原样加载内存中的数据就行了内存中的数据有符号就有符号没有符号那就是没有符号。
[第二十二节课]
Q为什么三条储存指令不需要处理数据符号问题呢
A首先储存指令是把寄存器中的数据储存到内存其次储存到内存中的数据不参与运算时不需要考虑符号问题。只需要原样保存在内存中就行了。