├── .gitignore ├── README.md ├── assignment_ch1 └── main.md ├── assignment_ch10 ├── 3-2.jpg └── main.md ├── assignment_ch11 └── main.md ├── assignment_ch12 └── main.md ├── assignment_ch2 ├── main.md └── 图片1.png ├── assignment_ch3 ├── TLB.c └── main.md ├── assignment_ch4 └── main.md ├── assignment_ch5 ├── main.md ├── skylake_block_diagram.svg └── zen_block_diagram.svg ├── assignment_ch6 ├── APB_GPIO.v ├── inside_computer.jpg ├── main.md └── 图片1.jpg ├── assignment_ch7 └── main.md ├── assignment_ch8 ├── main.md ├── 图片2.png └── 图片3.png └── assignment_ch9 ├── main.md ├── 图片1-1.png ├── 图片1-2.png ├── 图片1.png ├── 图片2-1.png ├── 图片2.png ├── 图片3-1.png ├── 图片3-2.png ├── 图片3-3.png ├── 图片3.png ├── 图片4-1.png ├── 图片4-2.png ├── 图片4-3.png ├── 图片4.png ├── 图片5.png └── 图片6.png /.gitignore: -------------------------------------------------------------------------------- 1 | slides/ 2 | 3 | *.pptx 4 | *.docx 5 | 6 | *.pdf 7 | *.html -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 习题解答 2 | 3 | > For UCAS 2020 Autumn 4 | 5 | ## List 6 | - [x] [第 1 章 引言](assignment_ch1/main.md) 7 | - [x] [第 2 章 指令系统](assignment_ch2/main.md) 8 | - [x] [第 3 章 特权指令系统](assignment_ch3/main.md) 9 | - [x] [第 4 章 软硬件协同](assignment_ch4/main.md) 10 | - [x] [第 5 章 计算机组成原理和结构](assignment_ch5/main.md) 11 | - [x] [第 6 章 计算机总线接口技术](assignment_ch6/main.md) 12 | - [x] [第 7 章 计算机系统启动过程分析](assignment_ch7/main.md) 13 | - [x] [第 8 章 运算器设计](assignment_ch8/main.md) 14 | - [x] [第 9 章 指令流水线](assignment_ch9/main.md) 15 | - [x] [第 10 章 并行编程基础](assignment_ch10/main.md) 16 | - [x] [第 11 章 多核处理结构](assignment_ch11/main.md) 17 | - [x] [第 12 章 计算机系统评价和性能分析](assignment_ch12/main.md) 18 | 19 | 20 | ## Note 21 | 仅供学习参考,不保证正确性。请勿用于不良用途。 22 | -------------------------------------------------------------------------------- /assignment_ch1/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 1 章作业 2 | 3 | ## 1.1 4 | 计算机系统可划分为哪几个层次,各层次之间的界面是什么?你认为这样划分层次的意义何在? 5 | 6 | **解** 7 | 8 | 计算机系统可划分为四个层次:应用程序、操作系统、硬件系统、晶体管。应用程序与操作系统之间的界面是应用程序编程接口 API,操作系统与硬件系统之间的界面是指令系统 ISA,硬件系统与晶体管之间的界面是工艺模型。 9 | 10 | 这样划分层次,通过抽象的方式降低了上层用户操作计算机的复杂度,通过统一界面的方式提升了各个层次的可移植性和通用性。各个层次之间,在满足界面要求的情况下可以独立发展,促进了计算机的发展。 11 | 12 | ## 1.2 13 | 在三台不同指令系统的计算机上运行同一程序 P 时,A 机器需要执行 $1.0 \times 10^9$ 条指令,B 机器需要执行 $2.0 \times 10^9$ 条指令,C 机器需要执行 $3.0 \times 10^9$,但三台机器的实际执行时间都是 $100$ 秒。请分别计算出这三台机器的 MIPS,并指出运行程序 P 时哪台机器的性能最高。 14 | 15 | **解** 16 | 17 | A 机器的 MIPS 是 $1.0 \times 10^9 \div 100 \div 10^6 = 10$; 18 | B 机器的 MIPS 是 $2.0 \times 10^9 \div 100 \div 10^6 = 20$; 19 | C 机器的 MIPS 是 $3.0 \times 10^9 \div 100 \div 10^6 = 30$。 20 | 21 | 三者运行同一程序 P 时,花费的时间相同,因此性能相当。 22 | 23 | ## 1.3 24 | 假设某程序中可向量化的百分比为 $P$,现在给处理器中增加向量部件以提升性能,向量部件的加速比是 $S$。请问增加向量部件后,处理器运行该程序的性能提升幅度是多少? 25 | 26 | **解** 27 | 设原处理器执行这一程序需要 $t$ 秒,则可向量化的部分需要 $tP$ 秒,其余部分需要 $t - tP$ 秒。 28 | 29 | 增加向量部件后,可向量化的部分仅需 $tP / S$ 秒,总运行时间为 $t - tP + tP/S$,其时间消耗是原来的 $(1 - P + P/S)$ 倍。 30 | 31 | 性能提升幅度为:$\displaystyle 1 / (1 - P + P/S) - 1 = \frac{PS - P}{S - PS + P}$ 32 | 33 | ## 1.4 34 | 处理器的功耗可简单分为静态功耗和动态功耗两部分,其中静态功耗的特性满足欧姆定律,动态功耗在其他条件相同的情况下与频率成正比。现对某处理器进行功耗测试,得到如下数据:关闭时钟,电压 $1.0 \text{V}$ 时,电流为 $100 \text{mA}$;时钟频率为 $1 \text{GHz}$,电压 $1.1 \text{V}$ 时,电流为 $2100 \text{mA}$。请计算此处理器在时钟频率为 $2 \text{GHz}$、电压为 $1.1 \text{V}$ 时的总功耗。 35 | 36 | **解** 37 | 38 | 电压为 $1.1 \text{V}$ 时,处理器静态功耗对应的电流为: 39 | $$ 40 | I_{\text{静态}2} = \frac{100 \text{mA}}{1.0 \text{V}}\times 1.1 \text{V} = 110 \text{mA} 41 | $$ 42 | 43 | 时钟频率为 $1 \text{GHz}$,电压 $1.1 \text{V}$ 时,处理器动态功耗对应的电流为: 44 | $$ 45 | I_{\text{动态}2} = I_2 - I_{\text{静态}2} = 1990 \text{mA} 46 | $$ 47 | 48 | 由于动态功耗在其他条件相同的情况下与频率成正比,则时钟频率为 $2 \text{GHz}$、电压为 $1.1 \text{V}$ 时,处理器动态功耗对应的电流为: 49 | $$ 50 | I_{\text{动态}3} = \frac{2 \text{GHz}}{1 \text{GHz}} \times 1990 \text{mA} = 3980 \text{mA} 51 | $$ 52 | 53 | 此时总电流为: 54 | $$ 55 | I_3 = I_{\text{动态}3} +I_{\text{静态}3} = I_{\text{动态}3} +I_{\text{静态}2} = 4090 \text{mA} 56 | $$ 57 | 58 | 故此处理器在时钟频率为 $2 \text{GHz}$、电压为 $1.1 \text{V}$ 时的总功耗为: 59 | $$ 60 | P_3 = U_3 \times I_3 = 4499 \text{mW} = 4.499 \text{W} 61 | $$ 62 | 63 | ## 1.5 64 | 在一台个人计算机上进行 SPEC CPU2000 的测试,分别给出无编译优化选项和编译优化选项为 `-O2` 的测试报告。 65 | 66 | **解** 67 | 68 | |SPEC 程序|`-O0` 运行时间 / 秒|`-O0` 分值|`-O2` 运行时间 / 秒|`-O2` 分值| 69 | |:-|:-:|:-:|:-:|:-:| 70 | |164.gzip|76.5|1830|121|1161| 71 | |175.vpr|55.3|2530|101|1380| 72 | |176.gcc|27.9|3938|X|X| 73 | |181.mcf|72.4|2488|90.1|1997| 74 | |186.crafty|28.4|3516|41.1|2430| 75 | |197.parser|93|1935|155|1160| 76 | |252.eon|X|X|232|560| 77 | |253.perlbmk|X|X|72.1|2496| 78 | |254.gap|31.6|3476|31.1|3538| 79 | |255.vortex|46.6|4079|85.3|2227| 80 | |256.bzip2|60.3|2486|129|1166| 81 | |300.twolf|83.6|3587|150|1998| 82 | |SPEC_INT2000||2878 ||1640 | 83 | |168.wupwise|X|X|104|1535| 84 | |171.swim|X|X|164|1886| 85 | |172.mgrid|X|X|334|539| 86 | |173.applu|X|X|286|734| 87 | |177.mesa|33.8|4143|68.3|2051| 88 | |178.galgel|X|X|X|X| 89 | |179.art|23.3|11148|51.2|5078| 90 | |183.equake|X|X|X|X| 91 | |187.facerec|36.7|5176|76.2|2493| 92 | |188.ammp|X|X|173|1273| 93 | |189.lucas|X|X|69|2899| 94 | |191.fma3d|X|X|124|1687| 95 | |200.sixtrack|X|X|257|429| 96 | |301.apsi|54.8|4746|200|1297| 97 | |SPEC_INT2000||5804 ||1471 | 98 | 99 | 100 | 根据分数可以看出,使用 `-O2` 优化后,SPEC CPU2000 的评分大约是无编译优化时 2 倍。但优化造成了大量的测试点运行结果出现偏差,对性能提升可能有副作用。 101 | 102 | ## 1.6 103 | 分别在苹果手机、华为手机以及 X86-Windows 机器上测试浏览器 Octane 的分值,并简单评述。 104 | 105 | **解** 106 | | 手机类型 | 型号 | 处理器 | 得分 | 备注 | 107 | | :---------: | :--------------------: | :---------------------: | :---: | :------------------------ | 108 | | 苹果手机 | iPhone X | A11 Bionic | 34089 | 结果来自于李国峰同学。 | 109 | | 华为手机 | HUAWEI P30 Pro | HUAWEI Kirin 980 | 18402 | 结果来自于钱瑾珈同学。 | 110 | | 小米手机 | Xiaomi 10 | Qualcomm Snapdragon 865 | 19528 | 自测。 | 111 | | X86-Windows | ThinkPad X1 Carbon 6th | Intel Core i5-8350U | 36192 | 自测,使用 Chrome 浏览器 | 112 | | X86-Windows | ThinkPad X1 Carbon 6th | Intel Core i5-8350U | 30820 | 自测,使用 Firefox 浏览器 | 113 | 114 | 可以注意到,华为和小米两台手机的得分相差不大,而苹果手机的得分远高于华为和小米。尽管他们都是用的是 ARM 架构的处理器,但处理器的设计水平可能有相当大差异。此外,iOS 与 Android 的系统平台不同,也可能会影响到得分。 115 | 116 | 苹果手机的测试得分几乎与 X86 机器相同,足以说明苹果的芯片、系统效率非常高。对比来看,在同一机器上使用 Firefox 和 Chrome 导致了 6000 多分的差异,说明浏览器对 JavaScript 的实现对性能也有较大的影响,Chrome 的 JavaScript 引擎要优于 Firefox。 -------------------------------------------------------------------------------- /assignment_ch10/3-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch10/3-2.jpg -------------------------------------------------------------------------------- /assignment_ch10/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 10 章作业 2 | 3 | ## 10.1 4 | 请介绍 MPI 中阻塞发送 `MPI_Send` / 阻塞接收 `MPI_Recv` 与非阻塞发送 `MPI_Isend` / 非阻塞接收 `MPI_Irecv` 的区别。 5 | 6 | **解** 7 | 8 | * 对于阻塞发送 `MPI_Send` / 阻塞接收 `MPI_Recv`,其在发送、接收时会将当前程序阻塞,直到发送、接收成功接口函数才会返回; 9 | * 对于非阻塞发送 `MPI_Isend` / 非阻塞接收 `MPI_Irecv`,其在发送、接收时并不会阻塞当前程序,只要通信启动接口函数就会返回,程序需要调用其他的接口函数来查询非阻塞通信是否完成,例如 `MPI_Test`。 10 | 11 | ## 10.2 12 | 请介绍什么是归约(Reduce)操作,MPI 和 OpenMP 中分别采用何种函数或者子句来实现规约操作。 13 | 14 | **解** 15 | 16 | 归约,指将一组数据通过某一个函数(操作)缩减到一个(或一小组)数据。常用的操作包含求和、求最大、求最小等。 17 | 18 | * MPI 中通过 `MPI_Reduce` 函数来实现归约操作; 19 | * OpenMP 中通过 `reduction` 子句来实现归约操作。 20 | 21 | ## 10.3 22 | 请介绍什么是栅障(Barrier)操作,MPI 和 OpenMP 中分别采用何种函数或者命令来实现栅障。 23 | 24 | **解** 25 | 26 | 栅障(屏障)操作,是一种进程同步操作。屏障会阻塞到达屏障的进程,直到所有进程都到达屏障。 27 | 28 | * MPI 中通过 `MPI_Barrier` 函数来实现栅障; 29 | * OpenMP 中通过 `barrier` 编译制导语句来实现栅障。 30 | 31 | ## 10.4 32 | 下面的 MPI 程序片段是否正确?请说明理由。假定只有 2 个进程正在运行且 `mypid` 为每个进程的进程号。 33 | ```c 34 | if (mypid == 0) { 35 | MPI_Bcast(buf0, count, type, 0, comm, ierr); 36 | MPI_Send(buf1, count, type, 1, comm, ierr); 37 | } else { 38 | MPI_Recv(buf1, count, type, 0, comm, ierr); 39 | MPI_Bcast(buf0, count, type, 0, comm, ierr); 40 | } 41 | ``` 42 | 43 | **解** 44 | 45 | 该 MPI 程序片段不正确,会造成死锁: 46 | * 0 号进程的第 1 行进行了 `MPI_Bcast` 的集体通信操作,这会将它阻塞,直到所有的进程都完成了 `MPI_Bcast` 操作。那么,只有 1 号进程完成了它的第 2 行,0 号进程才能继续进行。 47 | * 1 号进程的第 1 行进行了 `MPI_Recv` 的从 0 到 1 的点对点通信操作,这会将它阻塞,直到 0 号进程完成了 `MPI_Send` 操作。那么,只有 0 号进程完成了它的第 2 行,1 号进程才能继续进行。 48 | * 现在,0、1 两个进程都被阻塞在了第 1 行,不可能执行第 2 行。这形成了死锁。 49 | 50 | ## 10.5 51 | 矩阵乘是数值计算中的重要运算。假设有一个 $m \times p$ 的矩阵 $\mathbf{A}$,还有一个 $p \times n$ 的矩阵 $\mathbf{B}$。令 $\mathbf{C}$ 为矩阵 $\mathbf{A}$ 和 $\mathbf{B}$ 的乘积,即 $\mathbf{C} = \mathbf{A}\mathbf{B}$。表示矩阵在 $(i, j)$ 位置处的值,则 $0 \leq i \leq m - 1$,$0 \leq j \leq n - 1$。请采用 OpenMP,将矩阵 $\mathbf{C}$ 的计算并行化。假设矩阵在存储器中按行存放。 52 | 53 | **解** 54 | 下面的做法仅将最外层循环并行化: 55 | ```c 56 | #include 57 | #include 58 | #include 59 | 60 | #define MM 123 61 | #define PP 231 62 | #define NN 312 63 | 64 | int matrix_A[MM][PP]; 65 | int matrix_B[PP][NN]; 66 | int matrix_C[MM][NN]; 67 | 68 | int main() { 69 | init_matrix_A(); 70 | init_matrix_B(); 71 | memset(matrix_C, 0, sizeof(matrix_C)); 72 | 73 | matrix_mult(); 74 | } 75 | 76 | void matrix_mult() { 77 | #pragma omp parallel for 78 | for (int i = 0; i < MM; i++) { 79 | for (int j = 0; j < NN; j++) { 80 | for (int k = 0; k < PP; k++) { 81 | matrix_C[i][j] += matrix_A[i][k] * matrix_B[k][j]; 82 | } 83 | } 84 | } 85 | } 86 | ``` 87 | 下面的做法将最外两层循环都并行化: 88 | ```c 89 | #include 90 | #include 91 | #include 92 | 93 | #define MM 123 94 | #define PP 231 95 | #define NN 312 96 | 97 | int matrix_A[MM][PP]; 98 | int matrix_B[PP][NN]; 99 | int matrix_C[MM][NN]; 100 | 101 | int main() { 102 | init_matrix_A(); 103 | init_matrix_B(); 104 | memset(matrix_C, 0, sizeof(matrix_C)); 105 | 106 | matrix_mult(); 107 | } 108 | 109 | void matrix_mult() { 110 | #pragma omp parallel 111 | { 112 | #pragma omp single 113 | for (int i = 0; i < MM; i++) { 114 | for (int j = 0; j < NN; j++) { 115 | #pragma omp task 116 | for (int k = 0; k < PP; k++) { 117 | matrix_C[i][j] += matrix_A[i][k] * matrix_B[k][j]; 118 | } 119 | } 120 | } 121 | } 122 | } 123 | ``` 124 | 125 | ## 10.6 126 | 请采用 MPI 将上题中矩阵 $\mathbf{C}$ 的计算并行化,并比较 OpenMP 与 MPI 并行程序的特点。 127 | 128 | **解** 129 | ```c 130 | #include 131 | #include 132 | 133 | #define MM 123 134 | #define PP 231 135 | #define NN 312 136 | 137 | int matrix_A[MM][PP]; 138 | int matrix_B[PP][NN]; 139 | int matrix_C[MM][NN]; 140 | 141 | int main(int argc, char ** argv) { 142 | int proc_id, num_proc, line; 143 | MPI_Status status; 144 | 145 | MPI_Init(&argc, &argv); 146 | MPI_Comm_rank(MPI_COMM_WORLD, &proc_id); 147 | MPI_Comm_size(MPI_COMM_WORLD, &num_proc); 148 | 149 | line = MM / num_proc; 150 | memset(matrix_C, 0, sizeof(matrix_C)); 151 | int * A = (void *) matrix_A; 152 | int * B = (void *) matrix_B; 153 | int * C = (void *) matrix_C; 154 | 155 | if (proc_id == 0) { 156 | init_matrix_A(); 157 | init_matrix_B(); 158 | 159 | for (int i = 1; i < num_proc; i++) { 160 | MPI_Send(B, PP * NN, MPI_INT, i, 0, MPI_COMM_WORLD); 161 | MPI_Send(A + (i - 1) * line * PP, line * PP, MPI_INT, i, 1, 162 | MPI_COMM_WORLD); 163 | } 164 | for (int i = 1; i < num_proc; i++) { 165 | MPI_Recv(C + (i - 1) * line * NN, line * NN, MPI_INT, i, 2, 166 | MPI_COMM_WORLD, &status); 167 | } 168 | for (int i = (num_proc - 1) * line; i < MM; i++) { 169 | for (int j = 0; j < NN; j++) { 170 | for (int k = 0; k < PP; k++) { 171 | matrix_C[i][j] += matrix_A[i][k] * matrix_B[k][j]; 172 | } 173 | } 174 | } 175 | } else { 176 | MPI_Recv(B, PP * NN, MPI_INT, 0, 0, MPI_COMM_WORLD, &status); 177 | MPI_Recv(A + (proc_id - 1) * line * PP, line * PP, MPI_INT, 0, 1, 178 | MPI_COMM_WORLD, &status); 179 | for (int i = (proc_id - 1) * line; i < proc_id * line; i++) { 180 | for (int j = 0; j < NN; j++) { 181 | for (int k = 0; k < PP; k++) { 182 | matrix_C[i][j] += matrix_A[i][k] * matrix_B[k][j]; 183 | } 184 | } 185 | } 186 | MPI_Send(C + (proc_id - 1) * line * NN, line * NN, MPI_INT, 0, 2, 187 | MPI_COMM_WORLD); 188 | } 189 | MPI_Finalize(); 190 | return 0; 191 | } 192 | ``` 193 | 194 | 比较 OpenMP 和 MPI 的程序我们可以发现: 195 | * OpenMP 是建立在线程基础上的并行,不同线程之间可以方便的共享一部分内存;MPI 是建立在进程基础上的并行,不同进程之间的数据共享必须通过 MPI 接口函数来实现。 196 | * OpenMP 的编译制导语句类似于宏,基于 OpenMP 的程序可以在完全忽略这些制导语句的情况下正常运行;MPI 的接口均为函数,基于 MPI 的程序只适用于并行运行。 197 | * OpenMP 可以方便的利用制导语句将循环并行化,基本不需要程序员手动分配任务;MPI 相对要费劲很多,必须由程序员手动为每个进程分配任务。 198 | 199 | ## 10.7 200 | 分析一款 GPU 的存储层次。 201 | 202 | **解** 203 | 204 | 下图是 NVIDIA Fermi 架构 GPU 的存储层次图。 205 | 206 | 207 | 208 | * 每个 SM(流式多处理器,Streaming Multiprocessors)中,包含一个巨大的寄存器堆,大小为 128 KB。每个 SM 中又包含 32 个核心(Core)。 209 | * 每个 SM 中,还包含 L1 缓存以及 SMEM(共享内存,Shared Memory)。它们的大小总共为 64 KB(48 KB Shared / 16 KB L1,或者 16 KB Shared / 48 KB L1)。 210 | * 所有 SM 共用 L2 缓存,大小为 768 KB。 211 | * CPU 和 GPU 同时可访问主存储体,大小最大为 6 GB。 212 | -------------------------------------------------------------------------------- /assignment_ch11/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 11 章作业 2 | 3 | ## 11.1 4 | 关于多核处理器的 Cache 结构,请介绍 UCA 与 NUCA 的特点。 5 | 6 | **解** 7 | 8 | * UCA 是一种集中式共享结构,处理器核通过总线、交叉开关连接 LLC(Last Level Cache)。UCA 中,所有处理器核对 LLC 的访问延迟相同,常用于核数较少的多核处理器。UCA 结构的集中式 Cache 的可扩展性受到总线、交叉开关的限制,容易在处理器核数量增加时成为性能瓶颈。 9 | * NUCA 是一种分布式共享结构,每个处理器核拥有本地的 LLC,并通过片上互连访问其他处理器核的 LLC。NUCA 中吗,处理器核对不同位置的 LLC 访问延迟不同,常用于较多核数的多核、众核处理器。NUCA 结构需要高校的 Cache 查找和替换算法,以提升性能。NUCA 结构通常采用可扩展性的片上互连,采用基于目录的 Cache 一致性协议,具有良好的扩展性。 10 | 11 | ## 11.2 12 | 有两个并行执行的线程,在顺序一致性和弱一致性下,它各有几种正确的执行顺序?给出执行次序和最后的正确结果(假设 `X`、`Y` 的初始值均为 0。 13 | ``` 14 | P1 P2 15 | X = 1; Y = 1; 16 | print Y; print X; 17 | ``` 18 | 19 | **解** 20 | 21 | 顺序一致性的正确执行次序有下面 6 种: 22 | ``` 23 | 1: 2: 3: 24 | X = 1; X = 1; X = 1; 25 | Print Y; Y = 1; Y = 1; 26 | Y = 1; print Y; print X; 27 | Print X; print X; print Y; 28 | R: X = 1, Y = 0 R: X = 1, Y = 1 R: X = 1, Y = 1 29 | 30 | 4: 5: 6: 31 | Y = 1; Y = 1; Y = 1; 32 | X = 1; X = 1; print X; 33 | print Y; print X; X = 1; 34 | print X; print Y; print Y; 35 | R: X = 1, Y = 1 R: X = 1, Y = 1 R: X = 0, Y = 1 36 | ``` 37 | 38 | 对于弱一致性: 39 | * 如果认为 `print X;` 和 `print Y;` 具有同步操作的特点,那么顺序一致性的 2、3、4、5 是可能的正确执行次序。 40 | * 如果认为程序中没有同步,那么上述 6 种结果都有可能。 41 | 42 | ## 11.3 43 | 关于 Cache 一致性协议,MESI 协议比 ESI 协议增加了 M 状态,请解释有什么好处。 44 | 45 | **解** 46 | M 即 Modified,表示该 Cache 行被当前处理器核独占且修改了。同时,E(Exclusive,独占)状态表示该 Cache 行被当前处理器独占且没有修改。 47 | 48 | 可以看出,MESI 协议中的 M 状态是 ESI 协议中 E 状态的子集,使得没有被修改的 E 状态 Cache 行在替换时不再需要写回内存,减少了 Cache 到内存的数据传输次数。 49 | 50 | ## 11.4 51 | 请分别采用 `Fetch_and_Increment` 和 `Compare_and_Swap` 原子指令编写实现自旋锁的代码,并分析可能的性能改进措施。 52 | 53 | **解** 54 | 使用 `Fetch_and_Increment`: 55 | ```c 56 | typedef struct spinlock { 57 | int status; 58 | } spinlock_t; 59 | 60 | void acquire_spinlock1(spinlock * lock) { 61 | while (Fetch_and_Increment(lock->status)); 62 | } 63 | 64 | void release_spinlock1(spinlock * lock) { 65 | lock->status = 0; 66 | } 67 | 68 | void do_something() { 69 | spinlock_t lock; 70 | acquire_spinlock1(&lock); 71 | // critical_section 72 | release_spinlock1(&lock); 73 | } 74 | ``` 75 | 76 | 使用 `Compare_and_Swap`: 77 | ```c 78 | typedef struct spinlock { 79 | int status; 80 | } spinlock_t; 81 | 82 | void acquire_spinlock2(spinlock * lock) { 83 | int not_success = 1; 84 | while (not_success) { 85 | Compare_and_Swap(&lock->status, 0, ¬_success); 86 | } 87 | } 88 | 89 | void release_spinlock2(spinlock * lock) { 90 | lock->status = 0; 91 | } 92 | 93 | void do_something() { 94 | spinlock_t lock; 95 | acquire_spinlock2(&lock); 96 | // critical_section 97 | release_spinlock2(&lock); 98 | } 99 | ``` 100 | 101 | 自旋锁对锁变量会出现访存冲突,一个核获得锁后,其他处理器会不断的访问锁变量,形成大量的访存通信。可以在自旋过程中添加延迟以减轻访存压力,也可以通过实现互斥锁等锁结构来优化。 102 | 103 | ## 11.5 104 | 在共享存储的多处理器中,经常会出现假共享现象。假共享是由于两个变量处于同一个 Cache 行中引起的,会对性能造成损失。为了尽量减少假共享的发生,程序员在写程序时应该注意什么? 105 | 106 | **解** 107 | 108 | * 在编写程序时,避免使多个处理器、进程、线程同时访问全局或动态分配的相邻数据结构,例如同时访问一个全局结构体的变量 A 和 B; 109 | * 使用编译指令强制对齐单个变量、填充数据结构使之与 Cache 行对齐,从而避免引发假共享的两个变量处于同一个 Cache 行; 110 | * 将全局数据复制到本地副本后再进行操作,以避免对全局数据的频繁访问; 111 | * 测试时利用 CPU 厂商提供的实用程序进行监测。 112 | ## 11.6 113 | 请介绍片上网络路由器设计中的虚通道概念,并说明采用虚通道有什么好处。 114 | 115 | **解** 116 | 117 | 虚通道是分时复用物理通道的一种表示,输入单元包含能缓存数个 flit 及其状态信息的缓存,相当于多个数据传输通路。 118 | 119 | 使用虚通道能够分时复用物理通道,节约了片上资源。 120 | 121 | ## 11.7 122 | 分析 Fermi GPU 的存储结构,指出不同层次存储结构的带宽、延迟,以及是否共享。 123 | 124 | **解** 125 | 126 | |存储结构|位置|容量|带宽|延迟|共享|备注| 127 | |:-:|:-:|:-:|:-:|:-:|:-:|:-| 128 | |SM 寄存器堆|SM 内部|128 KB|8000 GB/s|1 cycle|否 129 | |共享存储|SM 内部|16 KB / 48 KB|1000 GB/s|20-30 cycles|是|与 L1 Cache 总计 64 KB 每 SM| 130 | |L1 Cache |SM 内部|16 KB / 48 KB|1000 GB/s|20-30 cycles|否|与共享存储总计 64 KB 每 SM| 131 | |L2 Cache |GPU|768 KB|-|-|是|未找到带宽、延迟的数据| 132 | |主存储|DRAM|最大 6GB|177 GB/s| 400-800 cycles|是|GDDR5,与 CPU 共享| 133 | 134 | 138 | -------------------------------------------------------------------------------- /assignment_ch12/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 12 章作业 2 | 3 | ## 12.1 4 | 写两个简单的测试程序,用于测量一台计算机系统最大的 MIPS 和最大的 MFLOPS 的值。 5 | 6 | **解** 7 | 8 | 1. 用于测量 MIPS 的 C 语言程序:(计算斐波那契数列) 9 | ```c 10 | #include 11 | #define FIB_MAX 100000000 12 | #define LOOP_MAX 100 13 | 14 | int T = LOOP_MAX; 15 | long a, b, c; 16 | 17 | int main() { 18 | while (T--) { 19 | a = 0; 20 | b = 1; 21 | for (int i = 0; i < FIB_MAX; i++) { 22 | c = a + b; 23 | a = b; 24 | b = c; 25 | } 26 | } 27 | return 0; 28 | } 29 | ``` 30 | 31 | 其运行结果为 32 | ```shell 33 | $ gcc -O0 Fibonacci.c 34 | $ time ./a.out 35 | 36 | real 0m27.919s 37 | user 0m27.919s 38 | sys 0m0.000s 39 | ``` 40 | 41 | 通过 `objdump` 工具进行反汇编,得到其反汇编代码: 42 | ``` 43 | 0000000000001129
: 44 | 1129: f3 0f 1e fa endbr64 45 | 112d: 55 push %rbp 46 | 112e: 48 89 e5 mov %rsp,%rbp 47 | 1131: eb 60 jmp 1193 48 | 1133: 48 c7 05 f2 2e 00 00 movq $0x0,0x2ef2(%rip) # 4030 49 | 113a: 00 00 00 00 50 | 113e: 48 c7 05 d7 2e 00 00 movq $0x1,0x2ed7(%rip) # 4020 51 | 1145: 01 00 00 00 52 | 1149: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp) 53 | 1150: eb 38 jmp 118a 54 | 1152: 48 8b 15 d7 2e 00 00 mov 0x2ed7(%rip),%rdx # 4030 55 | 1159: 48 8b 05 c0 2e 00 00 mov 0x2ec0(%rip),%rax # 4020 56 | 1160: 48 01 d0 add %rdx,%rax 57 | 1163: 48 89 05 be 2e 00 00 mov %rax,0x2ebe(%rip) # 4028 58 | 116a: 48 8b 05 af 2e 00 00 mov 0x2eaf(%rip),%rax # 4020 59 | 1171: 48 89 05 b8 2e 00 00 mov %rax,0x2eb8(%rip) # 4030 60 | 1178: 48 8b 05 a9 2e 00 00 mov 0x2ea9(%rip),%rax # 4028 61 | 117f: 48 89 05 9a 2e 00 00 mov %rax,0x2e9a(%rip) # 4020 62 | 1186: 83 45 fc 01 addl $0x1,-0x4(%rbp) 63 | 118a: 81 7d fc ff e0 f5 05 cmpl $0x5f5e0ff,-0x4(%rbp) 64 | 1191: 7e bf jle 1152 65 | 1193: 8b 05 77 2e 00 00 mov 0x2e77(%rip),%eax # 4010 66 | 1199: 8d 50 ff lea -0x1(%rax),%edx 67 | 119c: 89 15 6e 2e 00 00 mov %edx,0x2e6e(%rip) # 4010 68 | 11a2: 85 c0 test %eax,%eax 69 | 11a4: 75 8d jne 1133 70 | 11a6: b8 00 00 00 00 mov $0x0,%eax 71 | 11ab: 5d pop %rbp 72 | 11ac: c3 retq 73 | 11ad: 0f 1f 00 nopl (%rax) 74 | ``` 75 | 76 | 分析反汇编代码,估算出其执行的代码条数为 5 + 100 × (4 + 2 + 108 × (9 + 2) + 5) = 1.1 × 1011 77 | 78 | 由此计算得到 MIPS 约为 3940。通过 7-Zip 的基准测试得到的 MIPS 值约为 3200,差距在可接受范围内。 79 | 80 | 2. 用于测量 MFLOPS 的 C 语言程序:(牛顿迭代法求 2 的平方根) 81 | ```c 82 | #include 83 | #define NEW_MAX 100000000 84 | #define LOOP_MAX 50 85 | 86 | int T = LOOP_MAX; 87 | double ans; 88 | int main() { 89 | while (T--) { 90 | ans = 4.0; 91 | for (int i = 0; i < NEW_MAX; i++) { 92 | ans = (ans + 2.0 / ans) * 0.5; 93 | } 94 | } 95 | return 0; 96 | } 97 | ``` 98 | 99 | 其运行结果为 100 | ```shell 101 | $ gcc -O0 Newton.c 102 | $ time ./a.out 103 | 104 | real 0m42.531s 105 | user 0m42.530s 106 | sys 0m0.000s 107 | ``` 108 | 109 | 分析程序,估算出其进行的浮点操作数为 1.5 × 1010。 110 | 111 | 由此计算得到 MFLOPS 约为 352.7。 112 | 113 | 114 | ## 12.2 115 | 阅读和分析 STREAM v1 基准测试程序: 116 | 1. 测出一台计算机上的测试结果并给出分析报告。 117 | 2. 调节处理器的频率,看内存的带宽和频率的关系。 118 | 3. 修改 STREAM 测试程序,看单精度带宽和双精度带宽的差别。 119 | 120 | **解** 121 | 1. 测试结果如下: 122 | ```shell 123 | $ gcc -O stream.c -o stream 124 | $ ./stream 125 | ------------------------------------------------------------- 126 | STREAM version $Revision: 5.10 $ 127 | ------------------------------------------------------------- 128 | This system uses 8 bytes per array element. 129 | ------------------------------------------------------------- 130 | Array size = 10000000 (elements), Offset = 0 (elements) 131 | Memory per array = 76.3 MiB (= 0.1 GiB). 132 | Total memory required = 228.9 MiB (= 0.2 GiB). 133 | Each kernel will be executed 10 times. 134 | The *best* time for each kernel (excluding the first iteration) 135 | will be used to compute the reported bandwidth. 136 | ------------------------------------------------------------- 137 | Your clock granularity/precision appears to be 1 microseconds. 138 | Each test below will take on the order of 9442 microseconds. 139 | (= 9442 clock ticks) 140 | Increase the size of the arrays if this shows that 141 | you are not getting at least 20 clock ticks per test. 142 | ------------------------------------------------------------- 143 | WARNING -- The above is only a rough guideline. 144 | For best results, please be sure you know the 145 | precision of your system timer. 146 | ------------------------------------------------------------- 147 | Function Best Rate MB/s Avg time Min time Max time 148 | Copy: 15112.9 0.011500 0.010587 0.015825 149 | Scale: 13976.4 0.012203 0.011448 0.013891 150 | Add: 16304.4 0.015601 0.014720 0.017893 151 | Triad: 16248.1 0.015614 0.014771 0.017890 152 | ------------------------------------------------------------- 153 | Solution Validates: avg error less than 1.000000e-13 on all three arrays 154 | ------------------------------------------------------------- 155 | ``` 156 | 157 | 观察测试结果,可以发现 Add、Triad 操作的带宽最大,Copy 次之,Scale 最小。分析这四种操作的源代码: 158 | ```c 159 | c[j] = a[j]; // Copy 160 | b[j] = scalar*c[j]; // Scale 161 | c[j] = a[j]+b[j]; // Add 162 | a[j] = b[j]+scalar*c[j]; // Triad 163 | ``` 164 | 可以看出,单次 Copy、Scale 操作仅需 2 次访存,而单次 Add、Triad 操作需要3次访存。在单次操作内,访存次数越多,单次访存所均摊的其他操作(计算)时间越少,访存带宽越大,故而 Add、Triad 操作带宽大于 Copy 和 Scale;在单次操作内,其他操作(计算)越复杂,单次访存所均摊的其他操作时间越多,访存带宽越小,故而 Copy 带宽大于 Scale,Add 带宽大于 Triad。 165 | 166 | 2. 通过调整电源设置来调控 CPU 频率,依次进行测试,得到结果如下表: 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 |
电源设置CPU 频率Best Rate MB/s
CopyScaleAddTriad
最佳性能3.5 GHz15112.913976.416304.416248.1
更好的性能2.3 GHz11768.311382.912617.612583.9
节电模式1.0 GHz9193.48153.78998.29797.5
208 | 209 | 观察数据可以发现,CPU 频率与内存带宽正相关。 210 | 211 | 3. 将代码中的宏定义 `#define STREAM_TYPE float` 修改为 `#define STREAM_TYPE float`,重新编译测试,得到如下结果: 212 | ```shell 213 | $ gcc -O stream-float.c -o stream-float 214 | $ ./stream-float 215 | ------------------------------------------------------------- 216 | STREAM version $Revision: 5.10 $ 217 | ------------------------------------------------------------- 218 | This system uses 4 bytes per array element. 219 | ------------------------------------------------------------- 220 | Array size = 10000000 (elements), Offset = 0 (elements) 221 | Memory per array = 38.1 MiB (= 0.0 GiB). 222 | Total memory required = 114.4 MiB (= 0.1 GiB). 223 | Each kernel will be executed 10 times. 224 | The *best* time for each kernel (excluding the first iteration) 225 | will be used to compute the reported bandwidth. 226 | ------------------------------------------------------------- 227 | Your clock granularity/precision appears to be 1 microseconds. 228 | Each test below will take on the order of 4943 microseconds. 229 | (= 4943 clock ticks) 230 | Increase the size of the arrays if this shows that 231 | you are not getting at least 20 clock ticks per test. 232 | ------------------------------------------------------------- 233 | WARNING -- The above is only a rough guideline. 234 | For best results, please be sure you know the 235 | precision of your system timer. 236 | ------------------------------------------------------------- 237 | Function Best Rate MB/s Avg time Min time Max time 238 | Copy: 14492.5 0.005902 0.005520 0.007029 239 | Scale: 11889.0 0.006895 0.006729 0.007270 240 | Add: 15394.3 0.007995 0.007795 0.008764 241 | Triad: 15308.1 0.008098 0.007839 0.008688 242 | ------------------------------------------------------------- 243 | Solution Validates: avg error less than 1.000000e-06 on all three arrays 244 | ------------------------------------------------------------- 245 | ``` 246 | 观察数据可以发现,其访存带宽略小于采用双精度浮点数。 247 | 248 | 进一步测试发现,当关闭所有编译优化选项之后,单精度带宽约是双精度带宽的一半左右。 249 | 250 | 251 | > 参考文档:STREAM Benchmark Reference Information - http://www.cs.virginia.edu/stream/ref.html 252 | 253 | ## 12.3 254 | 分析 SPEC CPU2006 中 `462.libquantum` 程序,看它对处理器微结构的压力在哪里。查阅 `spec.org` 网站,看不同编译器对 `462.libquantum` 的分值的影响,猜测 Intel 编译器 `icc` 采用了什么编译技术使得其分值能达到上百分。 255 | 256 | **解** 257 | 258 | `libquantum` 模拟量子计算机的 C 语言库,其需要模拟大量量子比特的状态变化,这些过程在量子计算机上是并行的,但在 `libquantum` 中需要串行完成。 259 | 260 | 查看 `spec.org` 网站上的测试结果,使用 `icc` 的测试得分要比其他的高得多。根据 `462.libquantum` 的特点,`icc` 可能采用了将串行程序转换为并行的技术,具有高并行、高向量化的特点。 261 | 262 | ## 12.4 263 | 使用 `perf` 工具,测量各种排序算法如冒泡排序、希尔排序等算法的 IPC,分析排序算法对处理器的微结构的压力在哪里。 264 | 265 | **解** 266 | 267 | * 冒泡排序的 C 语言程序: 268 | ```c 269 | #include 270 | #define LENGTH 10 271 | int arr[LENGTH] = {10, 8, 6, 4, 2, 9, 7, 5, 3, 1}; 272 | 273 | void bubble_sort(int * arr, int len) { 274 | int tmp; 275 | for (int i = 0; i < len - 1; i++) { 276 | for (int j = 0; j < len - i - 1; j++) { 277 | if (arr[j] > arr[j + 1]) { 278 | tmp = arr[j]; 279 | arr[j] = arr[j + 1]; 280 | arr[j + 1] = tmp; 281 | } 282 | } 283 | } 284 | } 285 | 286 | int main() { 287 | for (int i = 0; i < LENGTH; i++) { 288 | printf("%d ", arr[i]); 289 | } 290 | printf("\n"); 291 | 292 | bubble_sort(arr, LENGTH); 293 | 294 | for (int i = 0; i < LENGTH; i++) { 295 | printf("%d ", arr[i]); 296 | } 297 | printf("\n"); 298 | 299 | return 0; 300 | } 301 | ``` 302 | 303 | 通过 `perf` 分析的结果如下: 304 | ```shell 305 | $ perf stat ./a.out 306 | 10 8 6 4 2 9 7 5 3 1 307 | 1 2 3 4 5 6 7 8 9 10 308 | 309 | Performance counter stats for './a.out': 310 | 311 | 0.48 msec task-clock:u # 0.615 CPUs utilized 312 | 0 context-switches:u # 0.000 K/sec 313 | 0 cpu-migrations:u # 0.000 K/sec 314 | 49 page-faults:u # 0.000 K/sec 315 | cycles:u 316 | instructions:u 317 | branches:u 318 | branch-misses:u 319 | 320 | 0.000776300 seconds time elapsed 321 | 322 | 0.000850000 seconds user 323 | 0.000000000 seconds sys 324 | ``` 325 | 326 | 327 | * 希尔排序的 C 语言程序: 328 | ```c 329 | #include 330 | #define LENGTH 10 331 | int arr[LENGTH] = {10, 8, 6, 4, 2, 9, 7, 5, 3, 1}; 332 | 333 | void shell_sort(int * arr, int len) { 334 | int tmp; 335 | 336 | for (int g = len / 2; g > 0; g /= 2) { 337 | for (int i = g; i < len ; i++) { 338 | int temp = arr[i]; 339 | int j = i - g; 340 | while (j >= 0 && arr[j] > temp) { 341 | arr[j + g] = arr[j]; 342 | j -= g; 343 | } 344 | arr[j + g] = temp; 345 | } 346 | } 347 | } 348 | 349 | int main() { 350 | for (int i = 0; i < LENGTH; i++) { 351 | printf("%d ", arr[i]); 352 | } 353 | printf("\n"); 354 | 355 | shell_sort(arr, LENGTH); 356 | 357 | for (int i = 0; i < LENGTH; i++) { 358 | printf("%d ", arr[i]); 359 | } 360 | printf("\n"); 361 | 362 | return 0; 363 | } 364 | ``` 365 | 366 | 通过 `perf` 分析的结果如下: 367 | ```shell 368 | $ perf stat ./a.out 369 | 10 8 6 4 2 9 7 5 3 1 370 | 1 2 3 4 5 6 7 8 9 10 371 | 372 | Performance counter stats for './a.out': 373 | 374 | 0.32 msec task-clock:u # 0.619 CPUs utilized 375 | 0 context-switches:u # 0.000 K/sec 376 | 0 cpu-migrations:u # 0.000 K/sec 377 | 51 page-faults:u # 0.000 K/sec 378 | cycles:u 379 | instructions:u 380 | branches:u 381 | branch-misses:u 382 | 383 | 0.000515300 seconds time elapsed 384 | 385 | 0.000587000 seconds user 386 | 0.000000000 seconds sys 387 | ``` 388 | 389 | 由于我没有安装在实体机器上的 Linux 操作系统,我只能在虚拟机(WSL2)中进行测试。但 WSL2 目前还不支持硬件性能计数器,导致无法获取到实际的 IPC。 390 | 391 | ## 12.5 392 | 使用 `gprof` 工具,获得 `linpack` 程序的热点函数。 393 | 394 | **解** 395 | 经过几轮尝试,没能成功安装 `linpack`,被卡在编译 GotoBLAS 的步骤…… 396 | 397 | 参照其他同学的结果,`linpack` 中的热点函数是 `daxpy`。 398 | 399 | ## 12.6 400 | 使用 LMbench 测试程序,获得 CPU 的一级、二级、三级 Cache 和内存的访存延迟。 401 | 402 | **解** 403 | 404 | 在运行 LMbench 测试程序的过程中,程序卡死在“Calculating memory load latency”一步…… 405 | 406 | ## 12.7 407 | 使用 SimpleScalar 模拟器,分析二级 Cache 的延迟对性能的影响(从 24 变到 12 个时钟周期)假设使用 Alpha 指令集,测试程序为 SPEC CPU2000 的 `164.bzip` 和 `253.perlbmk`。 408 | 409 | **解** 410 | 411 | SimpleScalar 模拟器比较古老,其标准安装环境是 2010 年发布的 Ubuntu 10.04。虽然有人尝试在 Ubuntu 14.04 或更高的版本上安装,但都遇到了很多依赖不兼容的问题。因此我选择使用现成的 Docker 环境(https://hub.docker.com/r/khaledhassan/simplescalar)。 412 | 413 | 但在完成环境配置之后,研究了很长时间的 SimplerScalar 和 SPEC CPU2000 的文档,我还是没有搞明白如何让 SPEC CPU2000 在 SimpleScalar 上编译运行…… 414 | 415 | ## 12.8 416 | 嵌入式基准测试程序如 EEMBC 和桌面基准测试程序在行为特性上有什么差别? 417 | 418 | **解** 419 | 420 | 对于嵌入式系统,其 Soc 的微结构要比一般的桌面 CPU 简单很多。Cache、乱序执行、重命名寄存器等桌面 CPU 常见的技术很少会在资源紧张的嵌入式系统上应用。因此,嵌入式基准测试程序不会关注这些方面。 421 | 422 | 相比较桌面系统,嵌入式系统对功耗要求更高,嵌入式基准测试程序可能会专门对功耗进行测试。 423 | 424 | ## 12.9 425 | 查找 ARM Cortex A 系列处理器的用户手册,列出你认为比较重要的硬件性能计数器的 10 个性能事件,并给出事件描述。 426 | 427 | **解** 428 | |事件名称|事件描述| 429 | |:-|:-| 430 | |Instruction cache dependent stall cycles|统计处理器等待指令到达的周期数。处理器在此时准备好接受指令,但指令缓存正在进行一次行填充而不能提供指令。| 431 | |Data cache dependent stall cycles|统计处理器等待数据到达的周期数。处理器在此时准备好接受数据,但指令缓存正在进行一次行填充而不能提供数据。| 432 | |Main TLB miss stall cycles|统计处理器等待主 TLB 完成遍历的周期数| 433 | |Main execution unit instructions|统计主处理单元(主执行流水线、乘法流水线、ALU 流水线)中正在执行的指令数| 434 | |Second execution unit instructions|统计次处理单元中正在执行的指令数| 435 | |Load/Store Instructions|统计访存指令条数| 436 | |Floating-point instructions|统计浮点指令条数| 437 | |External interrupts|统计外部中断的次数| 438 | |Processor stalled because of a write to memory|统计因写内存导致的处理器暂停周期数| 439 | |Processor stalls because of PLDs|统计由于 PLD 满导致的处理器暂停周期数| 440 | 441 | 442 | ## 12.10 443 | 模拟建模的方法和性能测量的方法相比有哪些优点? 444 | 445 | **解** 446 | 447 | * 性能测量的方法仅能用于已经搭建好的系统和原型系统,但模拟建模的方法可以用于系统的设计阶段; 448 | * 使用性能测量的方法,必须线搭建好原型系统,开销较大,但模拟建模的方法只需要通过软件建模,开销较小; 449 | * 性能测量的方法依赖于系统中的硬件性能计数器,灵活度低,模拟建模的方法可以方便地增添性能事件,更灵活的进行统计测量。 450 | 451 | ## 12.11 452 | SimPoint 的基本原理是什么,为什么其能减少模拟建模的时间? 453 | 454 | **解** 455 | 456 | SimPoint 是一种采样模拟技术,它找到程序执行的相位,然后对能够代表每个相位的部分进行采样和模拟仿真。其避免了模拟时的大量重复,以相同相位作代表,从而大量的节省了时间。 457 | 458 | ## 12.12 459 | 模拟器和真实的机器怎么校准,校准的评价指标通常是什么? 460 | 461 | **解** 462 | 463 | 比较模拟器和真实机器在同一程序上的运行结果,对比相关性能计数器的数据。若发现某些数据存在较大的误差,则寻找出问题所在予以修正。 464 | 465 | 评价指标即为模拟器与真实机器运行结果的吻合度。 466 | 467 | ## 12.13 468 | 在你的电脑上运行 SPEC CPU2000 的 rate 并给出分值。 469 | 470 | **解** 471 | 472 | |SPEC 程序|`-O0` 运行时间 / 秒|`-O0` 分值|`-O2` 运行时间 / 秒|`-O2` 分值| 473 | |:-|:-:|:-:|:-:|:-:| 474 | |164.gzip|76.5|1830|121|1161| 475 | |175.vpr|55.3|2530|101|1380| 476 | |176.gcc|27.9|3938|X|X| 477 | |181.mcf|72.4|2488|90.1|1997| 478 | |186.crafty|28.4|3516|41.1|2430| 479 | |197.parser|93|1935|155|1160| 480 | |252.eon|X|X|232|560| 481 | |253.perlbmk|X|X|72.1|2496| 482 | |254.gap|31.6|3476|31.1|3538| 483 | |255.vortex|46.6|4079|85.3|2227| 484 | |256.bzip2|60.3|2486|129|1166| 485 | |300.twolf|83.6|3587|150|1998| 486 | |SPEC_INT2000||2878 ||1640 | 487 | |168.wupwise|X|X|104|1535| 488 | |171.swim|X|X|164|1886| 489 | |172.mgrid|X|X|334|539| 490 | |173.applu|X|X|286|734| 491 | |177.mesa|33.8|4143|68.3|2051| 492 | |178.galgel|X|X|X|X| 493 | |179.art|23.3|11148|51.2|5078| 494 | |183.equake|X|X|X|X| 495 | |187.facerec|36.7|5176|76.2|2493| 496 | |188.ammp|X|X|173|1273| 497 | |189.lucas|X|X|69|2899| 498 | |191.fma3d|X|X|124|1687| 499 | |200.sixtrack|X|X|257|429| 500 | |301.apsi|54.8|4746|200|1297| 501 | |SPEC_INT2000||5804 ||1471 | 502 | -------------------------------------------------------------------------------- /assignment_ch2/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 2 章作业 2 | 3 | ## 2.1 4 | 列出一种指令系统的不同运行级别之间的关系。 5 | 6 | **解** 7 | 8 | 如图,为 MIPS 指令系统不同运行级别的关系图。 9 | 10 | 11 | 12 | ## 2.2 13 | 用 C 语言描述段页式存储管理的地址转换过程。 14 | 15 | **解** 16 | 17 | C 语言的描述如下: 18 | ```c 19 | Page_table * page_base = segment_table[segment]; 20 | void * phys_addr = offset + page_base[virtual_page] << PAGE_SIZE; 21 | ``` 22 | 23 | ## 2.3 24 | 请简述桌面电脑 PPT 翻页过程中用户态和核心态的转换过程。 25 | 26 | **解** 27 | 28 | 当按下键盘后,处理器接受到中断信号,从用户态切换到核心态以响应中断,随后回到用户态运行 PowerPoint;PowerPoint 调用显示驱动程序,处理器进入核心态以执行显示操作,随后回到用户态。 29 | 30 | ## 2.4 31 | 给定下列程序片段: 32 | ```plain 33 | A = B + C 34 | B = A + C 35 | C = B + A 36 | ``` 37 | (1)写出上述程序片段在四种指令系统类型(堆栈型、累加器型、寄存器-存储器型、寄存器-寄存器型)中的指令序列。 38 | (2)假设四种指令系统都属于 CISC 型,令指令码宽度为 $x$ 位,寄存器操作数宽度为 $y$ 位,内存地址操作数宽度为 $z$ 位,数据宽度为 $w$ 位。分析指令的总位数和所有内存访问的总位数。 39 | (3)微处理器由 32 位时代进入 64 位时代,上述四种指令系统类型哪种更好? 40 | 41 | **解** 42 | 43 | (1) 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 70 | 80 | 90 | 101 | 102 | 103 |
堆栈型累加器型寄存器-存储器型寄存器-寄存器型
56 |
PUSH  B
 57 | PUSH  C
 58 | ADD
 59 | POP   A
 60 | PUSH  A
 61 | PUSH  C
 62 | ADD
 63 | POP   B
 64 | PUSH  B
 65 | PUSH  A
 66 | ADD
 67 | POP   C
 68 | 
69 |
71 |
LOAD  B
 72 | ADD   C
 73 | STORE A
 74 | ADD   C
 75 | STORE B
 76 | ADD   A
 77 | STORE C
 78 | 
79 |
81 |
LOAD  R1, B
 82 | ADD   R1, C
 83 | STORE A, R1
 84 | ADD   R1, C
 85 | STORE B, R1
 86 | ADD   R1, A
 87 | STORE C, R1
 88 | 
89 |
91 |
LOAD  R2, B
 92 | LOAD  R3, C
 93 | ADD   R1, R2, R3
 94 | STORE A, R1
 95 | ADD   R2, R1, R3
 96 | STORE B, R2
 97 | ADD   R3, R1, R2
 98 | STORE C, R3
 99 | 
100 |
104 | 105 | (2) 106 | 107 | 对于堆栈型: 108 | * 其指令总位数为 $9 \times (x + z) + 3 \times x = 12x + 9z$; 109 | * 其访存总位数为 $(12x + 9z) + 9 \times w = 12x + 9z + 9w$。 110 | 111 | 对于累加器型: 112 | * 其指令总位数为 $7 \times (x + z) = 7x + 7z$; 113 | * 其访存总位数为 $(7x + 7z) + 7 \times w = 7x + 7z + 7w$。 114 | 115 | 对于寄存器-存储器型: 116 | * 其指令总位数为 $7 \times (x + y + z) = 7x + 7y + 7z$; 117 | * 其访存总位数为 $(7x + 7y + 7z) + 7 \times w = 7x + 7y + 7z + 7w$。 118 | 119 | 对于寄存器-寄存器型: 120 | * 其指令总位数为 $5 \times (x + y + z) + 3 \times (x + 3y) = 8x + 14y + 5z$; 121 | * 其访存总位数为 $(8x + 14y + 5z) + 5 \times w = 8x + 14y + 5z + 5w$。 122 | 123 | (3)微处理器由 32 位时代进入 64 位时代,寄存器-寄存器型指令系统更好。其访问速度快,便于编译器调度优化,容易判断相关性,容易实现流水线、多发射、乱序执行等。 124 | 125 | 126 | ## 2.5 127 | 写出 `0xDEADBEEF` 在大尾端和小尾端下在内存中的排列(由地址 `0` 开始)。 128 | 129 | **解** 130 | 131 | 大尾端: 132 | ``` 133 | 0 1 2 3 134 | DE AD BE EF 135 | ``` 136 | 137 | 小尾端: 138 | ``` 139 | 0 1 2 3 140 | EF BE AD DE 141 | ``` 142 | 143 | ## 2.6 144 | 在你的机器上编写 C 程序来得到不同数据类型占用的字节数,给出程序和结果。 145 | 146 | **解** 147 | 148 | C 程序如下: 149 | ```c 150 | #include 151 | int main() { 152 | printf("char %ld\n", sizeof(char)); 153 | printf("short %ld\n", sizeof(short)); 154 | printf("int %ld\n", sizeof(int)); 155 | printf("long %ld\n", sizeof(long)); 156 | printf("long long %ld\n", sizeof(long long)); 157 | printf("float %ld\n", sizeof(float)); 158 | printf("double %ld\n", sizeof(double)); 159 | printf("long double %ld\n", sizeof(long double)); 160 | return 0; 161 | } 162 | ``` 163 | 164 | 程序输出结果如下: 165 | ``` 166 | char 1 167 | short 2 168 | int 4 169 | long 8 170 | long long 8 171 | float 4 172 | double 8 173 | long double 16 174 | ``` 175 | 176 | 即 177 | 178 | | C 语言类型 | 占用字节数 | 179 | | :------------ | :--------: | 180 | | `char` | 1 | 181 | | `short` | 2 | 182 | | `int` | 4 | 183 | | `long` | 8 | 184 | | `long long` | 8 | 185 | | `float` | 4 | 186 | | `double` | 8 | 187 | | `long double` | 16 | 188 | 189 | ## 2.7 190 | 根据 MIPS 指令集的编码格式计算条件转移指令和直接转移指令的跳转范围。 191 | 192 | **解** 193 | 194 | 对于条件转移指令,其采用 I-type 指令,立即数长度为 $16$ 位,实际偏移量为立即数左移 $2$ 位,且为有符号数。故其跳转范围是相对于当前 PC,$-2^{17} \sim 2^{17}$ 字节,即 $\pm 128\ \text{KB}$。 195 | 196 | 对于直接转移指令,其采用 J-type 指令,立即数长度位 $26$ 位,实际偏移量为立即数左移 $2$ 位。故其跳转范围是 $2^{28}$ 字节,即 $256\ \text{MB}$。 197 | 198 | ## 2.8 199 | 不使用 LWL 和 LWR,写出如图 2.10 的不对齐加载(小尾端)。 200 | 201 | **解** 202 | 203 | 小尾端情况下,等效代替 `LWR R1, 1`、`LWL R1, 4` 的代码如下: 204 | ``` 205 | LW R1, 0 206 | SRL R1, 8 207 | LW R2, 4 208 | SLL R2, 24 209 | OR R1, R1, R2 210 | ``` 211 | -------------------------------------------------------------------------------- /assignment_ch2/图片1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch2/图片1.png -------------------------------------------------------------------------------- /assignment_ch3/TLB.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | asid_t ASID; 3 | vpn_t VPN; 4 | mask_t Mask; 5 | pfn_t PFN; 6 | flag_t Flag; 7 | } TLB_page_table_entry_t; 8 | 9 | TLB_page_table_entry_t TLB_table[TLB_SIZE]; 10 | 11 | pfn_t address_translation(asid_t ASID, vpn_t VPN) { 12 | search_result_t search_result; 13 | 14 | if (!(search_result = TLB_probe(ASID, VPN))) { 15 | raise_exception(EXCEPTION_TLB_REFILL); 16 | } 17 | if (!search_result.V) { 18 | raise_exception(EXCEPTION_TLB_INVALID); 19 | } 20 | if (!search_result.D) { 21 | raise_exception(EXCEPTION_TLB_MODIFY); 22 | } 23 | return search_result.PFN; 24 | } 25 | 26 | void handle_TLB_refill(void) { 27 | context_t context = get_cp0(CP0_CONTEXT); 28 | pfn_t PFN = get_PFN_from_page_table(context); 29 | TLB_write(context, PFN); 30 | return; 31 | } 32 | 33 | void handle_TLB_invalid(void) { 34 | pte_t pte = get_pte_current(); 35 | read_page_from_extern(); 36 | } 37 | 38 | void handle_TLB_modify(void) { 39 | pte_t pte = get_pte_current(); 40 | if (check_something()) { 41 | enable_write(); 42 | } else { 43 | kill(); 44 | } 45 | } -------------------------------------------------------------------------------- /assignment_ch3/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 3 章作业 2 | 3 | ## 3.1 4 | 简述 MIPS 与 X86 在异常处理过程中的区别。 5 | 6 | **解** 7 | 8 | 1. 异常处理准备: 9 | * MIPS 中,被异常打断的指令地址存放在协处理器 CP0 的 EPC 寄存器中; 10 | * X86 中,被异常打断的指令地址(CS、EIP 组合)被存放在栈中; 11 | 2. 确定异常来源: 12 | * MIPS 中,区分异常来源的工作由软件完成,异常处理程序根据 CAUSE 寄存器存储的状态,再做进一步查询和区分处理; 13 | * X86 中,区分异常来源的工作由硬件完成,硬件根据异常生成异常中断号,根据编号查找预设的中断描述符表,跳转到对应异常处理程序入口; 14 | 3. 保存执行状态、处理异常、恢复执行状态,这两部分 MIPS 与 X86 没有太大区别; 15 | 4. 异常返回: 16 | * MIPS 中,使用 ERET 指令从异常中返回;X86 中,使用 IRET 指令从异常中返回。两者功能相差不大。 17 | 18 | ## 3.2 19 | MIPS 的 LL bit 在发生异常后会怎样处理,为什么? 20 | 21 | **解** 22 | 23 | 在发生异常后,LL bit 会被重置,使得后面的 SC 指令执行失败。 24 | 25 | LL bit 用于标识 LL、SC 指令对在执行时的原子性。在 LL、SC 指令在运用过程中发生异常,异常本身会打破 LL、SC 指令的原子性。原子性的丢失意味着 LL bit 必须被重置,需要重新尝试 LL、SC 指令来保证原子性。 26 | 27 | ## 3.3 28 | 简述精确异常与非精确异常的区别。找一个使用非精确异常的处理器。 29 | 30 | **解** 31 | 32 | 精确异常(Precise Exception),要求被异常打断的指令前的指令都执行完毕,被异常打断前的指令及以后的所有指令都如同没执行。在精确异常中,EPTR 必须恰好指向被异常打断的指令。 33 | 34 | 非精确异常(Imprecise Exception),对被异常打断前后的指令执行情况没有要求。在非精确异常中,EPTR 不一定恰好指向被异常打断的指令,通常指向被异常打断的指令后的某条指令。 35 | 36 | 在 SONY、TOSHIBA、IBM 开发的 Cell 处理器架构中,浮点指令会产生非精确异常。 37 | 38 | ## 3.4 39 | 在一台 MIPS-Linux 机器(页大小为 4KB)上执行下列程序片段,会发生多少次异常?说明其过程。 40 | 41 | ```c 42 | void cycle(double *a) { 43 | int i; 44 | double b[65536]; 45 | for (i = 0; i < 3 ; i++) { 46 | memcpy(a, b, sizeof(b)); 47 | } 48 | } 49 | ``` 50 | 51 | **解** 52 | 53 | 假设 TLB 表能存储超过 256 项。 54 | 55 | 单个 `double` 变量为 8 个字节,长度为 `65536` 的数组 `b` 大小即为 `65536 × 8 B = 512 KB`,共 `128` 页。 56 | 57 | 第 1 次 `memcpy` 的过程中: 58 | * 访问 `a`:由于 TLB 内没有 `a` 所在内存的相应表项,会造成 `128` 次 TLB 充填异常。如果 `a` 还没有分配物理空间,则还会继续造成 `128` 次 TLB 无效异常。 59 | * 访问 `b`:由于 TLB 内没有 `b` 所在内存的相应表项,会造成 `128` 次 TLB 充填异常。同时,`b` 还没有分配物理空间,还会造成 `128` 次 TLB 无效异常。 60 | 61 | 在后两次 `memcpy` 的过程中,由于访问内存所需的 TLB 已经全部填充完成,不再产生异常。 62 | 63 | 故总共产生 512 次异常。 64 | 65 | ## 3.5 66 | 用 C 语言描述包含 TLB 的页式存储管理过程(包含 TLB 操作)。 67 | 68 | **解** 69 | 70 | 程序代码如下: 71 | ```c 72 | typedef struct { 73 | asid_t ASID; 74 | vpn_t VPN; 75 | mask_t Mask; 76 | pfn_t PFN; 77 | flag_t Flag; 78 | } TLB_page_table_entry_t; 79 | 80 | TLB_page_table_entry_t TLB_table[TLB_SIZE]; 81 | 82 | pfn_t address_translation(asid_t ASID, vpn_t VPN) { 83 | search_result_t search_result; 84 | 85 | if (!(search_result = TLB_probe(ASID, VPN))) { 86 | raise_exception(EXCEPTION_TLB_REFILL); 87 | } 88 | if (!search_result.V) { 89 | raise_exception(EXCEPTION_TLB_INVALID); 90 | } 91 | if (!search_result.D) { 92 | raise_exception(EXCEPTION_TLB_MODIFY); 93 | } 94 | return search_result.PFN; 95 | } 96 | 97 | void handle_TLB_refill(void) { 98 | context_t context = get_cp0(CP0_CONTEXT); 99 | pfn_t PFN = get_PFN_from_page_table(context); 100 | TLB_write(context, PFN); 101 | return; 102 | } 103 | 104 | void handle_TLB_invalid(void) { 105 | pte_t pte = get_pte_current(); 106 | read_page_from_extern(); 107 | } 108 | 109 | void handle_TLB_modify(void) { 110 | pte_t pte = get_pte_current(); 111 | if (check_something()) { 112 | enable_write(); 113 | } else { 114 | kill(); 115 | } 116 | } 117 | ``` -------------------------------------------------------------------------------- /assignment_ch4/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 4 章作业 2 | 3 | ## 4.1 4 | 在观看网络视频时,网卡将接收到的网络包放到内存并通知处理器对视频数据流进行解码好发送给显示单元。 5 | 6 | 此时,处理器对该网络包的中断处理是否应分上下部?若是,应如何切分? 7 | 8 | **解** 9 | 10 | 由于整个流程需要处理器处理大量数据,所需的时间长,应当分上下部处理。 11 | 12 | 上半部运行于中断上下文,负责清除中断状态,将对数据解码的处理方案通知到相应中断的进程。 13 | 14 | 下半部由专门的工作者进程处理,负责实际执行解码数据流的过程,可以进行休眠和阻塞。 15 | 16 | ## 4.2 17 | (1)用 MIPS 汇编程序来举例并分析未同步的线程之间进行共享数据访问出错的情况。 18 | (2)用 LL/SC 指令改写你的程序,使它们的共享数据访问正确。 19 | 20 | **解** 21 | 22 | (1)考虑一个双线程程序,两个线程向一个数组中分别写入 100 ~ 1,过程中共用一个偏移量。两个程序代码相同,如下: 23 | ```plain 24 | li $t1, 100 25 | L: 26 | lw $t0, 0($a0) 27 | addiu $t0, 1 28 | sw $t0, 0($a0) 29 | sw $t1, 0($t0) 30 | addiu $t1, -1 31 | bnez $t1, LL 32 | ``` 33 | 34 | (2)修改后的程序如下: 35 | ```plain 36 | li $t1, 100 37 | L: 38 | ll $t0, 0($a0) 39 | addiu $t0, 1 40 | sc $t0, 0($a0) 41 | beqz $t0, L 42 | 43 | sw $t1, 0($t0) 44 | addiu $t1, -1 45 | bnez $t1, L 46 | ``` 47 | 48 | ## 4.3 49 | (1)在你的机器上安装 MIPS 交叉编译器,通过编译-反汇编的方式提取函数调用的核心片段。 50 | (2)改变编译的优化选项,记录函数调用核心片段的变化,并分析不同优化选项的效果。 51 | 52 | **解** 53 | 54 | 这里使用 `mips64el-linux-gcc` 作为交叉编译器。 55 | 56 | (1)以下面的程序为例: 57 | ```c 58 | int function_b(int a, int b) { 59 | return a + b; 60 | } 61 | void function_a() { 62 | int a = 10; 63 | int b = 12; 64 | function_b(a, b); 65 | } 66 | ``` 67 | 68 | 在不添加编译优化选项的情况下,`function_a` 中调用 `function_b` 的核心片段如下: 69 | ```plain 70 | move a0,v1 71 | move a1,v0 72 | ld v0,-32664(gp) 73 | move t9,v0 74 | jalr t9 75 | nop 76 | ``` 77 | `function_b` 中进入函数和退出函数的核心片段如下: 78 | ```plain 79 | daddiu sp,sp,-32 80 | sd s8,24(sp) 81 | move s8,sp 82 | # do something 83 | move sp,s8 84 | ld s8,24(sp) 85 | daddiu sp,sp,32 86 | jr ra 87 | nop 88 | ``` 89 | 90 | (2) 91 | 不开启编译优化时(即 `-O0`),汇编代码与上面所述相同。 92 | 93 | 在开启编译优化 `-O1` 时,由于上面的函数均不需要用栈,`function_a` 和 `function_b` 中有关函数调用的准备代码基本被全部优化掉了,只剩下一个用于返回的 `jr ra` 指令。 94 | 95 | ## 4.4 96 | ABI 中会包含对结构体中各元素的对齐和摆放方式的定义。 97 | 98 | (1)在你的机器上用 C 语言编写一段包含不同类型的结构体,并获得结构体总空间占用情况。 99 | (2)调整结构体元素顺序,推测并分析结构体对齐的方式。 100 | 101 | **解** 102 | 103 | (1)以下面的结构体实验: 104 | ```c 105 | struct Test{ 106 | char a; 107 | short b; 108 | int c; 109 | long d; 110 | }; 111 | ``` 112 | 经过实验,其占用空间为 16 字节。 113 | 114 | (2)调整顺序为: 115 | ```c 116 | struct Test{ 117 | char a; 118 | long d; 119 | short b; 120 | int c; 121 | }; 122 | ``` 123 | 其占用空间为 24 字节。 124 | 125 | 调整顺序为: 126 | ```c 127 | struct Test{ 128 | char a; 129 | int c; 130 | long d; 131 | short b; 132 | }; 133 | ``` 134 | 其占用空间仍为 24 字节。 135 | 136 | 调整为: 137 | ```c 138 | struct Test{ 139 | char a; 140 | short b; 141 | int c; 142 | int e; 143 | }; 144 | ``` 145 | 其占用空间为 12 字节。 146 | 147 | 调整为: 148 | ```c 149 | struct Test{ 150 | char a; 151 | short b; 152 | int c; 153 | long f; 154 | int e; 155 | }; 156 | ``` 157 | 其占用空间为 24 字节。 158 | 159 | 由此可以推测,结构体以其中包含的最长元素为单位对齐。例如,存在 `long` 时,以 8 字节对齐;不存在 `long` 但存在 `int` 时,以 4 字节对齐。 160 | 161 | ## 4.5 162 | 函数调用、系统调用和中断处理都需要上下文切换,请结合 MIPS O32 ABI 说明上述三种上下文切换时保留现场有什么不同(内容、位置)。 163 | 164 | **解** 165 | 166 | * 函数调用:需要保存寄存器中由被调用者保存的寄存器(`s0` ~ `s8` 以及 6 个浮点寄存器)和栈帧(`s8/fp`),保存位置在栈上。 167 | * 系统调用:需要保存寄存器中由被调用者保存的寄存器(`s0` ~ `s8` 以及 6 个浮点寄存器),保存位置在内核栈上或 PCB 中。 168 | * 中断处理:需要保存所有通用寄存器和部分控制寄存器的值,保存位置在内核栈上或 PCB 中。 -------------------------------------------------------------------------------- /assignment_ch5/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 5 章作业 2 | 3 | ## 5.1 4 | 分别说明图 5.6 ~ 5.9 所示的四种结构中,每片包含冯诺依曼结构五个部分的哪部分功能。 5 | 6 | **解** 7 | 8 | 图 5.6 CPU - GPU - 北桥 - 南桥四片结构: 9 | * CPU 芯片包含了运算器、控制器的功能,同时包含了存储器中的高速缓存; 10 | * GPU 芯片包含了与图形相关的运算器、控制器的功能,同时也是图形相关的输入输出设备; 11 | * 北桥芯片包含了存储器的控制功能、输入输出设备的控制功能; 12 | * 南桥芯片包含了存储器中的只读存储器、输入输出设备的控制功能,亦可视作包含了存储器中的永久存储器(硬盘)的控制功能。 13 | 14 | 图 5.7 CPU - 北桥 - 南桥三片结构: 15 | * CPU 芯片包含了运算器、控制器的功能,同时包含了存储器中的高速缓存; 16 | * 北桥芯片包含了与图形相关的运算器、控制器的功能,也是图像的输入输出设备,同时包含了存储器的控制功能、输入输出设备的控制功能; 17 | * 南桥芯片包含了存储器中的只读存储器、输入输出设备的控制功能,亦可视作包含了存储器中的永久存储器(硬盘)的控制功能。 18 | 19 | 图 5.8 CPU - 弱北桥 - 南桥三片结构: 20 | * CPU 芯片包含了运算器、控制器的功能,同时包含了存储器中的高速缓存和存储器的控制功能; 21 | * 北桥芯片包含了与图形相关的运算器、控制器的功能,也是图像的输入输出设备,同时包含了输入输出设备的控制功能; 22 | * 南桥芯片包含了存储器中的只读存储器、输入输出设备的控制功能,亦可视作包含了存储器中的永久存储器(硬盘)的控制功能。 23 | 24 | 图 5.9 CPU - 南桥两片结构: 25 | * CPU 芯片包含了运算器、控制器的功能,同时包含了存储器中的高速缓存和存储器的控制功能,包含了与图形相关的运算器、控制器的功能和图像输入输出设备; 26 | * 南桥芯片包含了存储器中的只读存储器、输入输出设备的控制功能,亦可视作包含了存储器中的永久存储器(硬盘)的控制功能。 27 | 28 | ## 5.2 29 | 查阅资料,比较 Skylake 处理器和 Zen 处理器的运算器结构。 30 | 31 |
32 | 33 | **解** 34 | Skylake 处理器的单核架构如图: 35 | 36 | 37 | 38 | Zen 处理器的单核架构如图: 39 | 40 | 41 | 42 |
43 | 44 | 根据架构图可以看到,Skylake 和 Zen 单核均有 4 个 ALU。但是,Skylake 将浮点运算单元与整数运算单元做在了一起,Zen 则将浮点运算单元独立了出来;Skylake 的每个执行端口可执行的操作不同,Zen 每个执行端口则完全相同。 45 | 46 | ## 5.3 47 | 说明 ROB、保留站(发射队列)、重命名寄存器在指令流水线中的作用,并查阅资料,比较 Skylake 处理器和 Zen 处理器的 ROB、发射队列、重命名寄存器项数。 48 | 49 | **解** 50 | 51 | * ROB:即重排序缓冲(Re-Order Buffer),在乱序执行技术中,用于使指令流水线中乱序执行完的指令有序地结束。其有序地将指令执行结果提交到目标寄存器或存储器,以保证执行结果符合程序规定的要求。 52 | * 保留站(发射队列):在乱序执行技术中,用于将有序的指令变为无序以提高执行效率。其保存操作数没有准备好的指令,待操作数准备好后再放入执行阶段。 53 | * 重命名寄存器:再乱序执行技术中,用于临时存储指令和数据。其用于保存乱序执行过程中的指令执行结果,避免破坏结构寄存器的内容,使得两组执行不同运算但使用同一结构寄存器的指令并行执行。 54 | 55 | Skylake 处理器和 Zen 处理器的 ROB、发射队列、重命名寄存器项数: 56 | | 处理器 | ROB 项数 | 发射队列 | 重命名寄存器 | 57 | | :-----: | :------: | :------: | :----------: | 58 | | Skylake | 224 项 | 6 µOPs | 180项 | 59 | | Zen | 192 项 | 6 µOPs | 168项 | 60 | 61 | ## 5.4 62 | 对于程序段 63 | ``` 64 | for (i = 0; i < 10; i++) 65 | for (j = 0; j < 10; j++) 66 | for (k = 0; k < 10; k++) 67 | {...} 68 | ``` 69 | 计算分别使用一位 BHT 表和使用两位 BHT 表进行转移猜测时,三重循环的转移猜测准确率,假设 BHT 表的初始值均为 0。 70 | 71 | **解** 72 | 73 | 使用一位 BHT 表时: 74 | * 对循环 `k`,单次循环 `k` 将执行 $10$ 次跳转指令,进入、退出各会猜测错误 $1$ 次,猜测准确 $8$ 次,结束时 BHT 表对应项的值为 $0$。 75 | * 对循环 `i`、`j`,同理,进入、退出各会猜测错误 $1$ 次,结束时 BHT 表对应项的值为 $0$。 76 | * 那么,使用一位 BHT 表时,总的转移预测正确率为 $80\%$ 77 | 78 | 使用两位 BHT 表时: 79 | * 对循环 `k`: 80 | * 单次循环 `k` 将执行 $10$ 次跳转指令; 81 | * 第一次执行循环 `k` 时,前两次跳转均会猜错,随后一直正确,最后一次跳转又会猜错,总计猜测准确 $7$ 次,结束时 BHT 表对应项的值为 $2$; 82 | ``` 83 | Correct X X O O O O O O O X 84 | BHT after 0 1 2 3 3 3 3 3 3 3 2 85 | ``` 86 | * 后续执行循环 `k` 时,前九次跳转均会猜对,最后一次跳转猜错,总计猜测准确 $9$ 次,结束时 BHT 表对应项的值为 $2$; 87 | ``` 88 | Correct? O O O O O O O O O X 89 | BHT after 2 3 3 3 3 3 3 3 3 3 2 90 | ``` 91 | * 循环 `k` 总计执行 $100$ 次,跳转指令执行 $100 \times 10 = 1000$ 次,总计猜测准确 $7 + 9 \times 99 = 898$ 次。 92 | * 对循环 `j`: 93 | * 单次循环、第一次执行、后续执行的讨论与循环 `k` 同理; 94 | * 循环 `j` 总计执行 $10$ 次,跳转指令执行 $10 \times 10 = 100$ 次,总计猜测准确 $7 + 9 \times 9 = 88$ 次。 95 | * 对循环 `i`: 96 | * 其执行过程与循环 `k` 第一次执行相同; 97 | * 循环 `i` 只执行 $1$ 次, 跳转指令执行 $10$ 次,总计猜测准确 $7$ 次。 98 | * 那么,使用两位 BHT 表时,总的转移预测正确率为 $(898 + 88 + 7) / (1000 + 100 + 10) \approx 89.46\%$ 99 | 100 | ## 5.5 101 | 假设 A 处理器有两级 Cache,一级 Cache 大小为 32 KB,命中率为 95%,命中延迟为 1 拍,二级 Cache 大小为 1 MB,命中率为 80%,命中延迟为 30 拍,失效延迟为 150 拍。B 处理器有三级 Cache,一级 Cache 大小为 32 KB,命中率为 95%,命中延迟为 1 拍;二级 Cache 大小为 256 KB,命中率为 75%,命中延迟为 20 拍;三级 Cache 大小为 4 MB,命中率为 80%,命中延迟为 50 拍,失效延迟为 150 拍。比较两款处理器的平均访问延迟。 102 | 103 | **解** 104 | 105 | A 处理器的平均访问延迟为: 106 | $$ 107 | 95\% \times 1 + (1 - 95\%)\times [80\% \times 30 + (1- 80\%) \times 150] = 3.65 \ \text{拍} 108 | $$ 109 | 110 | B 处理器的平均访问延迟为: 111 | $$ 112 | 95\% \times 1 + (1 - 95\%) \times \{ 75\% \times 20 + (1 - 75\%) \times [80\% \times 50 + (1 - 80\%) \times 150] \} = 2.575 \ \text{拍} 113 | $$ 114 | 115 | 可以看出,B 处理器的平均访问延迟比 A 处理器更短。 116 | 117 | ## 5.6 118 | 假设某内存访问,行关闭、打开、读写各需要两拍,在行缓存命中为 $70\%$ 和 $30\%$ 的情况下,采用 Open Page 模式还是 Close Page 模式性能更高? 119 | 120 | **解** 121 | 122 | 在 Open Page 模式下: 123 | * 行缓冲命中时,只需要读写操作,总共需要 $2$ 拍; 124 | * 行缓冲不命中时,需要行关闭、行打开、读写操作,总共需要 $2 + 2 + 2 = 6$ 拍; 125 | * 在行缓存命中为 $70\%$ 的情况下,平均需要 $3.2$ 拍; 126 | * 在行缓存命中为 $30\%$ 的情况下,平均需要 $4.8$拍。 127 | 128 | 在 Close Page 模式下: 129 | * 总是需要读写、行关闭操作,总共需要 $2 + 2 = 4$ 拍。 130 | 131 | 综上,在行缓存命中为 $70\%$ 的情况下,选择 Open Page 模式;在行缓存命中为 $30\%$ 的情况下,选择 Close Page 模式。 132 | 133 | ## 5.7 134 | 简要说明处理器和 IO 设备之间的两种通信方式的通信过程。 135 | 136 | **解** 137 | 138 | 两种通信方式指的应该是两种寻址方式:内存映射 IO、特殊 IO 指令。 139 | * 内存映射 IO:IO 寄存器被统一编址到内存地址空间中,处理器通过普通的访存指令访问对应的地址空间,经过地址转换后访问 IO 寄存器; 140 | * 特殊 IO 指令:IO 地址空间与内存地址空间相互独立,处理器通过专用的 IO 指令来访问 IO 寄存器。 141 | 142 | ## 5.8 143 | 简要说明处理器和 IO 设备之间的两种同步方式的同步过程。 144 | 145 | **解** 146 | 147 | 两种同步方式为:查询、中断。 148 | * 查询:处理器在向 IO 设备发出请求后,不断地轮询 IO 设备的状态寄存器,直到设备完成请求后读回结果。 149 | * 中断:处理器在向 IO 设备发出请求后,转去执行其他进程,设备完成请求后,产生一个中断信号,使处理器被中断后再去读取 IO 设备的状态寄存器。 150 | 151 | ## 5.9 152 | 在一个两片系统中,CPU 含内存控制器,桥片含 GPU、DC 和显存,简要说明在 PPT 翻页过程中,CPU、GPU、DC、显存、内存之间的同步和通信过程。 153 | 154 | **解** 155 | 156 | * 敲击键盘,键盘发送一个信号到桥片,桥片中的中断控制器记录这个信号并向处理器发出中断信号。 157 | * 处理器收到中断信号,进入中断处理程序,从桥片中断控制器中获取中断信息,发现是键盘空格键被按下,于是找到 PowerPoint进程。 158 | * PowerPoint 进程在内存中准备好 PPT 下一页的相关数据,调用显示驱动程序,启动 DMA 将要显示的内容通过桥片送到显存中。 159 | * DC 读取显存中的相关信息,将内容显示在屏幕上。 160 | 161 | ## 5.10 162 | 调查目前市场主流光盘、硬盘、SSD 盘、内存的价格,并计算每 GB 存储容量的价格。 163 | 164 | **解** 165 | 166 | 如下表: 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 |
类型型号容量价格每 GB 价格备注
光盘飞利浦 CD-R 光盘700 MB × 50¥55.00¥1.57CD 单次刻录光盘
飞利浦 DVD-R 光盘4.7 GB × 50¥65.00¥0.27DVD 单次刻录光盘
徕德 BD-R 光盘50 GB × 50¥350.00¥0.14BD 单次刻录光盘
机械硬盘 HDD希捷 酷狼 ST4000VN008 4 TB¥725.00¥0.18NAS 服务器用机械硬盘
希捷 酷鹰 ST4000VX0074 TB¥495.00¥0.12视频监控用机械硬盘
固态硬盘 SSD三星 860 EVO500 GB¥429.00¥0.862.5 寸 SATA 接口固态硬盘
三星 970 EVO Plus500 GB¥550.00¥1.10NVME 接口固态硬盘
内存金士顿 骇客 DDR4 3200 16GB16 GB¥569.00¥35.56台式机 DDR4 3200 内存
三星 DDR4 2666 8GB8 GB¥209.00¥26.13笔记本 DDR3 2666 内存
-------------------------------------------------------------------------------- /assignment_ch5/zen_block_diagram.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 42 | 44 | 45 | 47 | image/svg+xml 48 | 50 | 51 | 52 | 53 | 54 | 59 | 68 | 77 | 86 | 92 | 101 | Front End 112 | ExecutionEngine 128 | Memory 139 | 147 | L2 Cache512KiB 8-Way 164 | 170 | L3 182 | 188 | 195 | DTLB 206 | 212 | 219 | Load Buffer(72 entries) 235 | 32B/cycle 246 | 252 | 258 | 265 | (44 entries) 276 | Store Buffer 287 | 293 | 32B/cycle store 304 | 311 | WCB 322 | 329 | ITLB 340 | 346 | 353 | 359 | 366 | OP CacheTags 382 | 388 | 395 | L1 Instruction Cache64KiB 4-Way 411 | 32B/Cycle 423 | 32B/Cycle 434 | 441 | PhysicalRequest Queue 457 | 463 | L1/L2 BTBReturn Stack (32 entry) Indirect Target Array (ITA)(512 entry; direct map) 489 | 495 | 503 | Next PC 515 | 521 | 527 | 534 | Instruction Byte Buffer 545 | 548 | 554 | 560 | 566 | 572 | 573 | 580 | PreDecode / Pick 591 | 594 | 600 | 606 | 612 | 618 | 619 | 625 | 632 | OP Cache(2K entry) 648 | 654 | 660 | 666 | 672 | 678 | 684 | 6 µOPs 695 | 4-8 MOPs 706 | 4 Instructions 717 | Integer 728 | FP/SIMD 740 | 747 | 4-Way Decode(Including fused µOPs) 763 | 770 | Decoder 781 | 788 | Decoder 799 | 806 | Decoder 817 | 824 | Decoder 835 | 838 | 844 | 850 | 856 | 862 | 863 | 870 | Dispatch 881 | 887 | 894 | 900 | MicroCode ROM(MSROM) 916 | 923 | Stack EngineMemfile 939 | 945 | 951 | 957 | 964 | µOP Queue (72 entry) 975 | 4 µOPs 986 | 992 | 998 | 1005 | Rename / Allocate 1016 | 1022 | 1028 | 1034 | 1040 | 1046 | 1052 | 1058 | 1064 | 1070 | 1076 | 1083 | Physical Register File (168 entries) 1094 | 1097 | 1104 | I Scheduler(14 entries) 1120 | 1121 | 1124 | 1131 | I Scheduler(14 entries) 1147 | 1148 | 1151 | 1158 | I Scheduler(14 entries) 1174 | 1175 | 1178 | 1185 | I Scheduler(14 entries) 1201 | 1202 | 1205 | 1212 | Mem Sche(14 entries) 1228 | 1229 | 1232 | 1239 | Mem Sche(14 entries) 1255 | 1256 | 1259 | 1265 | 1271 | 1272 | 1275 | 1281 | 1287 | 1288 | 1291 | 1297 | 1303 | 1304 | 1307 | 1313 | 1319 | 1320 | 1323 | 1329 | 1335 | 1336 | 1339 | 1345 | 1351 | 1352 | 1358 | 1361 | 1368 | AGU0 1379 | 1380 | 1387 | AGU1 1398 | 1404 | Forwarding Muxes 1415 | 1421 | 1428 | ALUBranch 1444 | 1450 | 1457 | ALUBranch 1473 | 1480 | ALUIMUL 1496 | 1503 | ALUIDIV 1519 | 1525 | 1531 | 1537 | 1544 | Non-Scheduling Queue (NSQ) 1555 | 1561 | 128 bitloads 1577 | 1583 | 1589 | 1595 | 1602 | LDCVT 1613 | 1619 | 1625 | 1628 | 1634 | 1640 | 1641 | 1644 | 1650 | 1656 | 1657 | 1660 | 1666 | 1672 | 1673 | 1676 | 1682 | 1688 | 1689 | 1695 | 1701 | 1707 | 1712 | 1719 | 128-bitFMAFMUL 1740 | 1747 | 128-bitFADD 1763 | 1770 | 128-bitFMAFMUL 1791 | 1798 | 128-bitFADD 1814 | 1820 | Forwarding Muxes 1831 | 1837 | 1843 | 1849 | 1856 | Physical Register File (160 entries) 1867 | 1873 | 1880 | Scheduling Queue (SQ)(96 entries) 1896 | 1903 | L1 Data Cache32KiB 8-Way 1919 | 2x128-bit 1931 | 2 loads/cycle 1943 | 1 store/cycle 1955 | 4-8 MOPs 1966 | 1969 | 1976 | Move Elimination 1987 | 1988 | 1994 | 2001 | Rename / Allocate 2012 | 2019 | Store to LoadForwarding 2035 | 8 entry L0 (all sizes)64 entry L1 (all sizes)512 entry L2 (no 1G) 2056 | 2062 | 2065 | 2071 | 2077 | 2083 | 2089 | 2095 | 2101 | 2107 | 2113 | 2114 | 2121 | Retire Queue(192 entries) 2137 | 8-wide retire 2148 | 2151 | 2158 | Branch Fusion 2169 | 2170 | 2176 | 2183 | HashPerceptron 2199 | 4 µOPs 2210 | 6 µOPs 2221 | 64 entry L11.5K entry L2 (no 1G) 2237 | 2244 | Micro-Tags(L1$ & µOP$) 2260 | 2261 | 2262 | -------------------------------------------------------------------------------- /assignment_ch6/APB_GPIO.v: -------------------------------------------------------------------------------- 1 | module APB_GPIO # ( 2 | parameter ADDR_WIDTH = 8, 3 | parameter DATA_WIDTH = 8, 4 | parameter GPIO_WIDTH = 8, 5 | parameter GPIO_DATA_ADDR = 8'h_f0, 6 | parameter GPIO_CONF_ADDR = 8'h_f1 7 | ) ( 8 | input pclk, 9 | input presetn, 10 | input [ADDR_WIDTH -1:0] paddr, 11 | input psel, 12 | input penable, 13 | input pwrite, 14 | output [DATA_WIDTH -1:0] prdata, 15 | input [DATA_WIDTH -1:0] pwdata, 16 | 17 | input [GPIO_WIDTH -1:0] gpio_in, 18 | output [GPIO_WIDTH -1:0] gpio_out, 19 | output [GPIO_WIDTH -1:0] gpio_out_en 20 | ); 21 | 22 | wire do_read; 23 | wire do_write; 24 | 25 | reg [DATA_WIDTH -1:0] prdata_r; 26 | 27 | reg [GPIO_WIDTH -1:0] gpio_config; 28 | reg [GPIO_WIDTH -1:0] gpio_data; 29 | 30 | wire rw_data; 31 | wire rw_conf; 32 | 33 | assign gpio_out = gpio_data; 34 | assign gpio_out_en = gpio_config; 35 | 36 | assign do_read = psel && !penable && !pwrite; 37 | assign do_write = psel && penable && pwrite; 38 | 39 | assign prdata = prdata_r; 40 | always @ (posedge pclk) begin 41 | if (!presetn) begin 42 | prdata_r <= {DATA_WIDTH{1'b0}}; 43 | end else if (do_read) begin 44 | if (paddr == GPIO_DATA_ADDR) begin 45 | prdata_r <= gpio_data; 46 | end else if (paddr == GPIO_CONF_ADDR) begin 47 | prdata_r <= gpio_config; 48 | end else begin 49 | prdata_r <= {DATA_WIDTH{1'b0}}; 50 | end 51 | end 52 | end 53 | 54 | always @ (posedge pclk) begin 55 | if (!presetn) begin 56 | gpio_config <= {GPIO_WIDTH{1'b0}}; 57 | end else if (do_write && paddr == GPIO_CONF_ADDR) begin 58 | gpio_config <= pwdata; 59 | end 60 | end 61 | 62 | always @ (posedge pclk) begin 63 | if (!presetn) begin 64 | gpio_data <= {GPIO_WIDTH{1'b0}}; 65 | end else if (do_write && paddr == GPIO_DATA_ADDR) begin 66 | gpio_data <= (~gpio_config & gpio_in) | (gpio_config & pwdata); 67 | end else begin 68 | gpio_data <= (~gpio_config & gpio_in) | (gpio_config & gpio_data); 69 | end 70 | end 71 | 72 | 73 | endmodule; -------------------------------------------------------------------------------- /assignment_ch6/inside_computer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch6/inside_computer.jpg -------------------------------------------------------------------------------- /assignment_ch6/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 6 章作业 2 | 3 | ## 6.1 4 | 找一台电脑,打开机箱,说明每条连线都是什么总线。(注意:一定要先切断电源。) 5 | 6 | **解** 7 | 8 | 如图所示。 9 | 10 | 11 | 12 | 图中没有标记的连线大多数是电源线。 13 | 14 | ## 6.2 15 | 说明总线包含哪些层次。 16 | 17 | **解** 18 | 19 | 总线基本包含以下四个层次: 20 | * 机械层:接口的机械外形、尺寸、信号排列顺序、连接线的长度范围等; 21 | * 电器层:信号描述、电源电压、电平标准、信号质量等; 22 | * 协议层:信号时序、握手规范、命令格式、错误处理等; 23 | * 架构层:硬件模型、软件架构等。 24 | 25 | ## 6.3 26 | 计算一组 AXI 总线需要的信号线条数。 27 | 28 | **解** 29 | 30 | 这里仅考虑课本上给出的主要信号。 31 | 32 | 设标识号位数为 $i$,地址位数为 $m$,数据位数为 $n$. 33 | 34 | * 时钟与复位: $2$ 35 | * 写请求通道:$i + m + 3 + 4 + 2 + 1 + 1 = 11 + i + m$; 36 | * 写数据通道:$i + n + \frac{1}{8}n + 1 + 1 = 2 + i + \frac{9}{8}n$; 37 | * 写响应通道:$i + 2 + 1 + 1 = 4 + i$; 38 | * 读请求通道:$i + m + 3 + 4 = 2 + 1 + 1 = 11 + i + m$; 39 | * 读响应通道:$i + n + 2 + 1 + 1 = 4 + i + n$。 40 | 41 | 总计 $34 + 5i + 2m + \frac{17}{8}n$ 条信号。对于 4 位 ID、32 位地址线、32 位数据线的情况,总计需要 $186$ 条信号。 42 | 43 | ## 6.4 44 | 阅读 AMBA APB 总线协议并设计一个 APB 接口的 GPIO 模块。 45 | 46 | **解** 47 | 48 | Verilog 代码如下: 49 | ```verilog 50 | module APB_GPIO # ( 51 | parameter ADDR_WIDTH = 8, 52 | parameter DATA_WIDTH = 8, 53 | parameter GPIO_WIDTH = 8, 54 | parameter GPIO_DATA_ADDR = 8'h_f0, 55 | parameter GPIO_CONF_ADDR = 8'h_f1 56 | ) ( 57 | input pclk, 58 | input presetn, 59 | input [ADDR_WIDTH -1:0] paddr, 60 | input psel, 61 | input penable, 62 | input pwrite, 63 | output [DATA_WIDTH -1:0] prdata, 64 | input [DATA_WIDTH -1:0] pwdata, 65 | 66 | input [GPIO_WIDTH -1:0] gpio_in, 67 | output [GPIO_WIDTH -1:0] gpio_out, 68 | output [GPIO_WIDTH -1:0] gpio_out_en 69 | ); 70 | 71 | wire do_read; 72 | wire do_write; 73 | 74 | reg [DATA_WIDTH -1:0] prdata_r; 75 | 76 | reg [GPIO_WIDTH -1:0] gpio_config; 77 | reg [GPIO_WIDTH -1:0] gpio_data; 78 | 79 | wire rw_data; 80 | wire rw_conf; 81 | 82 | assign gpio_out = gpio_data; 83 | assign gpio_out_en = gpio_config; 84 | 85 | assign do_read = psel && !penable && !pwrite; 86 | assign do_write = psel && penable && pwrite; 87 | 88 | assign prdata = prdata_r; 89 | always @ (posedge pclk) begin 90 | if (!presetn) begin 91 | prdata_r <= {DATA_WIDTH{1'b0}}; 92 | end else if (do_read) begin 93 | if (paddr == GPIO_DATA_ADDR) begin 94 | prdata_r <= gpio_data; 95 | end else if (paddr == GPIO_CONF_ADDR) begin 96 | prdata_r <= gpio_config; 97 | end else begin 98 | prdata_r <= {DATA_WIDTH{1'b0}}; 99 | end 100 | end 101 | end 102 | 103 | always @ (posedge pclk) begin 104 | if (!presetn) begin 105 | gpio_config <= {GPIO_WIDTH{1'b0}}; 106 | end else if (do_write && paddr == GPIO_CONF_ADDR) begin 107 | gpio_config <= pwdata; 108 | end 109 | end 110 | 111 | always @ (posedge pclk) begin 112 | if (!presetn) begin 113 | gpio_data <= {GPIO_WIDTH{1'b0}}; 114 | end else if (do_write && paddr == GPIO_DATA_ADDR) begin 115 | gpio_data <= (~gpio_config & gpio_in) | (gpio_config & pwdata); 116 | end else begin 117 | gpio_data <= (~gpio_config & gpio_in) | (gpio_config & gpio_data); 118 | end 119 | end 120 | endmodule; 121 | ``` 122 | 123 | 模块使用的 APB 总线地址、数据位宽均为 8 位,共有一组 8 位 GPIO。GPIO 配置寄存器地址为 `0xf1`,数据寄存器地址为 `0xf0`。配置寄存器对应位为高,代表 GPIO 对应引脚为输出,反之为输入。 124 | 125 | 126 | ## 6.5 127 | DRAM 的寻址包含哪几部分? 128 | 129 | **解** 130 | 131 | DRAM 的寻址包含 Bank 地址、行地址、列地址三部分。在计算机系统中,若将多组 DRAM 串接在一起,则会增加片选信号。 132 | 133 | ## 6.6 134 | 假设一个处理器支持两个 DDR3 内存通道,每个通道为 64 位宽,内存地址线个数为 15,片选个数为 4,计算该处理器实际支持的最大内存容量。 135 | 136 | **解** 137 | 138 | 每个通道为 64 位宽,则一次读写 8 字节数据。 139 | 140 | 根据题意: 141 | * 该处理器支持 2 个内存通道; 142 | * 每个内存通道有 4 条片选信号,即每个内存通道支持 24 = 16 组 DRAM。 143 | * 题目中未提到每组 DRAM 的 Bank 数,这里默认 Bank 信号数量为 4,即支持 24 = 16 组 Bank。 144 | * DDR3 中行列地址线复用,则支持的行、列数各 15。 145 | 146 | 综上,该处理器实际支持 2 × 24 × 24 × 215 × 215 × 8 Byte = 242 Byte = 4 TB 的内存容量。 -------------------------------------------------------------------------------- /assignment_ch6/图片1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch6/图片1.jpg -------------------------------------------------------------------------------- /assignment_ch7/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 7 章作业 2 | 3 | ## 7.1 4 | 什么情况下需要对 Cache 进行初始化?Cache 初始化过程中所使用的 Cache 指令 Index Store Tag(如 7.1.4 节的示例代码中所示)的作用是什么?列举一种 MIPS 的其他 Cache 指令并解释。 5 | 6 | **解** 7 | 8 | 在系统复位后 Cache 处于未经初始化的状态,如果使用 Cache 空间可能导致错误命中,此时需要对 Cache 进行初始化。 9 | 10 | Cache 指令 Index Store Tag 的作用是:使用地址索引到 Cache 行,根据 CP0 寄存器 LagLo 指定的 Tag、V、D 域更新该 Cache 行。 11 | 12 | 在 Cache 初始化过程中,我们首先初始化 CP0 寄存器 TagLo 为 0,然后再利用 Cache 指令 Index Store Tag 给所有 Cache 行写空 TAG。 13 | 14 | 其他的 MIPS Cache 指令如 Cache 指令 Index Invalid,它的作用是:使用地址索引到 Cache 行,然后使该行无效。 15 | 16 | ## 7.2 17 | Cache 初始化和内存初始化的目的有什么不同?系统如何识别内存的更换? 18 | 19 | **解** 20 | 21 | Cache 初始化的目的,是为了清除 Cache 中残留或随机的数据,防止访问 Cache 空间时导致错误的命中,涉及的是 Cache 内部存储的初始数据;内存初始化的目的,则是根据内存的配置信息正确初始化,以便后续程序能够正确地访问内存,并不涉及存储的初始数据。 22 | 23 | 内存的更换应当是在系统关闭的情况下进行的。在系统复位后的初始化过程中,BIOS 会自动通过 I2C 总线读取内存条上的 SPD 芯片,从中加载内存配置信息,并根据这些信息配置 CPU 或桥片中的内存控制器。如果系统发现此次读取的 SPD 信息与上一次初始化时读取的不相同,这说明内存发生了更换。 24 | 25 | ## 7.3 26 | 从 HyperTransport 配置地址空间的划分上,计算整个系统能够支持的总线数量、设备数量及功能数量。 27 | 28 | **解** 29 | 30 | 在 HyperTransport 总线中: 31 | * 总共支持的总线数量为 $256$:配置访问中总线号为第 $16 \sim 23$ 位,共 $8$ 位,可取 $2^8 = 256$ 种值; 32 | * 单条总线支持的设备数量为 $32$:配置访问中设备号为第 $15 \sim 11$ 位,共 $5$ 位,可取 $2^5 = 32$ 种值; 33 | * 单个设备支持的功能数量为 $8$:配置访问中功能号为第 $10 \sim 8$ 位,共 $3$ 位,可取 $2^3 = 8$ 种值; 34 | 35 | ## 7.4 36 | 根据 PCI 地址空间命中方法及 BAR 的配置方式,给出地址空间命中公式。 37 | 38 | **解** 39 | 40 | IO、Memory 空间命中公式为:`(ADDR & MASK) == {BAR[31:4], 4'b0000}`; 41 | 42 | 其中 `MASK` 由 BAR 空间的大小决定,可由下面的方法得到: 43 | * 向 BAR 寄存器写入 `32'h_ffffffff`; 44 | * 读取 BAR 的值到 `BAR_test`; 45 | * 取 `{BAR_test[31:4], 4'b0000}` 为 `MASK`。 46 | 47 | 配置空间命中公式为:`(ADDR & 32'h_ff000000) == {PCI_Config[31:24], 24'h000000}`; 48 | 49 | ## 7.5 50 | 多核唤醒时,如果采用核间中断方式,从核的唤醒流程是怎样的? 51 | 52 | **解** 53 | 54 | 唤醒流程如下: 55 | 1. 主核准备好唤醒程序的目标地址、执行参数等数据; 56 | 2. 主核触发从核的核间中断,并挂起主核; 57 | 3. 从核处理中断,跳转到唤醒程序开始执行唤醒过程; 58 | 4. 从核完成唤醒,触发主核的核间中断; 59 | 5. 主核处理中断,继续尝试唤醒下一个从核。 60 | 61 | ## 7.6 62 | 在一台 Linux 机器上,通过“`lspci -v`”指令查看该机器的设备列表,并列举其中三个设备的总线号、设备号和功能号,通过其地址空间信息写出该设备 BAR 的实际内容。 63 | 64 | **解** 65 | 66 | 运行 `lspci -v` 指令的结果如下(仅列举其中的三个设备): 67 | ```shell 68 | $ lspci -v 69 | # ... 70 | 00:01.2 USB controller: Intel Corporation 82371SB PIIX3 USB [Natoma/Triton II] (rev 01) 71 | (prog-if 00 [UHCI]) 72 | Subsystem: Red Hat, Inc. QEMU Virtual Machine 73 | Flags: bus master, fast devsel, latency 0, IRQ 11 74 | I/O ports at c040 [size=32] 75 | Kernel driver in use: uhci_hcd 76 | 77 | 00:02.0 VGA compatible controller: Cirrus Logic GD 5446 (prog-if 00 [VGA controller]) 78 | Subsystem: Red Hat, Inc. QEMU Virtual Machine 79 | Flags: fast devsel 80 | Memory at fc000000 (32-bit, prefetchable) [size=32M] 81 | Memory at febd0000 (32-bit, non-prefetchable) [size=4K] 82 | Expansion ROM at 000c0000 [disabled] [size=128K] 83 | Kernel driver in use: cirrus 84 | Kernel modules: cirrusfb, cirrus 85 | 86 | 00:05.0 SCSI storage controller: Red Hat, Inc. Virtio block device 87 | Subsystem: Red Hat, Inc. Virtio block device 88 | Physical Slot: 5 89 | Flags: bus master, fast devsel, latency 0, IRQ 10 90 | I/O ports at c000 [size=64] 91 | Memory at febd3000 (32-bit, non-prefetchable) [size=4K] 92 | Capabilities: [40] MSI-X: Enable+ Count=2 Masked- 93 | Kernel driver in use: virtio-pci 94 | # ... 95 | ``` 96 | 97 | 这三个设备的总线号、设备号、功能号、BAR 如下表: 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
总线号设备号功能号设备名BAR可写位只读 0 位
00012USB controller32'h_0000c041[31: 5][ 4: 4]
00020VGA compatible controller32'h_fc000000[31:25][24: 4]
32'h_febd0000[31:12][11: 4]
32'h_000c0000[31:17][16: 4]
00050SCSI storage controller32'h_0000c001[31: 6][ 5: 4]
32'h_febd3000[31:12][11: 4]
-------------------------------------------------------------------------------- /assignment_ch8/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 8 章作业 2 | 3 | ## 8.1 4 | 请将下列无符号数据在不同的进制表达间进行转换。 5 | 6 | (1) 二进制转换为十进制:$101001_2$、$001101_2$、$01011010_2$、$0000111010000101_2$。 7 | (2) 十进制转换为二进制:$42_{10}$、$79_{10}$、$811_{10}$、$374_{10}$。 8 | (3) 十六进制转换为十进制:$\text{8AE}_{16}$、$\text{C18D}_{16}$、$\text{B379}_{16}$、$\text{100}_16$。 9 | (4) 十进制转换为十六进制:$81783_{10}$、$1922_{10}$、$345208_{10}$、$5756_{10}$。 10 | 11 | **解** 12 | 13 | (1) 二进制转换为十进制: 14 | 15 | $101001_2 = 1 + 2^3 + 2^5 = 41_{10}$ 16 | 17 | $001101_2 = 1 + 2^2 + 2^3 = 13_{10}$ 18 | 19 | $01011010_2 = 2 + 2^3 + 2^4 +2^6 = 90_{10}$ 20 | 21 | $0000111010000101_2 = 1 + 2^2 + 2^7 + 2^9 + 2^{10} + 2^{11} = 3717_{10}$ 22 | 23 | (2) 十进制转换为二进制: 24 | 25 | $42_{10} = 2 + 2^3 + 2^5 = 101010_2$ 26 | 27 | $79_{10} = 1 + 2 + 2^2 + 2^3 + 2^6 = 1001111_2$ 28 | 29 | $811_{10} = 1 + 2 + 2^3 + 2^5 + 2^8 + 2^9 = 1100101011_2$ 30 | 31 | $374_{10} = 2 + 2^2 + 2^4 + 2^5 + 2^6 + 2^8 = 101110110_2$ 32 | 33 | (3) 十六进制转换为十进制: 34 | 35 | $\text{8AE}_{16} = 8 \times 16^2 + 10 \times 16 + 14 = 2222_{10}$ 36 | 37 | $\text{C18D}_{16} = 12 \times 16^3 + 1 \times 16^2 + 8 \times 16 + 13 = 49549_{10}$ 38 | 39 | $\text{B379}_{16} = 11 \times 16^3 + 3 \times 16^2 + 7 \times 16 + 9 = 45945_{10}$ 40 | 41 | $\text{100}_{16} = 1 \times 16^2 = 256_{10}$ 42 | 43 | (4) 十进制转换为十六进制: 44 | 45 | $81783_{10} = 1 \times 16^4 + 3 \times 16^3 + 15 \times 16^2 + 7 \times 16 + 16 = \text{13F77}_{16}$ 46 | 47 | $1922_{10} = 7 \times 16^2 + 8 \times 16 + 2 = 782_{16}$ 48 | 49 | $345208_{10} = 5 \times 16^4 + 4 \times 16^3 + 4 \times 16^2 + 7 \times 16 + 8 = 54478_{16}$ 50 | 51 | $5756_{10} = 1 \times 16^3 + 6 \times 16^2 + 7 \times 16 + 12 = \text{167C}_{16}$ 52 | 53 | ## 8.2 54 | 请给出 $32$ 位二进制数分别视作无符号数、原码、补码时所表示的数的范围。 55 | 56 | **解** 57 | 58 | 无符号数:$0 \sim 2^{32} - 1$,即 $0 \sim 4294967295$; 59 | 60 | 原码:$-2^{31} + 1 \sim 2^{31} - 1$,即 $-2147483647 \sim 2147483647$; 61 | 62 | 补码:$-2^{31} \sim 2^{31} - 1$,即 $-2147483648 \sim 2147483647$; 63 | 64 | ## 8.3 65 | 请将下列十进制数表示为 $8$ 位原码和 $8$ 位补码,或者表明该数据会溢出:$45_{10}$、$-59_{10}$、$-128_{10}$、$119_{10}$、$127_{10}$、$128_{10}$、$0_{10}$、$-1_{10}$。 66 | 67 | **解** 68 | 69 | $8$ 位原码的表示范围是 $-2^7 + 1 \sim 2^7 -1$,即 $-127 \sim 127$;$8$ 位补码的表示范围是 $-2^7 \sim 2^7 -1$,即 $-128 \sim 127$。 70 | 71 | | 十进制数 | 二进制数 | $8$ 位原码 | $8$ 位补码 | 72 | | ----------: | ------------: | ------------------------------: | -----------: | 73 | | $45_{10}$ | $101101_2$ | $00101101_2$ | $00101101_2$ | 74 | | $-59_{10}$ | $-111011_2$ | $10111011_2$ | $11000101_2$ | 75 | | $-128_{10}$ | $-10000000_2$ | 溢出 | $10000000_2$ | 76 | | $119_{10}$ | $1110111_2$ | $01110111_2$ | $01110111_2$ | 77 | | $127_{10}$ | $1111111_2$ | $01111111_2$ | $01111111_2$ | 78 | | $128_{10}$ | $10000000_2$ | 溢出 | 溢出 | 79 | | $0_{10}$ | $0_2$ | $00000000_2$
或 $11111111_2$ | $00000000_2$ | 80 | | $-1_{10}$ | $-1_2$ | $10000001_2$ | $11111111_2$ | 81 | 82 | ## 8.4 83 | 请将下列数据分别视为原码和补码,从 $8$ 位扩展到 $16$ 位:$00101100_2$、$11010100_2$、$10000001_2$、$00010111_2$。 84 | 85 | **解** 86 | 87 | 对原码,只需在符号位后添加 $8$ 个零;对补码,只需在符号位后添加 $8$ 个符号位。 88 | 89 | | 数据 | 按原码扩展到 $16$ 位 | 按补码扩展到 $16$ 位 | 90 | | :----------: | :------------------: | :------------------: | 91 | | $00101100_2$ | $0000000000101100_2$ | $0000000000101100_2$ | 92 | | $11010100_2$ | $1000000001010100_2$ | $1111111111010100_2$ | 93 | | $10000001_2$ | $1000000000000001_2$ | $1111111110000001_2$ | 94 | | $00010111_2$ | $0000000000010111_2$ | $0000000000010111_2$ | 95 | 96 | ## 8.5 97 | 请将下列浮点数在不同进制间进行转换。 98 | 99 | (1) 十进制数转换为单精度数:$0$、$116.25$、$-4.375$。 100 | (2) 十进制数转换为双精度数:$-0$、$116.25$、$-2049.5$。 101 | (3) 单精度数转换为十进制数:$\text{0xff800000}$、$\text{0x7fe00000}$。 102 | (4) 双精度数转换为十进制数:$\text{0x8008000000000000}$、$\text{0x7065020000000000}$。 103 | 104 | **解** 105 | 106 | (1) 十进制数转换为单精度数: 107 | 108 | * $0$:其单精度数表示为 $\text{0x00000000}$(零的阶码全 $0$、尾数全 $0$,正零的符号为 $0$) 109 | 110 | * $116.25$: 111 | $116.25_{10} = 1110100.01_2 = 1.11010001 \times 2^6$, 112 | 其符号为 $0$,阶码为 $6 + 127 = 133_{10} = 10000101_2$,尾数为 $11010001000000000000000$, 113 | 故其单精度数表示为 $\text{0x42E88000}$。 114 | 115 | * $-4.375$: 116 | $-4.375_{10} = -100.011_2 = -1.00011 \times 2^2$, 117 | 其符号为 $1$,阶码为 $2 + 127 = 129_{10} = 10000001_2$,尾数为 $00011000000000000000000$, 118 | 故其单精度数表示为 $\text{0xC08C0000}$。 119 | 120 | (2) 十进制数转换为双精度数: 121 | 122 | * $-0$:其双精度数表示为 $\text{0x8000000000000000}$(零的阶码全 $0$、尾数全 $0$,负零的符号为 $1$) 123 | 124 | * $116.25$: 125 | $116.25_{10} = 1110100.01_2 = 1.11010001 \times 2^6$, 126 | 其符号为 $0$,阶码为 $6 + 1023 = 1029_{10} = 10000000101_2$,尾数为 $1101000100000000000000000000000000000000000000000000$, 127 | 故其双精度数表示为 $\text{0x405D100000000000}$。 128 | 129 | * $-2049.5$: 130 | $-2049.5_{10} = -100000000001.1_2 = -1.000000000011 \times 2^{11}$, 131 | 其符号为 $1$,阶码为 $6 + 1023 = 1029_{10} = 10000000101_2$,尾数为 $0000000000110000000000000000000000000000000000000000$, 132 | 故其双精度数表示为 $\text{0xC050030000000000}$。 133 | 134 | (3) 单精度数转换为十进制数: 135 | * $\text{0xff800000}$:二进制表示为 $11111111100000000000000000000000$ 136 | 其符号为 $1$,阶码为 $11111111_2 = 255_{10}$,尾数为 $00000000000000000000000$,(阶码全 $1$、尾数全 $0$、符号为 $1$), 137 | 故其表示的是“负无穷”。 138 | 139 | * $\text{0x7fe00000}$:二进制表示为 $01111111111000000000000000000000$ 140 | 其符号为 $0$,阶码为 $11111111_2 = 255_{10}$,尾数为 $11000000000000000000000$,(阶码全 $1$,尾数非 $0$) 141 | 故其表示的是“非数”。 142 | 143 | (4) 双精度数转换为十进制数: 144 | * $\text{0x8008000000000000}$:二进制表示为 $1000000000001000000000000000000000000000000000000000000000000000$ 145 | 其符号为 $1$,阶码为 $00000000000_2 = 0$,尾数为 $1000000000000000000000000000000000000000000000000000$, 146 | 故其表示的是 $-0.1_2 \times 2^{-216} = -0.5 \times 2^{-216}$,是一个非规格化非 $0$ 负数。 147 | 148 | * $\text{0x7065020000000000}$:二进制表示为 $0111000001100101000000100000000000000000000000000000000000000000$ 149 | 其符号为 $0$,阶码为 $11100000110_2 = 255_{10}$,尾数为 $0101000000100000000000000000000000000000000000000000$, 150 | 故其表示的是 $1.01010000001_2 \times 2^{775}$。 151 | 152 | ## 8.6 153 | 请写出下图(图略)所示晶体管级电路图的真值表,并给出对应的逻辑表达式。 154 | 155 | **解** 156 | 157 | 真值表如下: 158 | | $A$ | $B$ | $C$ | $Y$ | 159 | | :---: | :---: | :---: | :---: | 160 | | $0$ | $0$ | $0$ | $1$ | 161 | | $0$ | $0$ | $1$ | $1$ | 162 | | $0$ | $1$ | $0$ | $1$ | 163 | | $0$ | $1$ | $1$ | $0$ | 164 | | $1$ | $0$ | $0$ | $1$ | 165 | | $1$ | $0$ | $1$ | $0$ | 166 | | $1$ | $1$ | $0$ | $1$ | 167 | | $1$ | $1$ | $1$ | $0$ | 168 | 169 | 逻辑表达式为 $Y = \neg((A \lor B) \land C)$。 170 | 171 | ## 8.7 172 | 请写出下图(图略)所示逻辑门电路图的真值表。 173 | 174 | **解** 175 | 176 | 真值表如下: 177 | | $A$ | $B$ | $C$ | $Y$ | 178 | | :---: | :---: | :---: | :---: | 179 | | $0$ | $0$ | $0$ | $1$ | 180 | | $0$ | $0$ | $1$ | $1$ | 181 | | $0$ | $1$ | $0$ | $1$ | 182 | | $0$ | $1$ | $1$ | $0$ | 183 | | $1$ | $0$ | $0$ | $1$ | 184 | | $1$ | $0$ | $1$ | $0$ | 185 | | $1$ | $1$ | $0$ | $1$ | 186 | | $1$ | $1$ | $1$ | $0$ | 187 | 188 | 逻辑表达式为 $Y = \neg((A \lor B) \land C)$。 189 | 190 | ## 8.8 191 | 请用尽可能少的而输入 NAND 门搭建出一个具有二输入 XOR 功能的电路。 192 | 193 | **解** 194 | 195 | 由于 196 | $$A \oplus B = (A \land \neg B) \lor (\neg A \land B) 197 | = (A \land (\neg A \lor \neg B)) \lor (B \land (\neg A \lor \neg B))$$ 198 | 199 | 200 | 201 | 可得最终电路如图。 202 | 203 | 204 | 205 | ## 8.9 206 | 请用 D 触发器和常见组合逻辑门搭建出一个具有同步复位为 $0$ 功能的触发器的电路。 207 | 208 | **解** 209 | 210 | 如图。 211 | 212 | 213 | 214 | ## 8.10 215 | 证明 $[X + Y]_\text{补} = [X]_\text{补} + [Y]_\text{补}$。 216 | 217 | **解** 218 | 219 | 证明如下: 220 | 221 | 根据补码的定义,有: 222 | $$ 223 | [X + Y]_\text{补} = 2^n + (X + Y) \pmod{2^n}\\ 224 | [X]_\text{补} = 2 ^ n + X \pmod{2^n}\\ 225 | [Y]_\text{补} = 2 ^ n + Y \pmod{2^n}\\ 226 | $$ 227 | 228 | 在模 $2^n$ 意义下,可向等号右边加 $2^n$,则有: 229 | $$ 230 | [X + Y]_\text{补} = (2 ^ n + X) + (2 ^ n + Y) = [X]_\text{补} + [Y]_\text{补} 231 | $$ 232 | 233 | 得证。 234 | 235 | ## 8.11 236 | 证明 $[X - Y]_\text{补} = [X]_\text{补} + [-Y]_\text{补}$。 237 | 238 | **解** 239 | 240 | 证明如下: 241 | 242 | 根据补码的定义,有: 243 | $$ 244 | [X - Y]_\text{补} = 2^n + (X - Y) \pmod{2^n}\\ 245 | [X]_\text{补} = 2 ^ n + X \pmod{2^n}\\ 246 | [-Y]_\text{补} = 2 ^ n + (-Y) \pmod{2^n}\\ 247 | $$ 248 | 249 | 在模 $2^n$ 意义下,可向等号右边加 $2^n$,则有: 250 | $$ 251 | [X - Y]_\text{补} = (2 ^ n + X) + (2 ^ n + (-Y)) = [X]_\text{补} + [-Y]_\text{补} 252 | $$ 253 | 254 | 得证。 255 | 256 | ## 8.12 257 | 假设每个“非门”、“与非门”、“或非门”的扇入不超过 $4$ 个且每个门的延迟为 $T$,请给出下列不同实现的 $32$ 位加法器的延迟。 258 | 259 | (1) 行波进位加法器; 260 | (2) $4$ 位一块且块内并行、块间串行的加法器; 261 | (3) $4$ 位一块且块内并行、块间并行的加法器。 262 | 263 | **解** 264 | 265 | (1) 行波进位加法器: 266 | 267 | * 从最低位的输入 $A_0$、$B_0$、$C_\text{in}$ 到最高位的进位输出 $C_\text{out}$ 的延迟为 $2 \times T \times 32 = 64T$; 268 | * 从最低位的输入 $A_0$、$B_0$、$C_\text{in}$ 到最高位的进位输入 $C_\text{31,in}$ 的延迟为 $2 \times T \times (32 - 1) = 62T$; 269 | * 从最高位的输入 $A_{31}$、$B_{31}$、$C_\text{31,in}$ 到最高位的加和输出 $S_{31}$ 的延迟为 $3T$; 270 | * 故从最低位的输入 $A_0$、$B_0$、$C_\text{in}$ 到最高位的加和输出 $S_{31}$ 的延迟为 $62T + 3T = 65T$。 271 | 272 | (2) $4$ 位一块且块内并行、块间串行的加法器: 273 | * 在逻辑门扇入不超过 $4$ 个的情况下,块内并行的 $4$ 位先行进位逻辑的 $c_4$ 延迟为 $4T$(需要将五输入与非门改造为与非门、或非门、非门的串联),$c_{1-3}$ 延迟为 $2T$。 274 | * 从最低进位 $c_0$ 到最高位进位输出 $c_{16}$ 的延迟为 $8 \times 4T = 32T$; 275 | * 从最低进位 $c_0$ 到最高位进位输入 $c_{15}$ 的延迟为 $7 \times 4T + 2T = 30T$; 276 | * 从最高位进位输入 $c_{15}$ 到最高位加和结果 $s_{31}$ 的延迟为 $3T$; 277 | * 故最低进位 $c_\text{in}$ 到最高位的加和输出 $s_{31}$ 的延迟为 $33T$。 278 | * 生成 $p_i$、$g_i$ 的延迟为 $2T$ 279 | * 加法器的总延迟为 $35T$。 280 | 281 | (3) $4$ 位一块且块内并行、块间并行的加法器。 282 | * 从 $p_i$、$g_i$ 生成下层各块的 $P$、$G$ 需要 $2T$,中层从 $p_i$、$g_i$ 生成中层各块的 $P$、$G$ 需要 $2T$,上层生成 $c_{1-3}$ 需要 $2T$,中层生成 $c_{1-3}$ 需要 $2T$,下层生成 $c_{1-3}$ 需要 $2T$; 283 | * 进位生成总共需要 $10T$ 时间 284 | * 进位生成前生成 $p$、$g$ 需要 $2T$; 285 | * 进位生成后全加器需要 $3T$; 286 | * 加法器的总延迟为 $15T$。 287 | 288 | ## 8.13 289 | 作为设计者,在什么情况下会使用行波进位加法器而非先行进位加法器? 290 | 291 | **解** 292 | 293 | 行波进位加法器所需门的数量远小于先行进位加法器,但延时远大于先行进位加法器。 294 | 295 | 因而在逻辑资源有限、对延时要求较低的条件下,会采用行波进位加法器而非先行进位加法器。 296 | 297 | ## 8.14 298 | 299 | 请利用图 8.21 所示的 $4$ 位先行进位逻辑组件出块内并行且块间并行的 $64$ 位先行进位加法器的进位逻辑,并证明其正确性。 300 | 301 | ## 8.15 302 | 303 | 请举例说明 $[X \times Y]_\text{补} \neq [X]_\text{补} \times [Y]_\text{补}$。 304 | 305 | **解** 306 | 307 | 考虑 $4$ 位补码相乘得到 $8$ 位补码,$X = -6$,$Y = -7$,则 $X \times Y = 42$。 308 | 309 | 那么 $[X]_\text{补} = 1010_2$,$[Y]_\text{补} = 1001_2$,$[X \times Y]_\text{补} = 00101010_2$。 310 | 311 | 但是 $[X]_\text{补} \times [Y]_\text{补} = 01011010_2 \pmod{2^4}$,故 $[X \times Y]_\text{补} \neq [X]_\text{补} \times [Y]_\text{补}$。 312 | 313 | ## 8.16 314 | 315 | 请证明 $[X \times 2^n]_\text{补} = [X]_\text{补} \times 2^n$ 316 | 317 | **解** 318 | 319 | 考虑 $k$ 位补码的情况 320 | 321 | 根据补码定义 322 | $$ 323 | [X \times 2^n]_\text{补} = 2^k + X \times 2^n \pmod{2^k}\\ 324 | [X]_\text{补} \times 2^n = (2^k + X)\times 2^n = 2^n \times 2^k + X \times 2^n = 2^k + X \times 2^n \pmod{2^k} 325 | $$ 326 | 故 327 | $$ 328 | [X \times 2^n]_\text{补} = [X]_\text{补} \times 2^n 329 | $$ 330 | 331 | ## 8.17 332 | 假设每个“非门”、“与非门”、“或非门”的扇入不超过 $4$ 个且每个门的延迟为 $T$,请给出下列不同实现将 $4$ 个 $16$ 位数相加的延迟。 333 | 334 | (1) 使用多个先行进位加法器; 335 | (2) 使用华莱士树及先行进位加法器。 336 | 337 | **解** 338 | 339 | (1) 使用多个先行进位加法器: 340 | * 搭建加法树,共需 $2$ 级先行进位加法器延迟,每级先行进位加法器延迟为 $11T$,故总延迟为 $22T$。 341 | 342 | (2) 使用华莱士树及先行进位加法器: 343 | * 华莱士树将 $4$ 个 $16$ 位数相加转换为 $2$ 个 $16$ 位数相加,其延迟为 $6T$; 344 | * 两个数相加需要 $1$ 级先行进位加法器,其延迟为 $11T$ 345 | * 故总延迟为 $17T$ 346 | 347 | ## 8.20 348 | 单精度和双精度浮点数能表示无理数 $\pi$ 吗?为什么? 349 | 350 | **解** 351 | 352 | 单精度、双精度浮点数无法精确的表示无理数 $\pi$。 353 | 354 | 单精度、双精度浮点数本质上是有限小数,不能表示无限不循环小数 $\pi$。但在实际应用中,可以用单精度、双精度浮点数表示 $\pi$ 的近似值。 -------------------------------------------------------------------------------- /assignment_ch8/图片2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch8/图片2.png -------------------------------------------------------------------------------- /assignment_ch8/图片3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch8/图片3.png -------------------------------------------------------------------------------- /assignment_ch9/main.md: -------------------------------------------------------------------------------- 1 | # 计算机体系结构基础 - 第 9 章作业 2 | 3 | ## 9.1 4 | 请给出下列程序在多周期处理器(如图 9.4 所示)上执行所需要的时钟周期数,并给出前三次循环执行的时空图。 5 | ``` 6 | addiu t0, $0, 100 7 | LOOP: 8 | bne t0, $0, LOOP 9 | addiu t0, t0, -1 10 | ``` 11 | 12 | **解** 13 | 14 | 程序后两行执行 $101$ 次(`t0` 从 $100$ 递减到 $0$),程序共需要执行 203 条指令,每条指令需要 5 个时钟周期,故共需要 $203 \times 5 = 1015$ 个时钟周期。 15 | 16 | 前三次循环执行的时空图如下: 17 | 18 | 19 | 20 | 21 | ## 9.2 22 | 请给出题 1 中的程序在单发射 5 级静态流水线处理器(如图 9.6 所示)上执行所需要的时钟周期数,并给出前三次循环执行的流水线时空图。 23 | 24 | **解** 25 | 26 | 第一条指令执行需要 $5$ 个周期,程序后两行循环一次需要 $5$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 101 \times 5 = 510$ 个时钟周期。 27 | 28 | 前三次循环执行的时空图如下: 29 | 30 | 31 | 32 | 33 | ## 9.3 34 | 请给出题 1 中的程序在包含前递机制的单发射 5 级静态流水线处理器(如图 9.13 所示)上执行所需要的时钟周期数,并给出前三次循环执行的流水线时空图。 35 | 36 | **解** 37 | 38 | (1) 若采用课本上给出的前递机制(即当前指令的译码级需要在下一拍才能拿到上一条指令的执行级的前递数据,可能需要阻塞): 39 | 40 | 第一条指令执行需要 $5$ 个周期,程序后两行循环一次需要 $3$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 101 \times 3 = 308$ 个时钟周期。 41 | 42 | 前三次循环执行的时空图如下: 43 | 44 | 45 | 46 | (2) 若采用幻灯片课件上给出的前递机制,(即当前指令的译码级可以在当拍能拿到上一条指令的执行级的前递数据,不需要阻塞): 47 | 48 | 第一条指令执行需要 $5$ 个周期,程序后两行第 $1$ 次循环需要 $2$ 个周期,此后的循环需要 $3$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 2 + 100 \times 3 = 307$ 个时钟周期。 49 | 50 | 前三次循环执行的时空图如下: 51 | 52 | 53 | 54 | (3)若引入译码时对转移指令的计算,利用分支延迟槽消除阻塞: 55 | 56 | 第一条指令执行需要 $5$ 个周期,程序后两行循环一次需要 $2$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 101 \times 2 = 207$ 个时钟周期。 57 | 58 | 前三次循环执行的时空图如下: 59 | 60 | 61 | 62 | 63 | ## 9.4 64 | 请给出题 1 中的程序在包含前递机制的双发射 5 级静态流水线处理器(如图 9.16 所示)上执行所需要的时钟周期数,并给出前三次循环执行的流水线时空图。 65 | 66 | **解** 67 | 68 | (1) 若采用课本上给出的前递机制(即当前指令的译码级需要在下一拍才能拿到上一条指令的执行级的前递数据,可能需要阻塞): 69 | 70 | 第一条指令执行需要 $5$ 个周期,程序后两行循环一次需要 $5$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 101 \times 5 = 510$ 个时钟周期。 71 | 72 | 前三次循环执行的时空图如下: 73 | 74 | 75 | 76 | (2) 若采用幻灯片课件上给出的前递机制,(即当前指令的译码级可以在当拍能拿到上一条指令的执行级的前递数据,不需要阻塞): 77 | 78 | 第一条指令执行需要 $5$ 个周期,程序后两行循环一次需要 $4$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 101 \times 4 = 409$ 个时钟周期。 79 | 80 | 前三次循环执行的时空图如下: 81 | 82 | 83 | 84 | (3)若引入译码时对转移指令的计算,利用分支延迟槽消除阻塞: 85 | 86 | 第一条指令执行需要 $5$ 个周期,程序后两行循环一次需要 $3$ 个周期,共循环 $101$ 次(`t0` 从 $100$ 递减到 $0$),故共需要 $5 + 101 \times 3 = 308$ 个时钟周期。 87 | 88 | 前三次循环执行的时空图如下: 89 | 90 | 91 | 92 | 可以注意到,双发射处理器的理论运算速度并不如单发射快。双发射处理器为了简化流水线控制,要求“只有同一级流水线的两条指令都不被更早的指令阻塞时,才能让这两条指令一起执行”,这样引入的陪同阻塞,造成了执行效率的下降。 93 | 94 | ## 9.5 95 | 请问要如何改进本章所述单发射静态 5 级流水线处理器的流水线功能定义,才能仅利用 MIPS 的分支指令延迟槽技术就能消除因控制相关所引入的流水线阻塞? 96 | 97 | **解** 98 | 99 | 本章所述的单发射静态 5 级流水线处理器对跳转指令的处理,是在执行级完成的。 100 | 101 | 如果希望仅利用 MIPS 的分支指令延迟槽技术就能消除因控制相关所引入的流水线阻塞,则需要将跳转指令的处理提前到译码级完成。具体来说,需要在译码级添加跳转地址计算、跳转条件判断的相关逻辑。这样的话,当跳转指令完成译码级进入执行级时,跳转地址计算已经完成。此时,分支延迟槽指令进入译码级,而跳转后的指令进入取值级,可以直接获得跳转地址而不用阻塞。 102 | 103 | 相关时空图可参见 9.3 题的图 3。 104 | 105 | ## 9.6 106 | 请在图 9.13 的基础上添加必要的逻辑,使其能够实现精确异常的功能。画出修改后的处理器结构图,并进行解释。 107 | 108 | **解** 109 | 110 | 修改后的处理器结构图入下: 111 | 112 | 113 | 114 | 为每一级寄存器增加异常信息的存储部分。在写回级,增加修改状态寄存器、记录异常处理PC等的逻辑。为取指级增加选择异常处理程序入口地址的数据选择器。 115 | 116 | 117 | ## 9.7 118 | 图 9.13 中指令存储器和数据存储器的 SRAM 都采用了异步读形式,如果将指令存储器和数据存储器的 SRAM 调整为同步读形式,请问处理器的结构将如何调整?画出修改后的处理器结构图,并进行解释。 119 | 120 | **解** 121 | 122 | SRAM 调整为同步读后,需要在取指级、访存级前一级向存储器发出读地址信号。对取指级来说,需要在更新 PC 的同时发出读地址信号;对于访存级来说,需要在执行级计算出访存地址后发出读地址信号。修改主要围绕这两个要求添加相关逻辑。 123 | 124 | 修改后的处理器结构图入下: 125 | 126 | 127 | 128 | ## 9.8 129 | 请问数据相关分为哪几种?静态流水线处理器是如何解决这几种相关的?采用寄存器重命名的动态流水线是如何解决这几种相关的? 130 | 131 | **解** 132 | 133 | 分为 3 种:写后读(RAW)、写后写(WAW)、读后写(WAR)。 134 | 135 | 静态流水线中,只会出现写后读(RAW),而不会出现写后写(WAW)、读后写(WAR)。写后读(RAW)最基本的处理方法是阻塞,即在之前的相关指令完成写入之前,将后续相关指令阻塞在译码级。还可以采用前递技术,将已经计算出但还未写会的结果传递给译码级。 136 | 137 | 动态流水线中,写后读(RAW)通过动态调度来解决,将存在写后读相关指令阻塞于保留站中;写后写(WAW)、读后写(WAR)则通过寄存器重命名技术实现,引入新的空闲寄存器来避免冲突。 138 | 139 | ## 9.9 140 | 假设在包含前递机制的单发射 5 级流水线处理器(如图 9.13 所示)的译码级添加了一个永远预测跳转的静态分支预测器,那么题 1 中的程序在这个处理器上执行需要花费多少时钟周期? 141 | 142 | **解** 143 | 对于题 1 中的程序,前 100 次 bne 指令为跳转,最后一次 bne 指令为不跳转,分支预测器绝大多数时间是正确的。在这样的情况下,跳转后的指令 bne 不需要阻塞到上一条跳转指令的执行级后才开始取指,可以提前一拍。但是,由于 bne 与分支延迟槽中的 addiu 存在相关,又会在译码级阻塞一拍。这导致了每轮循环的时钟周期没有发生改变,仍花费 308 个时钟周期。 144 | 145 | ## 9.10 146 | 假设程序动态执行过程中 load、store 指令占 $40\%$。现在有两种数据 Cache 的设计方案,其中第一种的 Cache 容量小于第二种方案,因此采用第一种方案的 Cache 命中率为 $85\%$,第二种方案的 Cache 命中率为 $95\%$,但是采用第二种方案时处理器的主频会比第一种低 $10\%$。请问那种设计方案性能更优?(假设 Cache 不命中情况下会阻塞流水线 100 个时钟周期。) 147 | 148 | **解** 149 | 150 | 考虑有 $N$ 条指令的程序,第一种方案的主频是 $f$: 151 | * 根据题意,第二种方案的主频是 $(1 - 10\%) \times f = 0.9 f$: 152 | * load、store 指令共 $40\% \times 10 = 0.4 N$ 条; 153 | * 第一种方案所需的时钟周期数:$0.4 N \times (1-85\%) \times 100 + N = 7N$; 154 | * 第二种方案所需的时钟周期数:$0.4 N \times (1-95\%) \times 100 + N = 3N$; 155 | * 第一种方案所需时间:$7N / f = 7 N/f$; 156 | * 第二种方案所需时间:$3N / 0.9f = 3.33 N/f$。 157 | 158 | 综上,第二种方案性能更优。 -------------------------------------------------------------------------------- /assignment_ch9/图片1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片1-1.png -------------------------------------------------------------------------------- /assignment_ch9/图片1-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片1-2.png -------------------------------------------------------------------------------- /assignment_ch9/图片1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片1.png -------------------------------------------------------------------------------- /assignment_ch9/图片2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片2-1.png -------------------------------------------------------------------------------- /assignment_ch9/图片2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片2.png -------------------------------------------------------------------------------- /assignment_ch9/图片3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片3-1.png -------------------------------------------------------------------------------- /assignment_ch9/图片3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片3-2.png -------------------------------------------------------------------------------- /assignment_ch9/图片3-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片3-3.png -------------------------------------------------------------------------------- /assignment_ch9/图片3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片3.png -------------------------------------------------------------------------------- /assignment_ch9/图片4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片4-1.png -------------------------------------------------------------------------------- /assignment_ch9/图片4-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片4-2.png -------------------------------------------------------------------------------- /assignment_ch9/图片4-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片4-3.png -------------------------------------------------------------------------------- /assignment_ch9/图片4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片4.png -------------------------------------------------------------------------------- /assignment_ch9/图片5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片5.png -------------------------------------------------------------------------------- /assignment_ch9/图片6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cebarobot/Introduction-to-Computer-Architecture-Exercises/4bb7f5d4e4cb71156bccb1aadf8263de1a4c54be/assignment_ch9/图片6.png --------------------------------------------------------------------------------