重构目录层次

0-课程笔记
1-平时作业
2-实验报告
3-期末大作业
This commit is contained in:
2024-09-02 18:29:19 +08:00
parent b2fb901612
commit 5906ac1efc
108 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
\usepackage{amssymb, amsfonts, amstext, amsmath, amsopn, amsthm}
\usepackage{booktabs}
\usepackage[framemethod=TikZ]{mdframed}
% \usepackage[tikz]{bclogo}
\usepackage{fontawesome5}
\usepackage{tabularx}
\usepackage{array}
\usepackage{ragged2e}
\usepackage{bm}
\usepackage{hyperref}
\usepackage{fancyhdr}
\usepackage{enumitem}
\usepackage{totpages}
\usepackage{mylatex}
\usepackage{subfiles}
\title{《计算机系统结构》作业}
\author{岳锦鹏}
\newcommand{\mysignature}{10213903403 岳锦鹏}
\date{2024年3月17日——2024年6月18日}
\setlist[1]{listparindent=\parindent}
\setlist[2]{label=\alph{enumii}.,listparindent=\parindent}
\definecolor{shadecolor}{RGB}{204,232,207}
\definecolor{verificationColor}{RGB}{85,206,255} % 这颜色误差确实有点大啊,目前手动调的
\newcommand{\complicateditem}[3]{
\item[\textbf{#1}] [#2]<#3>
}
\renewcommand{\questionandanswer}[3][]{%
\begin{shaded}%
\ifstrequal{#1}{-}{}{\item[\textbf{#1}]} #2%
\end{shaded}%
\begin{zhongwen}%
#3%
\end{zhongwen}%
}
\newmdenv[%
frametitle={%
\tikz[]
\node[anchor=east,rectangle,fill=verificationColor]
{ \faIcon{search}\ 验证一下};}, %
% frametitlerule=true, %
% frametitlebelowskip=10pt, %
roundcorner=5pt, %
innertopmargin=10pt,linecolor=verificationColor,%
linewidth=2pt,topline=true, %
frametitleaboveskip=\dimexpr-\ht\strutbox\relax,
]{verification}
% \newenvironment{verification}{
% \begin{bclogo}[couleur=verificationColor, arrondi =0.1 , logo=\bcloupe, noborder=true]{验证一下}
% }{
% \end{bclogo}
% }
\usemintedstyle{staroffice} % 虽然这个没有颜色区分操作符与操作数,但是对于数字的强调很重要,因为汇编中的这些立即数都是比较重要,同时注释的字体也比较正常没有花体
% 该命令用于控制 p{} 的情况
\newcolumntype{P}[1]{>{\RaggedRight\hspace{0pt}}p{#1}} % 使用过程中将p{4cm}换成P{4cm},小写改成大写即可!
% 该命令用于控制 X 的情况
\newcolumntype{Z}{>{\centering\let\newline\\\arraybackslash\hspace{0pt}}X} % 使用过程中将Z 换成 X即可
\let\kaishu\relax % 清除旧定义
\newCJKfontfamily\kaishu{KaiTi}[AutoFakeBold] % 重定义 \kaishu
\newcommand{\boldkai}[1]{{\bfseries\kaishu #1}}

View File

@@ -0,0 +1,5 @@
\pagestyle{fancyplain}
\fancyhead{}
\fancyhead[C]{\mysignature}
\fancyfoot[C]{\thepage\quad\ref{TotPages}}
% \definecolor{shadecolor}{named}{white}

View File

@@ -0,0 +1,12 @@
\documentclass[a4paper]{ctexbook}
\input{mypreamble}
\begin{document}
\maketitle
\tableofcontents
\subfile{第一章作业}
\subfile{第二章作业}
\subfile{第三章作业}
\subfile{第四章作业}
\subfile{第五章作业1}
\subfile{第五章作业2}
\end{document}

View File

@@ -0,0 +1,178 @@
\documentclass[全部作业]{subfiles}
\input{mysubpreamble}
\begin{document}
\chapter{计算机抽象及相关技术}
\begin{enumerate}
\questionandanswer[1.3]{
[ 2 ]<1.3>请描述高级语言(例如C)编写的程序转化为能够直接在计算机处理器上执行的表示的具体步骤。
}{
高级语言通过编译器编译型的高级语言如C、C++或解释器解释型的高级语言如Python、JavaScript转化成指令再转化成二进制的机器码或者直接转化成二进制的机器码不同的硬件对应的机器码可能不同机器码就是能够直接在计算机处理器上执行的表示。
}
\questionandanswer[1.5]{
[ 4 ]<1.6>有3种不同的处理器P1、P2和P3执行同样的指令系统。P1的时钟频率为3GHz,CPI为1.5;P2的时钟频率为2.5GHzCPI为1.0;P3的时钟频率为4GHz,CPI为2.2。
}{}
\begin{enumerate}
\questionandanswer[-]{
\item 以每秒执行的指令数为标准,哪个处理器性能最高?
}{
\noindent
P1$\frac{3 \text{GHz}}{1.5\text{时钟周期数/指令}}=2\times 10^{9}$\\
P2$\frac{2.5\text{GHz}}{1.0\text{时钟周期数/指令}}=2.5\times 10^{9}$\\
P3$\frac{4\text{GHz}}{2.2\text{时钟周期数/指令}}\approx 1.818\times 10^{9}$\\
所以处理器P2性能最高。
}
\questionandanswer[-]{
\item 如果每个处理器执行一个程序都花费10秒时间求它们的时钟周期数和指令数。
}{
\begin{tabular}{ccc}
\toprule
& 时钟周期数 & 指令数 \\
\midrule
P1 & $3\text{GHz}\times 10s=30\times 10^{9}$ & $\frac{30\times 10^{9}}{1.5}=20\times 10^{9}$ \\
P2 & $2.5\text{GHz}\times 10s=25\times 10^{9}$ & $\frac{25\times 10^{9}}{1.0}=25\times 10^{9}$ \\
P3 & $4\text{GHz}\times 10s=40\times 10^{9}$ & $\frac{40\times 10^{9}}{2.2}\approx 18.1818\times 10^{9}$ \\
\bottomrule
\end{tabular}
}
\questionandanswer[-]{
\item 我们试图把执行时间减少30\%但这会引起CPI增大20\%。请问为达到时间减少30\%的目标,时钟频率应达到多少?
}{
$$
\text{执行时间}\times 70\% = \text{指令数}\times (\text{CPI}\times 120\%) / \text{时钟频率}
$$
$$
\text{时钟频率}=\frac{\text{指令数}\times \text{CPI}}{\text{执行时间}}\times \frac{1.2}{0.7} \approx 1.714 \times \text{原始时钟频率}
$$
所以时钟频率要达到原始时钟频率的大约$1.714$倍。
}
\end{enumerate}
\questionandanswer[1.6]{
[ 20 ]<1.6>同一个指令系统体系结构有两种不同的实现方式。根据CPI的不同将指令分成四类(A、B、C和D)。P1的时钟频率为2.5GHzCPI分别为1、2、3和3;P2时钟频率为3GHzCPI分别为2、2、2和2。\\
给定一个程序,有$1.0\times 10^{6}$条动态指令按如下比例分为4类:A10\%;B20\%;C50\%;D20\%
}{}
\begin{enumerate}
\questionandanswer[-]{
\item 每种实现方式下的整体CPI是多少?
}{
P1$1\times 10\%+2\times 20\%+3\times 50\%+3\times 20\% = 2.6$\\
P2$2$
}
\questionandanswer[-]{
\item 计算两种情况下的时钟周期总数。
}{
P1$1.0\times 10^{6}\times 2.6 = 2.6\times 10^{6}$\\
P2$1.0\times 10^{6}\times 2=2\times 10^{6}$
}
\end{enumerate}
\questionandanswer[1.7]{
[ 15 ]<1.6>编译器对应用程序性能有极深的影响。假定对于一
个程序,如果采用编译器A
动态指令数为$1.0\times 10^{9}$执行时间为1.1s;如果采用编译器B则动态指令数为$1.2\times 10^{9}$执行时间为1.5s。
}{}
\begin{enumerate}
\questionandanswer[-]{
\item 在给定处理器时钟周期长度为1ns时求每个程序的平均CPI。
}{
编译器A$\frac{1.1s}{1\times 10^{-9} s}/1.0\times 10^{9}=1.1$\\
编译器B$\frac{1.5s}{1\times 10^{-9} s}/1.2\times 10^{9}=1.25$
}
\questionandanswer[-]{
\item 假定被编译的程序分别在两个不同的处理器上运行。如果这两个处理器的执行时间相同求运行编译器A生成之代码的处理器时钟比运行编译器B生成之代码的处理器时钟快多少。
}{
% 相同处理器时执行时间分别为1.1s和1.5s,那么相同执行时间时处理器时钟的比值为:
$$
\begin{aligned}
% &\frac{处理器1时钟}{处理器2时钟}=\frac{处理器1时钟\times 执行时间}{处理器2时钟\times 执行时间}=\frac{编译器A生成代码的时钟周期数}{编译器B生成代码的时钟周期数} \\
执行时间_{A}&=执行时间_{B} \\
\frac{指令数_{A}\times CPI_{A}}{时钟频率_{A}}&=\frac{指令数_{B}\times CPI_{B}}{时钟频率_{B}} \\
\frac{时钟频率_{A}}{时钟频率_{B}}&=\frac{指令数_{A}\times CPI_{A}}{指令数_{B}\times CPI_{B}}=\frac{1.0\times 10^{9}\times 1.1}{1.2\times 10^{9}\times 1.25} = \frac{11}{15} = 0.733 \\
\end{aligned}
$$
% $$
% \frac{1.5s}{1.2s} = 1.25
% $$
所以题意应该是错了运行编译器A生成之代码的处理器时钟比运行编译器B生成之代码的处理器时钟慢$0.733$倍。
}
\questionandanswer[-]{
\item 假设开发了一种新的编译器,只需$6.0\times 10^{8}$条指令程序平均CPI为1.1。求这种新的编译器在原处理器环境下相对于原编译器A和B的加速比。
}{
记这个新的编译器为C。
$$
\frac{性能C}{性能A}=\frac{执行时间A}{执行时间C}=\frac{\frac{指令数_{A}\times CPI_{A}}{时钟频率}}{\frac{指令数_{C}\times CPI_{C}}{时钟频率}}=\frac{指令数_{A}\times CPI_{A}}{指令数_{C}\times CPI_{C}}=\frac{1.0\times 10^{9}\times 1.1}{6.0\times 10^{8}\times 1.1} = \frac{5}{3} \approx 1.667
$$
同理,
$$
\frac{性能C}{性能B}=\frac{指令数_{B}\times CPI_{B}}{指令数_{C}\times CPI_{C}}=\frac{1.2\times 10^{9}\times 1.25}{6.0\times 10^{8}\times 1.1} = \frac{25}{11} \approx 2.273
$$
所以这种新的编译器在原处理器环境下相对于原编译器A和B的加速比分别约为$1.667$$2.273$
}
\end{enumerate}
\questionandanswer[1.9]{
在某处理器中假定算术指令、load/store指令和分支指令的CPI分别是1、12和5。同时假定某程序在单个处理器核上运行时需要执行$2.56\times 10^{9}$条算术指令、$1.28\times 10^{9}$条load/store指令和$2.56\times 10^{8}$条分支指令并假定处理器的时钟频率为2GHz。
现假定程序并行运行在多核上,分配到每个处理器核上运行的算术指令和 load/store指令数目为单核情况下相应指令数目除以$0.7\times p$ ( $p$为处理器核数),而每个处理器的分支指令的数量保持不变。
}{}
\questionandanswer[1.9.1]{
[ 5 ]<1.7>求出当该程序分别运行在1、2、4和8个处理器核上的执行时间并求出其他情况下相对于单核处理器的加速比。
}{
$$
多核执行时间=\frac{指令数\times CPI}{时钟周期}=\frac{\frac{2.56\times 10^{9}}{0.7\times p}\times 1+\frac{1.28\times 10^{9}}{0.7\times p}\times 12+2.56\times 10^{8}\times 5}{2\times 10^{9}} = \frac{16 (p + 20)}{25 p} s
$$
$$
单核执行时间=\frac{指令数\times CPI}{时钟周期}=\frac{2.56\times 10^{9}\times 1+1.28\times 10^{9}\times 12+2.56\times 10^{8}\times 5}{2\times 10^{9}} = \frac{48}{5} = 9.6 s
$$
$$
多核与单核的加速比=\frac{单核执行时间}{多核执行时间}=\frac{\frac{48}{5}}{\frac{16(p+20)}{25p}} = \frac{15 p}{p + 20}
$$
\begin{center}
\begin{tabular}{ccc}
\toprule
处理器核数 & 执行时间 & 加速比 \\
\midrule
1 & 9.600 & 1.000 \\
2 & 7.040 & 1.364 \\
4 & 3.840 & 2.500 \\
8 & 2.240 & 4.286 \\
\bottomrule
\end{tabular}
\end{center}
}
\questionandanswer[1.9.2]{
[ 10 ]<1.6,1.8>如果算术指令的CPI加倍对分别运行在1、2、4和8个处理器核上的执行时间有何影响?
}{
$$
多核执行时间=\frac{\frac{2.56\times 10^{9}}{0.7\times p}\times 2+\frac{1.28\times 10^{9}}{0.7\times p}\times 12+2.56\times 10^{8}\times 5}{2\times 10^{9}} = \frac{16 (7 p + 160)}{175 p} s
$$
$$
单核执行时间=\frac{2.56\times 10^{9}\times 2+1.28\times 10^{9}\times 12+2.56\times 10^{8}\times 5}{2\times 10^{9}} = \frac{272}{25} = 10.88 s
$$
\begin{center}
\begin{tabular}{ccc}
\toprule
处理器核数 & 之前的执行时间 & 现在的执行时间 \\
\midrule
1 & 9.600 & 10.880 \\
2 & 7.040 & 7.954 \\
4 & 3.840 & 4.297 \\
8 & 2.240 & 2.469 \\
\bottomrule
\end{tabular}
\end{center}
}
\questionandanswer[1.9.3]{
[ 10 ]<1.6,1.8>如果要使单核处理器的性能与四核处理器相当,单处理器中 load/store指令的CPI应该降低多少?此处假定四核处理器的CPI保持原数值不变。
}{
设单处理器中 load/store指令的CPI应该降低到原CPI的$x$倍。
$$
\begin{aligned}
单核处理器CPI降低的执行时间&=四核处理器原CPI的执行时间 \\
\frac{2.56\times 10^{9}\times 1+1.28\times 10^{9}\times 12x+2.56\times 10^{8}\times 5}{2\times 10^{9}} &= \frac{16 \times (4 + 20)}{25 \times 4} \\
\frac{192 x}{25} + \frac{48}{25} &= \frac{96}{25} \\
\end{aligned}
$$
$$
x = \frac{96-48}{192} = \frac{1}{4} = 0.25
$$
所以单处理器中 load/store指令的CPI应该降低到原CPI的0.25倍,即$12\times 0.25=3$
}
\end{enumerate}
\end{document}

View File

@@ -0,0 +1,46 @@
\documentclass[全部作业]{subfiles}
\input{mysubpreamble}
\setcounter{chapter}{2}
\begin{document}
\chapter{计算机的算术运算}
\begin{enumerate}
\questionandanswer[3.7]{
[ 5 ]<3.2>假设带符号的8位十进制整数185和122以符号-数值形式存储。计算185+122。是否上溢或下溢或都没有?
}{
185 转成8位二进制为 $1011\ 1001$其最高位为1表示负数$185-256=-71$
122 转成8位二进制为 $0111\ 1010$其最高位为0表示正数。
$1011\ 1001 + 0111\ 1010 = 1\ 0011\ 0011$只有8位所以结果为$0011\ 0011$即51。符合结果$-71+122 = 51$,所以没有上溢或下溢。
}
\questionandanswer[3.22]{
[ 10 ] <3.5>如果是浮点数位模式0x0C000000表示的十进制数是什么?使用IEEE 754标准。
}{
这是32位的浮点数即单精度浮点数。根据 IEEE 754 标准即1位符号位、8位指数位、23位尾数位。
$$
\underbrace{0}_{\text{符号位}} | \underbrace{000\ 1100\ 0}_{\text{指数位}}|\underbrace{000\ 0000\ 0000\ 0000\ 0000\ 0000}_{尾数位}
$$
符号位是0表示正数指数位是$0001\ 1000$转化为十进制为24尾数位是0。
所以位模式0x0C000000表示的十进制数为
$$
(-1)^{\text{符号}}\times (1+\text{尾数})\times 2^{\text{指数}-127} = (-1)^{0}\times (1+0.0)\times 2^{24-127} = 2^{-103}
$$
}
\questionandanswer[3.23]{
[ 10 ]<3.5>假定采用IEEE 754单精度格式写出十进制数63.25的二进制表示。
}{
$$
63.25 = \frac{253}{4} = 1111\ 1101_{2} \times 2^{-2} =1.111\ 1101_{2} \times 2^{5} =(-1)^{0}\times (1+0.111\ 1101)\times 2^{132-127}
$$
根据 IEEE 754 标准单精度格式为1位符号位、8位指数位、23位尾数位132转化为8位二进制为$1000\ 0100$所以十进制数63.25的二进制表示为
$$
\underbrace{0}_{\text{符号位}}|\underbrace{100\ 0010\ 0}_{\text{指数位}}|\underbrace{111\ 1101\ 0000\ 0000\ 0000\ 0000}_{\text{尾数位}}
$$
$$
0100\ 0010\ 0111\ 1101\ 0000\ 0000\ 0000\ 0000
$$
}
\end{enumerate}
\end{document}

View File

@@ -0,0 +1,249 @@
\documentclass[全部作业]{subfiles}
\input{mysubpreamble}
\setcounter{chapter}{1}
\begin{document}
\chapter{指令:计算机的语言}
\begin{enumerate}
\questionandanswer[2.3]{
[ 5 ]<2.2,2.3>对于以下C语句请编写相应的RISC-V汇编代码。假设变量f、g、h、i和j分别分配给寄存器x5、x6、x7、x28和x29。假设数组A和B的基地址分别在寄存器x10和x11中。
\mint{C}|B[8] = A[i-j];|
}{}
{\kaishu
% 这个minted环境放到自定义的命令里好像一直会报错
这里假设数组A和B中的元素都是64位的即“双字”即8个字节。
\begin{minted}{asm}
sub x30, x28, x29 // i-j从A开始的双字偏移
slli x30, x30, 3 // (i-j)*8 从A开始的字节偏移
add x30, x30, x10 // A[i-j]的地址
ld x31, 0(x30) // 加载A[i-j]
sd x31, 64(x11) // 放到B[8]8是双字偏移转化成字节偏移就是64
\end{minted}
% 由于minted用了verbatim而verbatim的文档中有这样一句话
% You cannot use the verbatim environment inside user defined commands;
% 可以看到在自己定义的环境里无法使用minted了。
\begin{verification}
使用命令 \mintinline{shell}|riscv64-unknown-linux-gnu-gcc -S main.c -o main.s| 编译左边是C代码右边是汇编代码。
\begin{minipage}{0.5\linewidth}
\begin{minted}{C}
...
long long *A, *B, i,j;
B[8] = A[i - j];
...
\end{minted}
\end{minipage}
\begin{minipage}{0.5\linewidth}
\begin{minted}{asm}
...
ld a4,-24(s0) // 加载i
ld a5,-32(s0) // 加载j
sub a5,a4,a5
slli a5,a5,3
ld a4,-40(s0) // 加载A
add a4,a4,a5
ld a5,-48(s0) // 加载B
addi a5,a5,64
ld a4,0(a4)
sd a4,0(a5)
...
\end{minted}
\end{minipage}
比较后可以发现基本差不多但是最后一步赋值时这里先用了addi偏移64位再存储为什么不是直接64(a5)一步存储到从a5偏移64个字节的位置呢
\end{verification}
}
\questionandanswer[2.4]{
[ 10 ]<2.2,2.3>对于以下 RISC-V汇编指令相应的C语句是什么假设变量f、g、h、i和j分别分配给寄存器x5、x6、x7、x28和x29。假设数组A和B的基地址分别在寄存器x10和x11中。}{}
\begin{minted}[fontfamily=tt]{asm}
slli x30, x5, 3 // x30 = f*8
add x30, x10, x30 // x30 = &A[f]
slli x31, x6, 3 // x31 = g*8
add x31, x11, x31 // x31 = &B[g]
ld x5, 0(x30) // f = A[f]
addi x12, x30, 8 // x12 = (&f + 1) = (原始的f)&A[f + 1]
ld x30, 0(x12) // x30 = A[f + 1]
add x30, x30, x5 // x30 = f + A[f + 1] = (原始的f)A[f] + A[f + 1]
sd x30, 0(x31) // B[g] = A[f] + A[f + 1]
\end{minted}
{\kaishu
注释已写在上方因此此汇编相应的C语句如下
\mint{C}|B[g] = A[f] + A[f + 1];|
}
\questionandanswer[2.10]{
假设寄存器x5和x6分别保存值0x8000000000000000和0xD000000000000000。
}{}
\questionandanswer[2.10.1]{
[ 5 ]<2.4>以下汇编代码中x30的值是多少?
\mint{asm}|add x30, x5, x6|
}{
由于后面全是0只需要考虑最高4位二进制。x5为$8_{16}$$1000_{2}$x6为$\mathrm{D}_{16}$$1101_{2}$要注意最高位为1代表负数由于负数已按照补码方式表示所以可以直接相加。这里两个数都是负数相加后为$1\ 0101_{2}$,进位忽略,即$0101_{2}=5_{16}$此时x30的值为
$$
0 \mathrm{x} 5000000000000000
$$
}
\questionandanswer[2.10.2]{
[ 5 ]<2.4> x30中的结果是否为预期结果或者是否溢出?
}{
两个负数相加结果的最高位为0表示正数不是预期结果即产生了溢出。
}
\questionandanswer[2.10.3]{
[ 5 ]<2.4>对于上面指定的寄存器x5和x6的内容以下汇编代码中x30的值是多少?
\mint{asm}|sub x30, x5, x6|
}{
还是只考虑最高4位二进制最高位为1代表负数直接相减不方便可以先按照补码方式转换为相反数再相加按照补码方式$1101_{2}$的相反数为$0011$,因此$1000_{2}-1101_{2}=1000_{2}+0011_{2}=1011_{2}$,即$\mathrm{B}_{16}$。因此x30的值为
$$
0 \mathrm{x} \mathrm{B}000000000000000
$$
}
\questionandanswer[2.10.4]{
[ 5 ]<2.4> x30中的结果是否为预期结果或者是否溢出?
}{
两个负数相减结果仍为负数最高位是1为预期结果无溢出。
}
\questionandanswer[2.10.5]{
[ 5 ]<2.4>对于上面指定的寄存器x5和x6的内容以下汇编代码中x30的值是多少?
\mint{asm}|add x30, x5, x6|
\vspace{-1.5em}
\mint{asm}|add x30, x30, x5|
}{
第一行就是2.10.1的指令,之后执行第二行,按照最高位来看就是$0101_{2}+1000_{2}=1101_{2}$,即$\mathrm{D}_{16}$所以x30的值为
$$
0 \mathrm{xD} 000000000000000
$$
}
\questionandanswer[2.10.6]{
[ 5 ]<2.4> x30中的结果是否为预期结果或者是否溢出?
}{
结果的最高位为1虽然仍是负数但显然不是$\mathrm{x}5+\mathrm{x}6+\mathrm{x}5$的结果,所以不是预期结果,产生了溢出。
}
\questionandanswer[2.27]{
[ 5 ]<2.7>将以下循环转换为C代码。假设C语言级的整数i保存在寄存器x5中, x6保存名为result的C语言级的整数x10保存整数MemArray的基址。
}{}
\begin{minted}{asm}
addi x6, x0, 0 // result = 0
addi x29, x0, 100 // x29 = 100
LOOP: ld x7, 0(x10) // x7 = *MemArray
add x5, x5, x7 // i = i + *MemArray
addi x10, x10, 8 // MemArray++
addi x6, x6, 1 // result++
blt x6, x29, LOOP // (result < 100)
\end{minted}
{\kaishu
注释已写在上方。根据题意和命名来看, \mintinline{C}{MemArray} 应该是整数数组而不是整数吧,不然总不能 \mintinline{C}{(&MemArray)++} 吧。这里假设整数都是64位的所以 \mintinline{C}{MemArray++} 对应的汇编代码是增加8个字节\mintinline{asm}{addi x10, x10, 8 }
根据注释分析出的结果可以得到C代码
\begin{minted}{C}
for (int result = 0; result < 100; result++) {
i += *(MemArray++);
}
\end{minted}
为什么这里是 \mintinline{C}{result} 作为循环变量而 \mintinline{C}{i} 作为结果啊???但按照题意分析出来就是这样。
}
\questionandanswer[2.31]{
[ 20 ]<2.8>将函数f转换为RISC-V汇编语言。假设g的函数声明是 \mintinline{C}{int g(int a,int b)}。函数f的代码如下:
}{}
\begin{minted}{C}
int f(int a, int b, int c, int d) {
return g(g(a,b), c+d);
}
\end{minted}
{\kaishu
注意:
% \setlist[2]{label=\alph{enumii}.,listparindent=\parindent}
\begin{enumerate}[label=(\arabic{enumii})]
\item 调用函数时参数应该是从右往左计算的,但是需要保存的局部变量是从左到右保存的;
\item 栈指针应该是16字节四字对齐的
\item 返回地址应该是调用者保存的。
\end{enumerate}
\begin{minted}{asm}
f: // 保存自己要用到的保存寄存器,好像没有
// 此时a,b,c,d 分别保存在 x10, x11, x12, x13 中
addw x5, x12, x13 // 计算c+d4字节整数的要加w
addi sp, sp, -16 // 移动栈指针栈指针应该是16字节对齐的
sd x1, 8(sp) // 保存x1返回地址
sd x5, 0(sp) // 保存x5这里int类型4个字节由于对齐产生了空位
// a和b在调用g(a,b)后不会用到,所以不用保存
// ***开始计算g(a,b)
// a和b已经在x10和x11中所以不需要移动
jal x1, g // 跳转到g
// g的返回值在x10中正好是下一次调用的第一个参数
ld x11, 0(sp) // 恢复x5直接恢复到x11上避免再移动
// x1不需要着急恢复马上就是下一次调用了
// 只恢复了x5栈指针要16字节对齐不能移动
// ***开始计算g(g(a,b), c+d)
// 第二个参数已从x5恢复
// 第一个参数已经在x10中
jal x1, g // 跳转到g
// g的返回值在x10中不需要移动
ld x1, 0(sp) // 恢复x1
addi sp, sp, 16 // 恢复栈指针
// 恢复保存的保存寄存器,好像没有
jalr x0, x1 // 返回
\end{minted}
}
\vspace{2em}
\begin{verification}
使用命令 \mintinline{shell}|riscv64-unknown-linux-gnu-gcc -S main.c -o main.s| 编译。
\baselineskip=1.4em
\begin{minted}{asm}
f:
.LFB0:
.cfi_startproc
addi sp,sp,-32
.cfi_def_cfa_offset 32
sd ra,24(sp)
sd s0,16(sp)
.cfi_offset 1, -8
.cfi_offset 8, -16
addi s0,sp,32
.cfi_def_cfa 8, 0
mv a5,a0
mv a4,a3
sw a5,-20(s0)
mv a5,a1
sw a5,-24(s0)
mv a5,a2
sw a5,-28(s0)
mv a5,a4
sw a5,-32(s0)
lw a4,-24(s0)
lw a5,-20(s0)
mv a1,a4
mv a0,a5
call g
mv a5,a0
mv a3,a5
lw a5,-28(s0)
mv a4,a5
lw a5,-32(s0)
addw a5,a4,a5
sext.w a5,a5
mv a1,a5
mv a0,a3
call g
mv a5,a0
mv a0,a5
ld ra,24(sp)
.cfi_restore 1
ld s0,16(sp)
.cfi_restore 8
.cfi_def_cfa 2, 32
addi sp,sp,32
.cfi_def_cfa_offset 0
jr ra
.cfi_endproc
\end{minted}
\end{verification}
\end{enumerate}
\end{document}

View File

@@ -0,0 +1,363 @@
\documentclass[全部作业]{subfiles}
\input{mysubpreamble}
\setcounter{chapter}{4}
\begin{document}
\chapter{大而快:层次化存储}
\begin{enumerate}
\questionandanswer[5.2]{
cache对于为处理器提供高性能存储器层次结构非常重要。下面是64位存储器地址访问顺序列表以字地址的形式给出。
\mint{C}|0x03, 0xb4, 0x2b, 0x02, 0xbf, 0x58, 0xbe, 0x0e, 0xb5, 0x2c, 0xba, 0xbd|
}{}
\begin{enumerate}
\questionandanswer[5.2.1]{
[ 10 ]<5.3>对于一个有16个cache块、每个块大小为1个字的cache标识这些引用的二进制字地址、标签和索引。此外假设cache最初为空列出每个地址的访问会命中还是失效。
}{
缓存块有16个也就是$2^{4}$所以索引的大小为4个位给出的地址为两个十六进制位即8位二进制所以索引实际上就是低4位地址标签实际上是就是高4位地址是否命中只需要看在某一行之前是否出现过相同的标签和索引。
\includexopp[1.5]{5.2.1.1}
}
\questionandanswer[5.2.2]{
[ 10 ]<5.3>对于一个有8个cache块、每个块大小为2个字的cache标识这些引用的二进制字地址、标签、索引和偏移。此外假设cache最初为空列出每个地址的访问会命中还是失效。
}{
每个缓存块的大小变大了,缓存块的数量变小了,所以偏移实际上就是把索引的最低位移过来了。同样是否命中只需要看在某一行之前是否出现过相同的标签和索引,并且在这之后没有索引相同但标签不同的访问(不然就被置换了),不需要考虑偏移。这里的命中一列,不命中使用$\times $表示,而命中使用〇表示(用〇比√从视觉上更好区分)。
\includexopp[1.5]{5.2.2.1}
}
\questionandanswer[5.2.3]{
[ 20 ]<5.3,5.4>请针对给定的访问顺序优化cache设计。这里有三种直接映射cache的设计方案,每种方案都可以容纳8个字的数据:
\begin{itemize}
\item C1的块大小为1个字
\item C2的块大小为2个字
\item C3的块大小为4个字
\end{itemize}
}{
\includexopp[1.5]{5.2.3.1}
可见C2的缓存命中次数最多所以这里应该选择C2方案。
}
\end{enumerate}
\questionandanswer[5.3]{
按照惯例, cache 以它包含的数据量来进行命名例如4KiB cache可以容纳4KiB的数据但是cache还需要SRAM来存储元数据如标签和有效位等。本题研究cache的配置如何影响实现它所需的SRAM总量以及cache 的性能。对所有的部分都假设cache是字节可寻址的并且地址和字都是64位的。
}{}
\begin{enumerate}
\questionandanswer[5.3.1]{
[ 10 ]<5.3>计算实现每个块大小为2个字的32KiB cache 所需的总位数。
}{
32KiB即$2^{5}\times 2^{10}=2^{15} \text{B}$每个块大小为2个字即$2\times 64 / 8=2^{4}\text{B}$由于字节寻址所以偏移为4位共有$2^{15-4}=2^{11}$个块因此索引为11位那么地址为64位所以标签就是$64-4-11=49$有效位为1位。每个块都有一个标签和一个有效位所以SRAM存储的元数据需要$2^{11}\times (49+1) = 102400$位。再加上存储数据的$2^{15+3}$位,即\boldkai{$\bm{2^{11}\times (49+1) + 2^{15+3} = 364544}$}
}
\questionandanswer[5.3.2]{
[ 10 ]<5.3>计算实现每个块大小为16个字的64KiB cache所需的总位数。这个cache 比 5.3.1中描述的32KiB cache大多少?(请注意通过更改块大小我们将数据量增加了一倍但并不是将cache的总大小加倍。)
}{
64KiB即$2^{6}\times 2^{10}=2^{16}\text{B}$每个块的大小为16个字即$16\times 64/8=2^{7}$B所以偏移为7位。
共有$2^{16-7}=2^{9}$个块索引为9位。
标签为$64-7-9 = 48$有效位为1位。
所以需要的总位数为$2^{9}\times (48+1)+2^{16+3} = \bm{549376}$比5.3.1大了$\frac{549376-364544}{364544} = 0.507022471910112$,即约大了$\bm{50.70\%}$
}
\questionandanswer[5.3.3]{
[ 5 ]<5.3>解释为什么5.3.2中的64KiB cache尽管数据量比较大但是可能会提供比5.3.1中的cache更慢的性能。
}{
5.3.2中的64KiB cache每个块的大小比5.3.1大,所以每次缓存失效时都需要把更多的数据读入缓存或写回存储,所以失效代价会更大。而且总块数更少,所以命中率会更低。
}
\questionandanswer[5.3.4]{
[ 10 ]<5.3,5.4>生成一系列读请求这些请求需要在32KiB的两路组相联cache上的失效率低于在5.3.1中描述的cache的失效率。
}{
在5.3.1中标签49位索引11位偏移4位。若改成两路组相联那么每个块就只有1个字了且索引为10位标签为50位每个块都各自有一个标签和一个有效位。所以只需要构造索引相同的地址但是标签不同即可让5.3.1的直接映射失效,而两路组相联不失效。所以构造的读请求地址如下:\boldkai{0x00000, 0x10000, 0x00000, 0x10000, 0x00000, 0x10000, ……},前两次请求都未命中缓存,但从第三次请求开始,直接映射会一直失效,而两路组相联会一直命中,所以符合要求。
}
\end{enumerate}
\questionandanswer[5.5]{
对一个64位地址的直接映射cache的设计地址的以下位用于访问cache。
\begin{center}
\begin{tabular}{ccc}
\toprule
标签 & 索引 & 偏移 \\
\midrule
$63 \sim 10$ & $9\sim 5$ & $4\sim 0$ \\
\bottomrule
\end{tabular}
\end{center}
}{}
\begin{enumerate}
\questionandanswer[5.5.1]{
[ 5 ]<5.3>cache 块大小为多少(以字为单位)?
}{
偏移是0到4也就是5位所以cache块的大小是$2^{5}=32$B一个字是4B所以cache块的大小是\boldkai{8}个字。
}
\questionandanswer[5.5.2]{
[ 5 ]<5.3 >cache块有多少个?
}{
索引从5到9也就是5位所以cache块有$2^{5}=\bm{32}$个。
}
\questionandanswer[5.5.3]{
[ 5 ]<5.3>这种cache实现所需的总位数与数据存储位之间的比率是多少?
}{
标签是10到63也就是54位还需要一位有效位所以实现所需的总位数是$2^{5}\times (54+1)+2^{5}\times 2^{5} \times 8 = 9952$,数据存储位是$2^{5}\times 2^{5}\times 8 = 8192$。所以这种cache实现所需的总位数与数据存储位之间的比率是$\frac{9952}{8192}\times 100\% = \bm{121.484375\%}$
}
\questionandanswer[5.5.4]{
下表记录了从上电开始cache访问的字节地址。
\begin{center}
\begin{tabular}{cccccccccccccc}
\toprule
十六进制 & 00 & 04 & 10 & 84 & E8 & A0 & 400 & 1E & 8C & C1C & B4 & 884 \\
\midrule
十进制 & 0 & 4 & 16 & 132 & 232 & 160 & 1024 & 30 & 140 & 3100 & 180 & 2180 \\
\bottomrule
\end{tabular}
\end{center}
[ 20 ]<5.3>对每一次访问,列出:它的标签、索引和偏移;指出命中还是失效;替换了哪个字节(如果有的话)。
}{
\includexopp[1.5]{5.5.4.1}
图中的Address表示十六进制的地址Tag为标签,Index为索引Offset为偏移Hit列中勾表示命中叉表示失效Sub表示替换的字节地址范围。
}
\questionandanswer[5.5.5]{
[ 5 ]<5.3>命中率是多少?
}{
12次访问中有4次命中所以命中率为$\frac{1}{3} \approx \bm{33.33}\%$
}
\questionandanswer[5.5.6]{
[ 5 ]<5.3>列出cache的最终状态每个有效表项表示为<索引,标签,数据>的记录。例如:
\mint{C}|<0, 3, Mem[0xC00]-Mem[0xC1F]|
}{}
{\kaishu
对于某个索引从后往前看Index首次找到这个索引的地方所在的标签即为最终状态的标签之后把偏移全填为0再把地址转成十六进制已按4位一组用蓝色线分隔即为起始地址把偏移量全填为1再把地址转成十六机制即为结束地址。
例如对于0号索引最后一次出现是在地址C1C的地方它的标签为11也就是十六进制的3。之后看这一行的地址为 11\!|\!00 000\!|\!1 1100将偏移量全填成0也就是 11\!|\!00 000\!|\!0 0000这就是0xC00将偏移量全填成1也就是 11\!|\!00 000\!|\!1 1111这就是 0xC1F所以结果为 \mintinline{C}{<0, 3, Mem[0xC00]-Mem[0xC1F]}
所以cache的最终状态如下
\begin{minted}{C}
<0, 3, Mem[0xC00]-Mem[0xC1F]>
<4, 2, Mem[0x880]-Mem[0x89F]>
<5, 0, Mem[0x0A0]-Mem[0x0BF]>
<7, 0, Mem[0x0E0]-Mem[0x0FF]>
\end{minted}
}
\end{enumerate}
\questionandanswer[5.7]{
考虑以下的程序和cache行为:
\begin{center}
\begin{tabularx}{\linewidth}{ZZZZZ}
\toprule
每1000条指令的数据读次数 & 每1000条指令的数据写次数 & 指令cache失效率 & 数据cache失效率 & 块大小(字节) \\
\midrule
250 & 100 & 0.30\% & 2\% & 64 \\
\bottomrule
\end{tabularx}
\end{center}
}{}
\begin{enumerate}
\questionandanswer[5.7.1]{
[ 10 ]<5.3,5.8>假设一个带有写直达、写分配cache的CPU实现了2的CPI那么RAM和cache之间的读写带宽用每个周期的字节数进行测量是多少?(假设每个失效都会生成一个块的请求。)
}{
CPI为2每条指令2个周期那么每个周期就是0.5条指令,那么指令的读带宽就是$0.5\times 0.30\% \times 64 = 0.096$字节/周期,而数据的读带宽就是$0.5\times \frac{250}{1000}\times 2\%\times 64 = 0.16$字节/周期。
% $$
% 0.5\times 0.30\% \times 64 + 0.5\times \frac{250}{1000}\times 2\%\times 64 = 0.256 \text{字节/周期}
% $$
由于写直达所以不管是否失效都需要将某个寄存器的数据写入到RAM中RISC-V中的寄存器为64位也就是8个字节那么写入RAM的带宽为$0.5\times \frac{100}{1000}\times 8 = 0.4$字节/周期。
由于写分配,所以当失效时,需要先(后*将RAM中的数据放回到寄存器中这时会产生读带宽$0.5\times \frac{100}{1000}\times 2\%\times 64 = 0.064$字节/周期。
*如果先取回数据那么需要同时写入cache和RAM如果后取回数据那么就只写入RAM取回时就已经是最新的数据了。
所以总的读带宽为
$
0.096+0.16+0.064 = \bm{0.32} \text{字节/周期}
$
总的写带宽为
$
\bm{0.4} \text{字节/周期}
$
}
\questionandanswer[5.7.2]{
[ 10 ]<5.3,5.8>对于一个写回、写分配 cache来说假设替换出的数据cache块中有30\%是脏块那么为了实现CPI为2读写带宽需要达到多少?
}{
指令的读带宽仍为0.096字节/周期数据的读带宽仍为0.16字节/周期。但是这里的“写分配”似乎没用写的时候如果不失效那cache中就是最新的如果失效那先替换旧的块之后再写入cache也不会出现分配的情况。
对于写回策略当写不失效时不需要在cache与RAM中传输数据。当写失效时如果被替换的cache块是“脏”块也就是被修改过那么需要将这个块写入到RAM中。当读失效时仍然会产生cache块的替换所以如果是“脏”块也需要写入RAM。并且这里没有提及缓冲的事所以认为没有写缓冲那么写带宽为$0.5\times \left( \frac{250}{1000}+\frac{100}{1000} \right) \times 2\%\times 30\%\times 64 = 0.0672$
所以总的读带宽为$\bm{0.096}$字节/周期,总的写带宽为$\bm{0.0672}$字节/周期。
}
\end{enumerate}
\questionandanswer[5.9]{
cache块大小(B)可以影响失效率和失效延迟。假设一台机器的基本CPI为1每条指令的平均访问次数包括指令和数据为1.35给定以下各种不同cache块大小的失效率找到能够最小化总失效延迟的cache块大小。
\begin{center}
\begin{tabularx}{0.8\linewidth}{ZZZZZ}
\toprule
8:4\% & 16:3\% & 32:2\% & 64:1.5\% & 128:1\% \\
\bottomrule
\end{tabularx}
\end{center}
}{}
\begin{enumerate}
\questionandanswer[5.9.1]{
[ 10 ]<5.3>失效延迟为20$\times $B周期时,最优块大小是多少?
}{
总失效延迟为$1.35\times \text{失效率}\times 20\times B$周期,所以所求问题为
$$
\mathop{\arg\min}_{i}
\quad 1.35\times \text{失效率}_{i}\times 20\times B_i
$$
$$
\left\{ \left( B_i, \text{失效率}_{i} \right) \right\} = \{ (8,0.04), (16,0.03), (32,0.02), (64,0.015), (128,0.01) \}
$$
枚举可得
\begin{center}
\begin{tabular}{ccc}
\toprule
$B_i$ & $\text{失效率}_{i}$ & 总失效延迟 \\
\midrule
8 & 0.04 & 8.64 \\
16 & 0.03 & 12.96\\
32 & 0.02 & 17.28\\
64 & 0.015 & 25.92\\
128 & 0.01 & 34.56\\
\bottomrule
\end{tabular}
\end{center}
\boldkai{所以最优块大小是8。}
}
\questionandanswer[5.9.2]{
[10]<5.3>失效延迟为24+B周期时最优块大小是多少?
}{
总失效延迟为$1.35\times \text{失效率}\times (24+B)$周期,所以所求问题为
$$
\mathop{\arg\min}_{i}
\quad 1.35\times \text{失效率}\times (24+B)
$$
$$
\left\{ \left( B_i, \text{失效率}_{i} \right) \right\} = \{ (8,0.04), (16,0.03), (32,0.02), (64,0.015), (128,0.01) \}
$$
枚举可得
\begin{center}
\begin{tabular}{ccc}
\toprule
$B_i$ & $\text{失效率}_{i}$ & 总失效延迟 \\
\midrule
8 & 0.04 & 1.728\\
16 & 0.03 & 1.62 \\
32 & 0.02 & 1.512\\
64 & 0.015 & 1.782\\
128 & 0.01 & 2.052\\
\bottomrule
\end{tabular}
\end{center}
\boldkai{所以最优块大小是32。}
}
\questionandanswer[5.9.3]{
5.9.3[ 10 ]<5.3>失效延迟为定值时,最优块大小是多少?
}{
总失效延迟为$1.35\times \text{失效率}\times \text{定值}$,所以失效率越小,总失效延迟就越小,\boldkai{所以最优块大小是128。}
}
\end{enumerate}
\questionandanswer[5.10]{
本题研究不同cache容量对整体性能的影响。通常, cache访问时间与cache容量成正比。假设主存访问需要70ns并且在所有指令中有36\%的指令访问数据内存。下表显示了两个处理器P1和P2中每个处理器各自的L1 cache 的数据。
\begin{center}
\begin{tabular}{cccc}
\toprule
& L1大小 & L1失效率 & L1命中时间 \\
\midrule
P1 & 2 KiB & 8.0\% & 0.66 ns \\
P2 & 4 KiB & 6.0\% & 0.90 ns \\
\bottomrule
\end{tabular}
\end{center}
}{}
\questionandanswer[5.10.1]{
[ 5 ]<5.4>假设L1命中时间决定Pl和P2的时钟周期时间它们各自的时钟频率是多少?
}{
% 设P1的时钟周期频率为C1CPI为CPI
% % + C_1 \times CPI \times (1+0.36)\times 0.08 \times 70
% $$
% C_1\times CPI \times 0.36\% \times 2k = 0.66
% $$
P1$\frac{1}{0.66 \times 10^{-9}} \approx 1.515 \times 10^{9} \text{Hz}=1.515 \text{GHz}$
P2$\frac{1}{0.90 \times 10^{-9}} \approx 1.111 \times 10^{9} \text{Hz}=1.111 \text{GHz}$
}
\questionandanswer[5.10.2]{
[ 10 ]<5.4>P1和P2各自的AMAT (平均内存访问时间)是多少(以周期为单位)?
}{
这里的平均内存访问时间应该是每条指令的,而且是已知产生内存访问的情况下计算的,
% 所以应该为$36\% \times (0.66 + 8\% \times 70) \times 10^{-9}\times \frac{1}{0.66\times 10^{-9}} = 3.41454545454545$
所以为
$$
\text{P1:}\quad 1+8\% \times \left\lceil \frac{70}{0.66} \right\rceil = 9.56 \text{周期}
$$
$$
\text{P2:} \quad 1+6\%\times \left\lceil \frac{70}{0.90} \right\rceil = 5.68 \text{周期}
$$
}
\questionandanswer[5.10.3]{
[ 5 ]<5.4>假设基本CPI为1.0而且没有任何内存停顿那么P1和P2的总CPI是多少?哪个处理器更快?(当我们说“基本CPI为1.0”时意思是指令在一个周期内完成除非指令访问或者数据访问导致cache失效。)
}{
这里计算的总CPI仍然是每条指令的周期数但是并没有已知产生内存访问所以
$$
\text{P1:}\quad 1+ 8\% \times \left\lceil \frac{70}{0.66} \right\rceil +36\% \times 8\% \times \left\lceil \frac{70}{0.66} \right\rceil = 12.6416 \text{周期/指令}
$$
$$
\text{P2:} \quad 1+ 6\% \times \left\lceil \frac{70}{0.90} \right\rceil + 36\% \times 6\% \times \left\lceil \frac{70}{0.90} \right\rceil = 7.3648 \text{周期/指令}
$$
\boldkai{所以P2更快。}
}
\questionandanswer[]{
对于接下来的三个问题我们将考虑向P1添加L2 cache(可能弥补其有限的Ll cache容量)。解决这些问题时请使用上一个表中的Ll cache容量和命中时间。L2失效率表示的是其局部失效率。
\begin{center}
\begin{tabular}{ccc}
\toprule
L2大小 & L2失效率 & L2命中时间 \\
\midrule
1 MiB & 95\% & 5.62 ns \\
\bottomrule
\end{tabular}
\end{center}
}{}
\questionandanswer[5.10.4]{
[ 10 ]<5.4>添加L2 cache的P1的AMAT是多少?在使用L2 cache后,AMAT变得更好还是更差?
}{
$$
1+8\% \times \left\lceil \frac{5.62}{0.66} \right\rceil + 8\% \times 95\% \times \left\lceil \frac{70}{0.66} \right\rceil = 9.852 \text{周期}
$$
显然使用L2 cache后AMAT变得更差。
}
\questionandanswer[5.10.5]{
[ 5 ]<5.4>假设基本CPI为1.0而且没有任何内存停顿那么添加L2 cache的P1的总CPI是多少?
}{
$$
1+ 8\% \times \left\lceil \frac{5.62}{0.66} \right\rceil + 8\% \times 95\% \times \left\lceil \frac{70}{0.66} \right\rceil + 36\% \times \left( 8\% \times \left\lceil \frac{5.62}{0.66} \right\rceil + 8\% \times 95\% \times \left\lceil \frac{70}{0.66} \right\rceil \right) = 13.03872
$$
}
\questionandanswer[5.10.6]{
[ 10 ]<5.4>为了使具有L2 cache的P1比没有L2 cache的P1更快需要L2的失效率为多少?
}{
设L2的失效率最大为$x$,则
$$
1+8\% \times \left\lceil \frac{5.62}{0.66} \right\rceil + 8\% \times x \times \left\lceil \frac{70}{0.66} \right\rceil = 9.56
$$
解得
$ x = \frac{98}{107} \approx 0.9159 = 91.59\%$所以L2的失效率需要小于$91.59\%$
}
\questionandanswer[5.10.7]{
[ 15 ]<5.4>为了使具有L2 cache 的P1比没有L2 cache的P2更快需要L2的失效率为多少?
}{
设L2的失效率最大为$x$由于涉及到P1和P2所以这里需要比较的是实际的执行时间即CPI $\times $ 每条指令执行的时间由于5.10.1的假设所以每条指令执行的时间就是L1命中时间。
$$
\begin{aligned}
&\left[1+ 8\% \times \left\lceil \frac{5.62}{0.66} \right\rceil + 8\% \times x\times \left\lceil \frac{70}{0.66} \right\rceil + 36\% \times \left( 8\% \times \left\lceil \frac{5.62}{0.66} \right\rceil + 8\% \times x\times \left\lceil \frac{70}{0.66} \right\rceil \right) \right] \times 0.66 \\
&= 7.3648 \times 0.90 \\
\end{aligned}
$$
解得
$ x = \frac{27719}{40018} \approx 0.6927 = 69.27 \%
$所以L2的失效率需要小于$69.27\%$
}
\end{enumerate}
\end{document}

View File

@@ -0,0 +1,245 @@
\documentclass[全部作业]{subfiles}
\input{mysubpreamble}
\setcounter{chapter}{4}
\begin{document}
\begin{enumerate}
\questionandanswer[5.11]{
本题研究不同cache 设计的效果特别是将组相联cache 与5.4节中的直接映射cache进行比较。有关这些练习请参阅下面显示的字地址序列:
\mint{C}|0x03, 0xb4, 0x2b, 0xbe, 0x58, 0xbf, 0x0e, 0x1f, 0xb5, 0xba, 0x2e, 0xce|
}{}
\begin{enumerate}
\questionandanswer[5.11.1]{
[ 10 ]<5.4>绘制块大小为2字、总容量为48字的三路组相联cache 的组织结构图。图中应有类似于图5-18的样式还应该清楚地显示标签和数据字段的宽度。
}{
\includexopp[1.1]{5.11.1.1}
块大小为$2=2^{1}$所以地址中的偏移量为1位。$48 \div 3 \div 2 = 8$,所以索引有$8=2^{3}$所以地址中的索引有3位。所以标签为$64-3-1 = \bm{60}$位。一个字应该是32位并且块大小为2字那么数据字段就是$2\times 32 = \bm{64}$位。
}
\questionandanswer[5.11.2]{
[ 10 ]<5.4>从5.11.1中记录cache 的行为。假设cache使用LRU替换策略。对于每一次 cache访问,确定:
\begin{itemize}
\item 二进制字地址。
\item 标签。
\item 索引。
\item 偏移。
\item 访问会命中还是失效。
\item 在处理访问后cache每一路中有哪些标签。
\end{itemize}
}{
\includexopp[1.1]{5.11.2.1}
图中的Hit命中列用蓝色圈表示命中命中时在上一行会有蓝色框表示命中了哪个缓存。红色下划线表示在这一时刻产生了缓存替换标记了新的缓存放在哪个位置。
}
\questionandanswer[5.11.3]{
[ 5 ]<5.4>绘制块大小为1字、总容量为8字的全相联cache 的组织结构图。图中应有类似于图5-18的样式,还应该清楚地显示标签和数据字段的宽度。
}{
\includexopp[1.1]{5.11.3.1}
地址是按字索引的块大小是1字所以没有偏移量。由于是全相联所以没有索引位所以标签为64位。总容量为8字所以8个块排成一行。数据字段就是块大小即1字 $=$ 32位。
}
\questionandanswer[5.11.4]{
[ 10 ]<5.4>从5.11.3中记录cache的行为。假设cache使用LRU替换策略。对于每一次 cache访问,确定:
\begin{itemize}
\item 二进制字地址。
\item 标签。
\item 索引。
\item 偏移。
\item 访问会命中还是失效。
\item 在处理访问后cache每一路中有哪些标签。
\end{itemize}
}{
\includexopp[1.1]{5.11.4.1}
图中的Hit命中列用蓝色圈表示命中命中时在上一行会有蓝色框表示命中了哪个缓存。红色下划线表示在这一时刻产生了缓存替换标记了新的缓存放在哪个位置。
}
\questionandanswer[5.11.5]{
[ 5 ]<5.4>绘制块大小为2字、总容量为8字的全相联cache 的组织结构图。图中应有类似于图5-18的样式还应该清楚地显示标签和数据字段的宽度。
}{
\includexopp[1.1]{5.11.5.1}
块大小为2字所以偏移量为1位一个字是32位所以数据大小为64位。总容量为8字所以有4个块全相联所以4个块排成一行没有索引位所以标签为$64-1=63$位。
}
\questionandanswer[5.11.6]{
[ 10 ]<5.4>从5.11.5中记录cache 的行为。假设cache使用LRU替换策略。对于每一次 cache访问确定:
\begin{itemize}
\item 二进制字地址。
\item 标签。
\item 索引。
\item 偏移。
\item 访问会命中还是失效。
\item 在处理访问后cache每一路中有哪些标签。
\end{itemize}
}{
\includexopp[1.1]{5.11.6.1}
图中Tag列中的蓝色线表示4位分隔便于二进制转十六进制。Hit命中列用蓝色圈表示命中在命中时右侧的蓝色下划线表示命中了哪一路的标签同时也代表产生了一次访问相当于LRU把它放到链表最后。在未命中时右侧的红色下划线表示替换了哪一路的标签同时也代表产生了一次访问。
所以对于每一行填写方法是先把Tag转成十六进制再查看Way这里全相联就是四路组相联Way表示路中是否有这个十六进制地址如果有表示命中那就把上一行的Way复制下来并在命中的地址上划一条蓝色下划线如果没有表示未命中就从这行开始向上查看最近的哪条下划线距离最远表示最久没访问那么就替换这个地址其他地址不变替换后在这个地址上划一条红色下划线。
}
\end{enumerate}
\questionandanswer[5.12]{
多级cache是一种重要的技术可以在克服一级cache提供的有限空间的同时仍然保持速度。考虑具有以下参数的处理器:
\begin{center}
\small
\begin{tabularx}{\linewidth}{ZZZZZZZZ}
\toprule
无内存停顿的基本CPI & 处理器速度 & 主存访问时间 & 每条指令的 L1 cache 的失效率 * & L2 直接映射 cache 速度 & L2 直接映射 cache 全局失效率 & L2八路组相联速度 & L2八路组相联cache全局失效率 \\
\midrule
1.5 & 2GHz & 100ns & 7\% & 12cycles & 3.5\% & 28cycles & 1.5\% \\
\bottomrule
\end{tabularx}
*Ll cache失效率是针对每条指令而言的。假设Ll cache的总失效数量包括指令和数据为总指令数的7\%
\end{center}
}{
\textcolor{red}{\Large 这题的参考答案有误答案当成局部失效率计算了。全局失效率与局部失效率的定义在课本第290页}
}
\begin{enumerate}
\questionandanswer[5.12.1]{
[ 10 ]<5.4>使用以下方法计算表中处理器的CPI:仅有Ll cache;使用L2直接映射cache;使用L2八路组相联cache。如果主存访问时间加倍这些数据会如何变化?(将每个更改作为绝对CPI和百分比更改。)请注意L2 cache可以隐藏慢速内存影响的程度。
}{
先计算主存访问的时钟周期,$2 \times 10^{9} \text{Hz} \times 100 \times 10^{-9} \text{s} = 200 \text{cycles}$
全局失效率是指访问L2并且L2失效的指令数量与全部指令数量的比值局部失效率是指访问L2并且L2失效的指令数量与访问L2的指令的数量的比值。
\begin{itemize}
\item 仅有L1 cache时CPI为$1.5+7\% \times 200 = \bm{15.5}$周期;
\item 使用L2直接映射cache时CPI为 $1.5+7\% \times 12 + 3.5\% \times 200 = \bm{9.34}$周期;
\item 使用L2八路组相联cache时CPI为 $1.5+7\% \times 28 + 1.5\% \times 200 = \bm{6.46}$周期。
\end{itemize}
如果主存访问时间加倍,
\begin{itemize}
\item 仅有L1 cache时CPI为$1.5+7\% \times 400 = \bm{29.5}$周期,增加了$29.5-15.5=\bm{14}$个周期,增加了$14 / 15.5 = \bm{90.3225806451613\%}$
\item 使用L2直接映射cache时CPI为 $1.5+7\% \times 12 + 3.5\% \times 400 = \bm{16.34}$周期,增加了$16.34-9.34 = \bm{7}$个周期,增加了$7 / 15.5 = \bm{45.1612903225806\%}$
\item 使用L2八路组相联cache时CPI为 $1.5+7\% \times 28 + 1.5\% \times 400 = \bm{9.46}$周期,增加了$9.46-6.46 = \bm{3}$个周期,增加了$3 / 6.46 = \bm{46.4396284829721}\%$
\end{itemize}
}
\questionandanswer[5.12.2]{
[ 10 ]<5.4>可能有比两级更多的cache层次结构吗?已知上述处理器具有L2直接映射cache,设计人员希望添加一个L3 cache访问时间为50个时钟周期并且该cache将具有13\%的失效率。这会提供更好的性能吗?一般来说添加L3 cache有哪些优缺点?
}{
可能有比两级更多的cache层次结构。这里的13\%失效率没有说局部还全局。那么如果它是全局失效率那么肯定要比L2的全局失效率低但是这里它比L2的全局失效率高所以只能是局部失效率。
那么加入L3 cache后的CPI为$1.5+7\%\times 12 +3.5\% \times (50 + 13\% \times 200) = 5$周期 $<$ 9.34 周期,所以\boldkai{}提供更好的性能。
添加L3 cache的优点是能用更小的全局失效率兜底隐藏慢速内存影响的程度减小总体的CPI缺点是一旦全部缓存都失效必须访问主存时会产生很大的延迟。
}
\questionandanswer[5.12.3]{
[ 20 ]<5.4>在较老的处理器中例如Intel Pentium或Alpha 21264L2 cache在主处理器和Ll cache的外部(位于不同芯片上)。虽然这种做法使得大型L2 cache成为可能但是访问cache 的延迟也变得很高并且因为L2 cache以较低的频率运行所以带宽通常也很低。假设512KiB的片外L2 cache 的失效率为4\%·如果每增加一个额外的512KiB cache能够降低0.7\%的失效率并且cache 的总访问时间为50个时钟周期那么cache容量必须多大才能与上面列出的L2直接映射cache的性能相匹配?
}{
这里$4\%$的失效率应该为局部失效率。设有$x+1$个512 KiB 的片外L2 cache。那么
$$
1.5+7\%\times 12+3.5\%\times 200 = 1.5 + 7\% \times (50+(4\% - 0.7\% x)\times 200)
$$
解得
$x = - \frac{270}{7} = -38.5714285714286$,但$x$$\geqslant 0$,所以\boldkai{不存在合适的cache容量与上面列出的L2直接映射cache的性能相匹配。}
}
\end{enumerate}
\questionandanswer[5.16]{
如5.7节所述虚拟内存使用页表来跟踪虚拟地址到物理地址的映射。本题显示了在访问地址时必须如何更新页表。以下数据构成了在系统上看到的虚拟字节地址流。假设有4KiB页一个4表项全相联的TLB使用严格的LRU替换策略。如果必须从磁盘中取回页请增加下一次能取的最大页码:
\begin{center}
\begin{tabular}{cccccccc}
\toprule
十进制 & 4669 & 2227 & 13916 & 34587 & 48870 & 12608 & 49225 \\
\midrule
十六进制 & 0x123d & 0x08b3 & 0x365c & 0x871b & 0xbee6 & 0x3140 & 0xc049 \\
\bottomrule
\end{tabular}
\end{center}
TLB
\begin{center}
\begin{tabular}{cccc}
\toprule
有效位 & 标签 & 物理页号 & 上次访问时间间隔 \\
\midrule
1 & 0xb & 12 & 4 \\
1 & 0x7 & 4 & 1 \\
1 & 0x3 & 6 & 3 \\
0 & 0x4 & 9 & 7 \\
\bottomrule
\end{tabular}
\end{center}
页表
\begin{center}
\begin{tabular}{ccc}
\toprule
索引 & 有效位 & 物理页号/在磁盘中 \\
\midrule
0 & 1 & 5 \\
1 & 0 & 在磁盘中 \\
2 & 0 & 在磁盘中 \\
3 & 1 & 6 \\
4 & 1 & 9 \\
5 & 1 & 11 \\
6 & 0 & 在磁盘中 \\
7 & 1 & 4 \\
8 & 0 & 在磁盘中 \\
9 & 0 & 在磁盘中 \\
a & 1 & 3 \\
b & 1 & 12 \\
\bottomrule
\end{tabular}
\end{center}
}{}
\begin{enumerate}
\questionandanswer[5.16.1]{
[ 10 ]<5.7>对于上述每一次访问,列出:
\begin{itemize}
\item 本次访问在 TLB会命中还是失效。
\item 本次访问在页表中会命中还是失效。
\item 本次访问是否会造成缺页错误。
\item TLB的更新状态。
\end{itemize}
}{
4KiB即$2^{12}$Bytes所以对于一个十六进制地址右侧三位十六进制表示页内偏移左侧一位表示标签。
\includexopp[1.5]{5.16.1.1}
\begin{itemize}
\item TLB是否失效只需要查看是否在上一行的Tag中出现过
\item 页表是否失效,只需要看标签是否在页表中出现;
\item 如果某个标签在磁盘中,或者不在页表中,都会造成缺页错误;
\item 每次访问后TLB中的上次访问时间间隔都需要加一用蓝色表示如果TLB未命中则需要替换上次访问时间间隔最大的那一行用红色表示不管是否命中都需要把当前访问到的Tag所在的那行的上次访问时间间隔改为0用红色表示
\item 题目中的“如果必须从磁盘中取回页,请增加下一次能取的最大页码”的意思是发生缺页错误时,分配的物理页号是当前最大的物理页号加一。
\item 答案中的last access是相对顺序每次替换序号最小的一行而这里是指访问时间间隔所以每次替换最大的一行。
\end{itemize}
}
\questionandanswer[5.16.2]{
[ 15 ]<5.7>重复5.16.1但这次使用16KiB页而不是4KiB页。拥有更大页大小的优势是什么有什么缺点
}{
16KiB = $2^{14}$Bytes所以右侧14位二进制位表示页内偏移左侧2位二进制位表示页号。
\includexopp[1.5]{5.16.2.1}
由于标签只有2位所以一共4行的TLB不会出现很多次置换这里的上次访问间隔就省略了直接按照原始的TLB先置换第4行再置换第1行再置换第3行再置换第2行每次置换的行仍然用红色表示。
拥有更大页大小的优势是有更高的快表命中率,缺点是会降低内存使用率(产生了更多内零头)。
}
\questionandanswer[5.16.3]{
[ 15 ]<5.7>重复5.16.1但这次使用4KiB页和一个两路组相联TLB。
}{
一个页是4KiB两个页组成一行。右侧12位表示页内偏移中间1位表示索引左侧3位表示标签。页号仍然是左侧4位。
\includexopp[1.1]{5.16.3.1}
}
\questionandanswer[5.16.4]{
[ 15 ]<5.7>重复5.16.1但这次使用4KiB页和一个直接映射 TLB。
}{
一个页是4KiB右侧12位表示页内偏移中间2位表示索引左侧2位表示标签。页号仍然是左侧4位。
\includexopp[1.5]{5.16.4.1}
}
\questionandanswer[5.16.5]{
[ 10 ]<5.4,5.7>讨论为什么CPU必须使用TLB才能实现高性能。如果没有TLB如何处理虚拟内存访问
}{
为了便于编写程序写代码时不需要指定某段数据放在哪个物理地址中出现了虚拟地址为了将虚拟地址存放到实际的物理地址中需要有个表存放这个映射关系这就是页表而页表存放在内存中访问比较慢。但是每次访问虚拟地址时都需要访问一次页表再访问实际的数据也就是访问两次内存所以就出现了TLB快表作为页表的缓存在TLB命中时只需要访问一次内存从而提升性能。
如果没有TLB每次虚拟内存访问就需要访问两次内存第一次访问页表第二次再访问实际的数据。
}
\end{enumerate}
\end{enumerate}
\end{document}

View File

@@ -0,0 +1,288 @@
\documentclass[全部作业]{subfiles}
\input{mysubpreamble}
\setcounter{chapter}{3}
\begin{document}
\chapter{处理器}
\begin{enumerate}
\questionandanswer[4.7]{
假设用来实现处理器数据通路的各功能模块延迟如下所示:
\noindent{\footnotesize\sffamily
\begin{tabularx}{\linewidth}{ZZZZZZZZZZ}
\toprule
I-Mem / D-Mem & Register File & Mux & ALU & Adder & Single gate & Register Read & Register Setup & Sign extend & Control \\
\midrule
250 ps & 150 ps & 25 ps & 200 ps & 150 ps & 5 ps & 30 ps & 20 ps & 50 ps & 50 ps \\
\bottomrule
\end{tabularx}
}
其中寄存器读延迟指的是时钟上升沿到寄存器输出端稳定输出新值所需的时间。该延迟仅针对PC寄存器。寄存器建立时间指的是寄存器的输入数据稳定到时钟上升沿所需的时间。该数值针对PC寄存器和寄存器堆。
}{}
\begin{enumerate}
\questionandanswer[4.7.1]{
[ 5 ]<4.4>R型指令的延迟是多少?比如,如果想让这类指令工作正确,时钟周期最少为多少?
}{
R型指令的步骤如下图所示。其中在译码阶段Control的延迟为50psRegister File的延迟为150psMux的延迟为25ps由于这三个步骤可以同时执行所以延迟取最大值即150ps。在访存MEM阶段由于R型指令不需要访问内存所以只需要通过一个多路选择器MUX所以延迟为25ps。
\includexopp[1.2]{4.7.1.1}
因此,延迟为$325+150+200+25+20 = 720$ ps即如果想让这类指令工作正确时钟周期最少为$720$ ps。
}
\questionandanswer[4.7.2]{
[ 10 ]<4.4>ld指令的延迟是多少?仔细检查你的答案,许多学生会在关键路径上添加额外的寄存器。
}{
ld指令的步骤如下图所示可以观察到在译码步骤中虽然延迟的组成部分和上一题不一样但由于Register File的延迟较长因此总的延迟还是由Register File决定即150ps。IF、ID、EX步骤的延迟与上一题没有改变但后面两个步骤有所改变。
\includexopp[1.2]{4.7.2.1}
因此,延迟为$325+150+200+275+20 = 970$ ps。
}
\questionandanswer[4.7.3]{
[ 10 ]<4.4>sd指令的延迟是多少?仔细检查你的答案,许多学生会在关键路径上添加额外的寄存器。
}{
前三个步骤仍然与之前一样在MEM中只需要访问D-Mem即250 ps并且没有WB步骤所以延迟为$325+150+200+250 = 925$ ps。
}
\questionandanswer[4.7.4]{
[ 5 ]<4.4> beq指令的延迟是多少?
}{
前三个步骤仍然与之前一样只需要在MEM中加入一个Single gate的延迟并且没有WB步骤。
\includexopp[3]{4.7.4.1}
因此,延迟为$325+150+200+5=680$ ps。
}
\questionandanswer[4.7.5]{
[ 5 ]<4.4>I型指令的延迟是多少?
}{
与R型指令类似I型指令只是在ID阶段需要在MUX前加入Sign extend的延迟但仍然没有Register File的延迟大所以ID步骤仍然需要150 ps的延迟所以总延迟仍然为 720 ps。
}
\questionandanswer[4.7.6]{
[ 5 ]<4.4>该CPU的最小时钟周期是多少?
}{
由于延迟最长的指令为ld指令所以该CPU的最小时钟周期为ld指令的延迟即970 ps。
}
\end{enumerate}
\questionandanswer[4.8]{
[ 10 ]<4.4>假设你能设计一款处理器并让每条指令执行不同的周期数。给定指令比例如下表所示相比图4-21中的处理器这款新处理器的加速比是多少?
\begin{center}
\begin{tabular}{cccc}
\toprule
R-type/I-type (non-ld) & ld & sd & beq \\
\midrule
$52\%$ & $25\%$ & $11\%$ & $12\%$ \\
\bottomrule
\end{tabular}
\end{center}
}{
R型指令和I型指令没有MEM阶段ld指令5个阶段都有sd指令没有WB阶段beq指令没有MEM和WB阶段。可以认为一个阶段的执行需要一个时钟周期如果所有指令执行相同的周期数那么都需要5个时钟周期而如果每条指令可以执行不同的周期数那么各类指令的周期数之比为R/I:4/5ld:1sd:4/5beq:3/5。将各类指令的周期比按照指令比例加权平均即可得到周期比
$$
\frac{4}{5}\times 0.52+1\times 0.25+\frac{4}{5}\times 0.11+\frac{3}{5}\times 0.12 = 0.826
$$
取倒数即可得到加速比:$\displaystyle \frac{1}{0.826} = \frac{500}{413} \approx 1.21065375302663$
}
\questionandanswer[4.16]{
在本题中将讨论流水线如何影响处理器的时钟周期。假设数据通路的各个流水级的延迟如下:
\begin{center}
\begin{tabular}{ccccc}
\toprule
IF & ID & EX & MEM & WB \\
\midrule
250ps & 350ps & 150ps & 300ps & 200ps \\
\bottomrule
\end{tabular}
\end{center}
同时,假设处理器执行的指令分布如下:
\begin{center}
\begin{tabular}{cccc}
\toprule
ALU/Logic & Jump/Branch & Load & Store \\
\midrule
$45\%$ & $20\%$ & $20\%$ & $15\%$ \\
\bottomrule
\end{tabular}
\end{center}
}{}
\begin{enumerate}
\questionandanswer[4.16.1]{
[ 5 ]<4.5>在流水化和非流水的处理器中,时钟周期分别是多少?
}{
流水化的处理器按照最长的阶段即350ps\\
非流水化的处理器:所有阶段延迟之和,即$250+350+150+300+200=1250$ ps。
}
\questionandanswer[4.16.2]{
[ 10 ]<4.5 >在流水化和非流水的处理器中对于ld指令的延迟分别是多少?
}{
ld指令5个阶段都有在流水化的处理器中$350\times 5 = 1750$ ps\\
非流水化的处理器中,为所有阶段延迟之和,即$250+350+150+300+200=1250$ ps。
}
\questionandanswer[4.16.3]{
[ 10 ]<4.5>如果我们将数据通路中的一个流水级拆成两个新流水级,每一个新流水级的延迟是原来的一半,那么我们将拆分哪一级?新处理器的时钟周期是多少?
}{
应该拆分最长的一级即ID阶段拆分之后最长的阶段延迟为300 ps所以新处理器的时钟周期是300 ps。
}
\questionandanswer[4.16.4]{
[ 10 ]<4.5>假设没有停顿或冒险,数据存储的利用率如何?
}{
既然题目中出现了“停顿”“冒险”这种只有在流水化处理器中才会出现的情况那么说明这里只需要考虑流水化的情况。数据存储对应的是MEM阶段MEM阶段只需要300ps但是为了满足流水线延迟到了350ps所以MEM阶段的利用率为$\frac{300}{350}$而在题目给出的指令分布中只有Load和Store指令会用到数据存储$20\%+15\%$,所以数据存储的利用率为
$$
\frac{300}{350} \times (0.2+0.15) = 0.3
$$
}
\questionandanswer[4.16.5]{
[ 10 ]<4.5>假设没有停顿或冒险,寄存器堆的写口利用率如何?
}{
寄存器堆的写口对应的是WB阶段WB阶段的利用率为$\frac{200}{350}$在题目给出的指令分布中使用到寄存器堆的写口的指令为ALU/Logic和Load$45\%+20\%$,所以寄存器堆写口的利用率为
$$
\frac{200}{350} \times (0.45+0.2) = \frac{13}{35} \approx 0.371428571428571
$$
}
\end{enumerate}
\questionandanswer[4.18]{
[ 5 ]<4.5>假设初始化寄存器x11为11,x12为22如果在4.5节中的流水线结构上执行下述代码寄存器x13和x14中最终为何值?注:硬件不处理数据冒险编程者需要在必要处插入NOP指令来解决数据冒险。
}{}
\begin{minted}{asm}
addi x11, x12, 5
add x13, x11, x12
addi x14, x11, 15
\end{minted}
{\kaishu
显然在硬件不处理数据冒险情况下执行上述代码会出现数据冒险以下是示意图在ID指令旁边标注了实际取出的操作数。
\includexopp[1.5]{4.18.1}
所以寄存器x13最终为33寄存器x14最终为26。
}
\questionandanswer[4.22]{
[ 5 ]<4.5>对于如下的RISC-V的汇编片段:
}{}
\begin{minted}{asm}
sd x29, 12(x16)
ld x29, 8(x16)
sub x17, x15, x14
beqz x17, label
add x15, x11, x14
sub x15, x30, x14
\end{minted}
\begin{enumerate}
\questionandanswer[4.22.1]{
[ 5 ]<4.5>请画出流水线图,说明以上代码会在何处停顿。
}{
在加入停顿之前的流水线图是这样的显然由于前面的指令的MEM阶段和后面的指令的IF阶段都需要访问存储器会发生结构冒险。
\includexopp[1.1]{4.22.1.1}
加入停顿后流水线图变成了这样:
\includexopp{4.22.1.2}
}
\questionandanswer[4.22.2]{
[ 5 ]<4.5>是否可通过重排代码来减少因结构冒险而导致停顿的次数?
}{
可以由于只考虑结构冒险即两条指令在同一个阶段访问寄存器堆或存储器的冒险可以把第一行的sd指令放到第二三行的ld和sub指令后面这样就可以减少一个停顿。
}
\questionandanswer[4.22.3]{
[ 5 ]<4.5>该结构冒险必须用硬件来解决吗?我们可以通过在代码中插入NOP指令来消除数据冒险对于结构冒险是否可以相同处理?如果可以,请解释原因。否则,也请解释原因。
}{
不一定要用硬件来解决可以通过插入NOP指令来消除结构冒险因为NOP指令相当于一个停顿只需要把上述的停顿换成NOP指令即可。
}
\questionandanswer[4.22.4]{
[ 5 ]<4.5>在典型程序中,大约需要为该结构冒险产生多少个周期的停顿?(使用习题4.8中的指令分布)。
}{
仔细观察可以发现停顿的产生是由于sd和ld有MEM阶段会和后续指令的IF阶段冲突ld和R型指令有WB阶段会和后续指令的ID阶段冲突那么可以认为一个ld导致2个停顿一个sd导致1个停顿一个R型导致1个停顿。所以大概产生的停顿周期数为
$$
1\times 0.52+2\times 0.25+1\times 0.11 = 1.13
$$
即产生$1.13\times \text{原始时钟周期数}$ 个周期的停顿。
}
\end{enumerate}
\questionandanswer[4.27]{
讨论下述指令序列,假设在一个五级流水的数据通路中执行:
}{}
\begin{minted}{asm}
add x15, x12, x11
ld x13, 4(x15)
ld x12, 0(x2)
or x13, x15, x13
sd x13, 0(x15)
\end{minted}
\begin{enumerate}
\questionandanswer[4.27.1]{
[ 5 ]<4.7>如果没有前递逻辑或者冒险检测支持请插入NOP指令保证程序正确执行。
}{}
{\kaishu
\begin{minted}{asm}
add x15, x12, x11 // 在第5个阶段写入x15
nop
nop
ld x13, 4(x15) // 在第2个阶段读取x15在第5个阶段写入x13
ld x12, 0(x2) // 在第2个阶段读取x2在第5个阶段写入x12
nop
or x13, x15, x13 // 在第2个阶段读取x13和x15在第5个阶段写入x13
nop
nop
sd x13, 0(x15) // 在第2个阶段读取x13和x15
\end{minted}
}
\questionandanswer[4.27.2]{
[ 10 ]<4.7>对代码进行重排插入最少的NOP指令。假设寄存器x17可用来做临时寄存器。
}{}
{\kaishu
\begin{minted}{asm}
add x15, x12, x11
nop
nop
ld x13, 4(x15)
ld x12, 0(x2)
nop
or x17, x15, x13
sd x17, 0(x15)
\end{minted}
}
\questionandanswer[4.27.3]{
[ 10 ]<4.7>如果处理器中支持前递,但未实现冒险检测单元,上述代码段的执行将会发生什么?
}{
不会发生数据冒险因为在不存在加载后马上使用的情况第二行加载到x13后在第4行才使用x13此时已经可以使用前递确保正确执行。
}
\questionandanswer[4.27.4]{
[ 20 ]<4.7>以图4-58中的冒险检测和前递单元为例如果执行上述代码在前7个时钟周期中每周期哪些信号会被它们置为有效?
}{
\includexopp[1.2]{4.27.4.1}
前递信号如图所示。所以在前7个时钟周期中有效信号表示如下表
\begin{center}
\begin{tabular}{cccc}
\toprule
时钟周期 & 冒险检测 & ForwardA & ForwardB \\
\midrule
1 & x & x & x \\
2 & x & x & x \\
3 & 有效 & 有效 & x \\
4 & x & x & x \\
5 & 有效 & x & 有效 \\
6 & 有效 & 有效 & x \\
7 & x & x & x \\
\bottomrule
\end{tabular}
\end{center}
}
\questionandanswer[4.27.5]{
[ 10 ]<4.7>如果没有前递单元以图4-58中的冒险检测逻辑为例需要为其增加哪些输入和输出信号?
}{
第3个周期的前递需要IF/ID.Rs1 和 ID/EX.Rd的输入信号ForwardA的输出信号\\
第5个周期的前递需要IF/ID.Rs2 和 EX/MEM.Rd的输入信号ForwardB的输出信号\\
第6个周期的前递需要IF/ID.Rs1 和 ID/EX.Rd的输入信号ForwardA的输出信号。\\
综上所述需要增加IF/ID.Rs1, IF/ID.Rs2, ID/EX.Rd, EX/MEM.Rd 的输入信号ForwardA, ForwardB的输出信号。
}
\questionandanswer[4.27.6]{
[ 20 ]<4.7>如果使用习题4.26.5中的冒险检测单元执行上述代码在前5个时钟周期中,每个周期哪些输出信号会有效?
}{
\includexopp[1.2]{4.27.4.1}
前递信号如图所示。所以在前5个时钟周期中有效信号表示如下表
\begin{center}
\begin{tabular}{cccc}
\toprule
时钟周期 & 冒险检测 & ForwardA & ForwardB \\
\midrule
1 & x & x & x \\
2 & x & x & x \\
3 & 有效 & 有效 & x \\
4 & x & x & x \\
5 & 有效 & x & 有效 \\
\bottomrule
\end{tabular}
\end{center}
}
\end{enumerate}
\end{enumerate}
\end{document}