archlab属于第四章的内容。这章讲了处理器体系结构,就CPU是怎样构成的.看到时候跃跃欲试,以为最后实验是真要去造个CPU,配套资料也是一如既往的豪华,合计四十多页的参考手册,一大包的源码和测试程序.意料之外是具体考你的不是"炼丹"(指沙土炼硅造芯),而是处理器级别的优化,要把处理器的性能榨干才能得满分.不愧是CMU,榨得我已经一滴脑汁也没有了,最后还只得了八成的分.

通过上次实验我知道了CMU喜欢给头铁之人留几个零头,所以剩下两成分我也不追求了.(耻辱下播)

前期准备

下载讲义和解压的部分略过,这里一讲各种依赖的设置.基本上就是make的时候缺啥补啥.

我用的系统是Unbutu,直接apt-get大法

sudo apt-get install tcl8.5-dev tk8.5-dev flex

Part A

这一部分是用Y86-64指令集把几个C程序实现成汇编形式来热热身.说来也巧,这次的几道汇编题里的优化小技巧都是我从几年前玩《人力资源机器》里学来的.

Y86-64指令集概括为:

RF:程序寄存器
rax,rbx,rcd,rdx,
rsp,rbp,rsi,rdi,
r8~r14 CC:条件码
ZF,SF,OF 指令集:
halt
nop
rrmovq
irmovq
rmmovq
mrmovq
OPq(subq,addq,andq,xorq)
jXX(jmp,jle,jl,je,jne,jge,jg)
cmovXX(le,l,e,ne,ge,g)
call
ret
pushq
popq

注意这一部分需要我们内嵌测试代码,即在实现的时候需要手动在代码里添加运行栈,主函数,启动函数和测试数据,并且源文件末尾要空一行

sum_list

这一题我在用yis运行这段代码时结果错误,用ssim运行则正常,我认为时yis有问题

#init function
.pos 0x0
irmovq stack,%rsp
call main
ret # Sample linked list
.pos 0x200
.align 8
ele1:
.quad 0x00a
.quad ele2
ele2:
.quad 0x0b0
.quad ele3
ele3:
.quad 0xc00
.quad 0 # main function
main:
irmovq ele1,%rdi
call sum_list
ret # sum_list function
sum_list:
irmovq $0,%rax
jmp L1
L2:
mrmovq (%rdi),%rbx
addq %rbx,%rax
mrmovq 8(%rdi),%rdi
L1:
andq %rdi,%rdi
jne L2
ret #alloc stack space
.pos 0x1000
stack:

rsum_list

#init function
.pos 0x0
irmovq stack,%rsp
call main
ret # Sample linked list
.pos 0x200
.align 8
ele1:
.quad 0x00a
.quad ele2
ele2:
.quad 0x0b0
.quad ele3
ele3:
.quad 0xc00
.quad 0 # main function
main:
irmovq ele1,%rdi
call rsum_list
ret # rsum_list function
rsum_list:
andq %rdi,%rdi
je L1
mrmovq (%rdi),%rbx
mrmovq 8(%rdi),%rdi
pushq %rbx
call rsum_list
popq %rbx
addq %rbx,%rax
ret
L1:
irmovq $0,%rax
ret #alloc stack space
.pos 0x1000
stack:

copy_block

#init function
.pos 0x0
irmovq stack,%rsp
call main
ret .align 8
# Source block
src:
.quad 0x00a
.quad 0x0b0
.quad 0xc00
# Destination block
dest:
.quad 0x111
.quad 0x222
.quad 0x333 # main function
main:
irmovq src,%rdi
irmovq dest,%rsi
irmovq $3,%rdx
call copy_block
ret # copy_block function
copy_block:
irmovq $8,%r8
irmovq $1,%r9
irmovq $0,%rax
addq %r9,%rdx
jmp L2
L1:
mrmovq (%rdi),%rbx
addq %r8,%rdi
rmmovq %rbx,(%rsi)
addq %r8,%rsi
xorq %rbx,%rax
L2:
subq %r9,%rdx
jne L1
ret #alloc stack space
.pos 0x1000
stack:

Part B

这部分要求为处理器增加一个iaddq指令,参考课本的图4.18,很容易写出iaddq对应的各个阶段

fetch:
icode:ifun <- M1[PC]
rA:rB <- M1[PC+1]
valC <- M8[PC+2]
valP <- PC+10 decode:
valB <- R[rB] execute:
valE <- valB OP valC
set CC memory:
NONE write back:
R[rB] <- valE PC update:
PC <- valP

然后在seq-full.hcl文件里搜索IRRMOVQ和IOPQ相关项并修改之即可

--- ~/Desktop/seq-full.hcl
+++ ~/Desktop/sim/seq/seq-full.hcl
@@ -106,16 +106,16 @@ bool instr_valid = icode in
{ INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ,
- IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ };
+ IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ, IIADDQ }; # Does fetched instruction require a regid byte?
bool need_regids =
icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ,
- IIRMOVQ, IRMMOVQ, IMRMOVQ };
+ IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ }; # Does fetched instruction require a constant word?
bool need_valC =
- icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL };
+ icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ }; ################ Decode Stage ################################### @@ -128,7 +128,7 @@ ## What register should be used as the B source?
word srcB = [
- icode in { IOPQ, IRMMOVQ, IMRMOVQ } : rB;
+ icode in { IOPQ, IRMMOVQ, IMRMOVQ, IIADDQ } : rB;
icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;
1 : RNONE; # Don't need register
];
@@ -136,7 +136,7 @@
## What register should be used as the E destination?
word dstE = [
icode in { IRRMOVQ } && Cnd : rB;
- icode in { IIRMOVQ, IOPQ} : rB;
+ icode in { IIRMOVQ, IOPQ, IIADDQ} : rB;
icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;
1 : RNONE; # Don't write any register
];
@@ -152,7 +152,7 @@
## Select input A to ALU
word aluA = [
icode in { IRRMOVQ, IOPQ } : valA;
- icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ } : valC;
+ icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ } : valC;
icode in { ICALL, IPUSHQ } : -8;
icode in { IRET, IPOPQ } : 8;
# Other instructions don't need ALU
@@ -161,7 +161,7 @@
## Select input B to ALU
word aluB = [
icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL,
- IPUSHQ, IRET, IPOPQ } : valB;
+ IPUSHQ, IRET, IPOPQ, IIADDQ } : valB;
icode in { IRRMOVQ, IIRMOVQ } : 0;
# Other instructions don't need ALU
];
@@ -173,7 +173,7 @@
]; ## Should the condition codes be updated?
-bool set_cc = icode in { IOPQ };
+bool set_cc = icode in { IOPQ, IIADDQ }; ################ Memory Stage ###################################

一个小插曲是因为各种库更新换代,部分源代码失效导致我编译ssim的时候报错了

USER@NAME:~/sim/seq$ make ssim VERSION=std
# Building the seq-std.hcl version of SEQ
../misc/hcl2c -n seq-std.hcl <seq-std.hcl >seq-std.c
gcc -Wall -O2 -isystem /usr/include/tcl8.5 -I../misc -DHAS_GUI -o ssim \
seq-std.c ssim.c ../misc/isa.c -L/usr/lib -ltk -ltcl -lm
/tmp/ccmcBZXH.o:(.data.rel+0x0):对‘matherr’未定义的引用
collect2: error: ld returned 1 exit status
Makefile:44: recipe for target 'ssim' failed
make: *** [ssim] Error 1

我的解决方法就是把所有带matherr的相关代码注释掉,主要就下面这两行.这两行没有在别处调用,且注释后在我整个实验过程中没有遇到任何副作用,大可放心.

extern int matherr();
int *tclDummyMathPtr = (int *) matherr;

Part C

要求首先在pipe-full.hcl实现iaddq指令,这部分照抄上面就行.然后对ncopy.ys汇编文件和进行pipe-full.hcl效率优化.要使之效率提高一半以上才有分数,蛮有难度的,我第一次优化完看见零分直接傻了.最后一同乱搞终于拿了47/60的分

这里讲一下的思路:

先通过CSAPP4.5.8节可知,我们这里可以对流水线的优化有:

  • 加载/使用冒险: 即在一条从内存读出一个值的指令和一条使用这个值的指令间,流水线必会暂停一个周期.可以通过避免使用刚从内存里读出的值解决.
  • 预测错误分支: 在分支逻辑发现不该选择分支之前,分支目标处几条指令已经进入流水线了.必须取消这些指令,并从跳转指令后面的那条指令开始取指.可以通过重新架构硬件更改处理器预测逻辑,或者写代码时迎合处理器预测逻辑解决.

    后者难度太高,我们主要优化前者,具体方法是在rmmovq或popq指令后避免使用刚读入的值.

    另外根据讲义提示,还可以参考CSAPP5.8节,通过循环展开,减少迭代判断语句的执行次数进行优化.举例子:
//展开前
for(int i=0;i<N;i++) sum+=a[i];
//二路展开后
for(int i=0;i<N;i+=2) sum+=a[i]+a[i+1];

我的方法是先六路展开,再二路展开,最后处理剩下的那一个.

另外rmmovq和mrmovq间的空隙不能浪费,不如再重复一边填充之

	xorq %rax,%rax
jmp StartLoop6 Loop6:
mrmovq (%rdi),%r8
mrmovq 8(%rdi),%r9
rmmovq %r8,(%rsi)
rmmovq %r9,8(%rsi)
andq %r8,%r8
jle L61
iaddq $1,%rax
L61:
andq %r9,%r9
jle L62
iaddq $1,%rax
L62: mrmovq 16(%rdi),%r8
mrmovq 24(%rdi),%r9
rmmovq %r8,16(%rsi)
rmmovq %r9,24(%rsi)
andq %r8,%r8
jle L63
iaddq $1,%rax
L63:
andq %r9,%r9
jle L64
iaddq $1,%rax
L64: mrmovq 32(%rdi),%r8
mrmovq 40(%rdi),%r9
rmmovq %r8,32(%rsi)
rmmovq %r9,40(%rsi)
andq %r8,%r8
jle L65
iaddq $1,%rax
L65:
andq %r9,%r9
jle L66
iaddq $1,%rax
L66: iaddq $48,%rdi
iaddq $48,%rsi
StartLoop6:
iaddq $-6,%rdx
jge Loop6 iaddq $6,%rdx
jmp StartLoop2
Loop2:
mrmovq (%rdi),%r8
mrmovq 8(%rdi),%r9
rmmovq %r8,(%rsi)
rmmovq %r9,8(%rsi)
andq %r8,%r8
jle L21
iaddq $1,%rax
L21:
andq %r9,%r9
jle L22
iaddq $1,%rax
L22: iaddq $16,%rdi
iaddq $16,%rsi
StartLoop2:
iaddq $-2,%rdx
jge Loop2 mrmovq (%rdi),%rbx
iaddq $1,%rdx
jne Done
rmmovq %rbx,(%rsi)
andq %rbx,%rbx
jle Done
iaddq $1,%rax

【CSAPP】Architecture Lab 实验笔记的更多相关文章

  1. 【CSAPP】Shell Lab 实验笔记

    shlab这节是要求写个支持任务(job)功能的简易shell,主要考察了linux信号机制的相关内容.难度上如果熟读了<CSAPP>的"异常控制流"一章,应该是可以不 ...

  2. 【CSAPP】Cache Lab 实验笔记

    cachelab这节先让你实现个高速缓存模拟器,再在此基础上对矩阵转置函数进行优化,降低高速缓存不命中次数.我的感受如上一节,实在是不想研究这些犄角旮旯的优化策略了. 前期准备 我实验的时候用到了va ...

  3. 【CSAPP】Attack Lab实验笔记

    attacklab这节玩的是利用一个字符串进行缓冲区溢出漏洞攻击,就小时候想象中黑客干的事儿. 做题的时候好几次感叹这些人的脑洞,"这都可以攻击?还能这么注入?这还可能借力打力?" ...

  4. 【CSAPP】Performance Lab 实验笔记

    perflab这节的任务是利用书中知识,来对图像处理中的Rotate和Smooth操作函数进行优化.这次没对上电波,觉得学了一堆屠龙之技.于我个人理解,现在计算机配置比以前高多了,连SWAP分区都几近 ...

  5. 【CSAPP】Bomb Lab实验笔记

    bomblab这节搞的是二进制拆弹,可以通俗理解为利用反汇编知识找出程序的六个解锁密码. 早就听闻BOMBLAB的大名,再加上我一直觉得反汇编是个很艰难的工作,开工前我做好了打BOSS心理准备.实际上 ...

  6. 【CSAPP】Data Lab实验笔记

    前天讲到要刚CSAPP,这一刚就是两天半.CSAPP果然够爽,自带完整的说明文档,评判程序,辅助程序.样例直接百万组走起,管饱! datalab讲的是整数和浮点数怎么用二进制表示的,考验的是用基本只用 ...

  7. ChCore Lab3 用户进程和异常处理 实验笔记

    本文为上海交大 ipads 研究所陈海波老师等人所著的<现代操作系统:原理与实现>的课程实验(LAB)的学习笔记的第三篇:用户进程与异常处理.所有章节的笔记可在此处查看:chcore | ...

  8. CSAPP buffer lab记录——IA32版本

    CSAPP buffer lab为深入理解计算机系统(原书第二版)的配套的缓冲区溢出实验,该实验要求利用缓冲区溢出的原理解决5个难度递增的问题,分别为smoke(level 0).fizz(level ...

  9. CSAPP Bomb Lab记录

    记录关于CSAPP 二进制炸弹实验过程 (CSAPP配套教学网站Bomb Lab自学版本,实验地址:http://csapp.cs.cmu.edu/2e/labs.html) (个人体验:对x86汇编 ...

随机推荐

  1. spring-boot-关于module自定义jar包打包无法给其他module使用

    ####世界大坑: 如果仅是使用 <build> <plugins> <plugin> <groupId>org.springframework.boo ...

  2. 怎么获取 Java 程序使用的内存?堆使用的百分比?

    可以通过 java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及 最大堆内存.通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间. Runtime.freeMemor ...

  3. 详细描述一下 Elasticsearch 更新和删除文档的过程?

    1.删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不 能被删除或者改动以展示其变更: 2.磁盘上的每个段都有一个相应的.del 文件.当删除请求发送后,文档并没有真 ...

  4. 是否可以从一个静态(static)方法内部发出对非静态 (non-static)方法的调用?

    不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,在 调用静态方法时可能对象并没有被初始化.

  5. SQLAlchemy 使用教程

    前戏: ​ 不用怀疑,你肯定用过Django中的orm,这个orm框架是django框架中自己封装的,在Django中配置和使用较为简单,但是并不适用于其他web框架,而今天说的sqlalchemy是 ...

  6. js身份证精确认证

    function checkIdCard(idcard) { // 1 "验证通过!", 0 //身份证号码校验错误 var Errors = new Array( "1 ...

  7. PCB设计常见规则及基本原则

    一.PCB基础知识 1.全称:印制电路板或者印制线路板 2.分类 材质分类:硬板(Rigid PCB).软板FPC(Flexible PCB).软硬结合板(Rigid-Flex PCB).HDI板(含 ...

  8. react开发教程(三)组件的构建

    什么是组件 组件化就好像我们的电脑装机一样,一个电脑由显示器.主板.内存.显卡.硬盘,键盘,鼠标.... 组件化开发有如下的好处:降低整个系统的耦合度,在保持接口不变的情况下,我们可以替换不同的组件快 ...

  9. React中Ref 的使用 React-踩坑记_05

    React中Ref 的使用 React v16.6.3 在典型的React数据流中,props是父组件与其子组件交互的唯一方式.要修改子项,请使用new props 重新呈现它.但是,在某些情况下,需 ...

  10. 现代CSS进化史

    英文:https://medium.com/actualize-...编译:缪斯 CSS一直被web开发者认为是最简单也是最难的一门奇葩语言.它的入门确实非常简单--你只需为元素定义好样式属性和值,看 ...