前言

《深入理解计算机系统》实验四Architecture Lab下载和官方文档机翻请看:
《深入理解计算机系统》实验四Architecture Lab下载和官方文档机翻

我觉得这个文档对整个实验很有帮助。

如果你的Y86-64环境还没安装好可以看:
《深入理解计算机系统》Y86-64实验四Architecture Lab环境安装:
《深入理解计算机系统》Y86-64实验四Architecture Lab环境安装

C部分的CPE
12.70->12.55->11.55->9.06->8.34->8.19->7.80->7.49(满分)。
建议看完第五章在来写C部分

A部分

在本部分中,您将在sim/misc目录下工作。
您的任务是编写并模拟下面三个Y86-64程序。这些程序所需的行为由examples.c中的示例C函数定义。确保把你的名字和ID放在每个程序开始的注释中。你可以先用YAS程序组装你的程序,然后用指令集模拟器YIS运行它们。
在所有Y86-64函数中,都应该遵循x86-64约定来传递函数参数、使用寄存器和使用堆栈。这包括保存和恢复您使用的所有调用保存寄存器。

第一题sum.ys

编写Y86-64程序求和。sum.ys迭代地对链表的元素求和。您的程序应该由一些代码组成,这些代码设置堆栈结构,调用函数,然后停止。在本例中,函数应该是函数(sum_list)的Y86-64代码,该函数在功能上与下面的C函数sum_list等效。使用下面的三个元素列表来测试你的程序:

/* linked list element */
typedef struct ELE {long val;struct ELE *next;
} *list_ptr;/* sum_list - 对链表的元素求和 */
long sum_list(list_ptr ls)
{long val = 0;while (ls) {val += ls->val;ls = ls->next;}return val;
}

参照sim/y86-code/asum.yo(CS:APP3e图4.8)的格式。编写sum_list的Y86-64汇编代码

sum.ys:

 .pos 0irmovq stack,%rspcall mainhalt.align 8
ele1:.quad 0x00a.quad ele2
ele2:.quad 0x0b0.quad ele3
ele3:.quad 0xc00.quad 0main:irmovq ele1,%rdicall sum_listret# long sum_list(list_ptr ls)
# ls in %rdi
sum_list:xorq %rax,%rax     # val = 0mrmovq (%rdi),%rsiandq %rsi,%rsi      # Set CCjmp test            # Goto testloop:addq %rsi,%rax      #累加mrmovq 8(%rdi),%rdi  #指向下一个节点andq %rdi,%rdi      #set CC 下一个节点是否是0mrmovq (%rdi),%rsi #(%rdi)表示节点的值test:jne loop      # Stop when 0ret                # Return.pos 0x200
stack:

要把sum.ys文件放入sim/y86-code下。
根据simguguide.pdf中的提示进行如下操作

linux> make sum.yo
linux> ../misc/yis sum.yo

如下图所示,可以看到返回值(%rax)是0xcba,说明程序正确。

第二题rsum.ys

编写一个Y86-64程序rsum.ys,递归地对链表的元素求和。这段代码应该类似于sum.ys中的代码,除了它应该使用一个函数rsum_list来递归地求和一个数字列表,如下面的C函数rsum_list所示。使用第一题测试用的三个元素列表来测试。

/* linked list element */
typedef struct ELE {long val;struct ELE *next;
} *list_ptr;/* rsum_list - sum_list的递归版本 */
long rsum_list(list_ptr ls)
{if (!ls)return 0;else {long val = ls->val;long rest = rsum_list(ls->next);return val + rest;}
}

编写rsum_list的y86-64汇编代码
rsum.ys

 .pos 0irmovq stack,%rspcall mainhalt.align 8
ele1:.quad 0x00a.quad ele2
ele2:.quad 0x0b0.quad ele3
ele3:.quad 0xc00.quad 0main:irmovq ele1,%rdicall rsum_listret# long rsum_list(list_ptr ls)
# ls in %rdi
rsum_list:pushq %rbxxorq %rax,%rax      # val = 0rrmovq %rdi,%rsi  andq %rsi,%rsi      #判断当前节点是否为0je exitmrmovq (%rdi),%rbx    #获取当前节点的值valmrmovq 8(%rdi),%rdi #指向下一节点call rsum_list       #递归。返回值(%rax)即restaddq %rbx,%rax        #val+restpopq %rbxret                  # Returnexit:popq %rbxret.pos 0x200
stack:

运行如下(同第一题同):
如下图所示,可以看到返回值(%rax)是0xcba,说明程序正确。

第三题copy.ys

编写一个程序(copy.ys),将一块单词从内存的一部分复制到内存的另一部分(非重叠区域),计算所有被复制单词的校验和(Xor)。你的程序应该由建立堆栈框架,调用函数复制块,然后停止的代码组成。该函数在功能上应该与下所示的C函数复制块相同。使用以下三个元素的源和目标块来测试你的程序:

/* copy_block - 将src拷贝到dest并返回xor校验和 */
long copy_block(long *src, long *dest, long len)
{long result = 0;while (len > 0) {long val = *src++;*dest++ = val;result ^= val;len--;}return result;
}

编写copy_block的y86-64汇编代码
copy.ys:

 .pos 0irmovq stack,%rspcall mainhalt.align 8
src:.quad 0x00a.quad 0x0b0.quad 0xc00dest:.quad 0x111.quad 0x222.quad 0x333main:irmovq src,%rdiirmovq dest,%rsiirmovq $3,%rdx       #有3个要复制call copy_block      #copy_block(%rdi,%rsi,%rdx)retcopy_block:pushq %rbx         #%rbx是被调用者保护,入栈xorq %rax,%raxirmovq $8,%r8       #常数8.指向下一个irmovq $1,%r9     #常数1.andq %rdx,%rdx jle exit            #<=0退出loop:mrmovq (%rdi),%rbx   #获取src第一个词addq %r8,%rdi     #指向下一个词rmmovq %rbx,(%rsi)   #把src的复制给destaddq %r8,%rsi      #指向下一个复制区xorq %rbx,%rax     #计算所有被复制单词的校验和(Xor)subq %r9,%rdx        #还剩下几个andq %rdx,%rdx        #>0继续循环jg loopexit:popq %rbx     ret.pos 0x200
stack:

运行如下:
可以看到校验和%rax,是对的。
dest也被改变为src的值,说明复制过去了。程序正确

B部分

在这一部分中,您将在目录sim/seq中工作。
你在B部分的任务是扩展SEQ处理器以支持iaddq,在家庭作业问题4.51和4.52中描述了这一点。要添加此说明,您需要修改文件seq-full.hcl。它实现了CS:APP3e教科书中描述的SEQ版本。此外,它还包含解决方案所需的一些常量的声明。

家庭作业
4.51:练习题4.3介绍了iaddq指令,即将立即数与寄存器相加。描述实现该指令所执行的计算。参考irmovq和OPq指令的计算
4.52:文件seq- full.hcl包含SQL的HCL描述,并将常数IIADDQ声明为十六进制c,也就是iaddq的指令代码。修改实现iaddq指令的控制逻辑块的HCl描述,就像练习题4.3和家庭作业4.51中描述的那样。可以参考实验资料获得如何为你的解答生成模拟器以及如何测试模拟器的指导。
练习题4.3:机器级程序中常见的模式之一是将一根常数值与一根寄存器相加。利用目前已给出的Y86-64指令,实现这个操作需要一条irmovq指令把常数加载到寄存器,然后一条addq指令把这个寄存器值与目标寄存器值相加。假设我们想增加一条新指令iaddq,格式如下:

该指令将常数值V与寄存器rB相加。这就是我们要做的事情。
根据这些提示

写出了iaddq在顺序实现中的计算

阶段 iaddq V,rB
取值 icode:ifun<-M1[PC]
rA:rB<-M1[PC+1]
valC<-M8[PC+2]
valP<-PC+10
译码
valB<-R[rB]
执行 valE<-valB+valC
Set CC
访存
写回 R[rB]<-valE
更新PC PC<-valP

现在要做的事情,就是修改seq-full.hcl。
打开可以看见

往下翻可以看到已经添加上了iaddq的指令代码(下面的修改可以参考《CS:APP3e》图4.18~4.21)

在往下翻可以看到取值阶段(Fetch Stage)(可参考《CS:APP3e》P278)

iaddq v,rB的取值阶段的操作是
icode:ifun<-M1[PC]   #需要是合法的Y86-64指令
rA:rB<-M1[PC+1]    #有寄存器
valC<-M8[PC+2]    #有常数值
valP<-PC+10

所以更改取值阶段(Fetch Stage)内容为:

在往下翻可以看到译码和写回阶段(Decode Stage)(可参考《CS:APP3e》P279)

我们写的iaddq v,rB在译码阶段的操作是
valB<-R[rB]    #rB

在写回阶段是
R[rB]<-valE    #valE和rB

所以更改译码和写回阶段(Decode Stage)为:

在往下翻可以看到执行阶段(Execute Stage)(可参考《CS:APP3e》P280)

我们的iaddq指令在执行阶段进行的操作是:
valE<-valB+valC

可知aluB为valB,aluA为valC。条件码需要更新

所以更改执行阶段(Execute Stage)为:

访存阶段(Memory Stage )和更新PC阶段(Program Counter Update)都不用改动。

根据archlab.pdf的内容来测试我们的方案

如下所示:

测试成功
最终的seq-full.hcl文件

#/* $begin seq-all-hcl */
####################################################################
#  HCL Description of Control for Single Cycle Y86-64 Processor SEQ   #
#  Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2010       #
###################################################################### Your task is to implement the iaddq instruction(您的任务是实现iaddq指令)
## The file contains a declaration of the icodes(该文件包含一个icode的声明)
## for iaddq (IIADDQ)
## Your job is to add the rest of the logic to make it work(你的工作是添加剩下的逻辑使它工作)####################################################################
#    C Include's.  Don't alter these                               #
####################################################################quote '#include <stdio.h>'
quote '#include "isa.h"'
quote '#include "sim.h"'
quote 'int sim_main(int argc, char *argv[]);'
quote 'word_t gen_pc(){return 0;}'
quote 'int main(int argc, char *argv[])'
quote '  {plusmode=0;return sim_main(argc,argv);}'####################################################################
#    Declarations.  Do not change/remove/delete any of these       #
######################################################################### Symbolic representation of Y86-64 Instruction Codes #############
wordsig INOP    'I_NOP'
wordsig IHALT   'I_HALT'
wordsig IRRMOVQ 'I_RRMOVQ'
wordsig IIRMOVQ 'I_IRMOVQ'
wordsig IRMMOVQ 'I_RMMOVQ'
wordsig IMRMOVQ 'I_MRMOVQ'
wordsig IOPQ    'I_ALU'
wordsig IJXX    'I_JMP'
wordsig ICALL   'I_CALL'
wordsig IRET    'I_RET'
wordsig IPUSHQ  'I_PUSHQ'
wordsig IPOPQ   'I_POPQ'
# Instruction code for iaddq instruction(iaddq指令的指令代码)
wordsig IIADDQ  'I_IADDQ'##### Symbolic represenations of Y86-64 function codes                  #####
wordsig FNONE    'F_NONE'        # Default function code##### Symbolic representation of Y86-64 Registers referenced explicitly #####
wordsig RRSP     'REG_RSP'        # Stack Pointer
wordsig RNONE    'REG_NONE'       # Special value indicating "no register"##### ALU Functions referenced explicitly                            #####
wordsig ALUADD  'A_ADD'       # ALU should add its arguments##### Possible instruction status values                             #####
wordsig SAOK    'STAT_AOK'    # Normal execution
wordsig SADR    'STAT_ADR'    # Invalid memory address
wordsig SINS    'STAT_INS'    # Invalid instruction
wordsig SHLT    'STAT_HLT'    # Halt instruction encountered##### Signals that can be referenced by control logic ######################### Fetch stage inputs        #####
wordsig pc 'pc'               # Program counter
##### Fetch stage computations      #####
wordsig imem_icode 'imem_icode'       # icode field from instruction memory
wordsig imem_ifun  'imem_ifun'        # ifun field from instruction memory
wordsig icode     'icode'     # Instruction control code
wordsig ifun      'ifun'      # Instruction function
wordsig rA    'ra'            # rA field from instruction
wordsig rB    'rb'            # rB field from instruction
wordsig valC      'valc'      # Constant from instruction
wordsig valP      'valp'      # Address of following instruction
boolsig imem_error 'imem_error'       # Error signal from instruction memory
boolsig instr_valid 'instr_valid' # Is fetched instruction valid?##### Decode stage computations      #####
wordsig valA    'vala'            # Value from register A port
wordsig valB    'valb'            # Value from register B port##### Execute stage computations    #####
wordsig valE    'vale'            # Value computed by ALU
boolsig Cnd 'cond'            # Branch test##### Memory stage computations        #####
wordsig valM    'valm'            # Value read from memory
boolsig dmem_error 'dmem_error'       # Error signal from data memory####################################################################
#    Control Signal Definitions.                                   #
#################################################################################### Fetch Stage     #################################### Determine instruction code(确定指令代码)
word icode = [imem_error: INOP;    #INOP:nop的指令代码1: imem_icode;     # Default: get from instruction memory
];# Determine instruction function(确定指令功能)
word ifun = [imem_error: FNONE;    #FNONE:默认功能码1: imem_ifun;        # Default: get from instruction memory
];#这个字节对应于一个合法的Y86-64指令吗?这个信号用来发现不合法的指令
bool instr_valid = icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ,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,IIADDQ};#这个指令包括一个常数字吗?
# Does fetched instruction require a constant word?
bool need_valC =icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL,IIADDQ};################ Decode Stage    #################################### 什么寄存器应该用作A源?
## What register should be used as the A source?
word srcA = [icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ  } : rA;icode in { IPOPQ, IRET } : RRSP;1 : RNONE; # Don't need register
];# 什么寄存器应该用作B源?
## What register should be used as the B source?
word srcB = [icode in { IOPQ, IRMMOVQ, IMRMOVQ,IIADDQ  } : rB;icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;1 : RNONE;  # Don't need register
];# E目的地应该使用什么寄存器?
## What register should be used as the E destination?
word dstE = [icode in { IRRMOVQ } && Cnd : rB;icode in { IIRMOVQ, IOPQ,IIADDQ} : rB;icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;1 : RNONE;  # Don't write any register
];# M目的地应该使用什么寄存器?
## What register should be used as the M destination?
word dstM = [icode in { IMRMOVQ, IPOPQ } : rA;1 : RNONE;  # Don't write any register
];################ Execute Stage   ####################################选择输入A到ALU
## Select input A to ALU
word aluA = [icode in { IRRMOVQ, IOPQ } : valA;icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ ,IIADDQ} : valC;icode in { ICALL, IPUSHQ } : -8;icode in { IRET, IPOPQ } : 8;# Other instructions don't need ALU
];#选择输入B到ALU
## Select input B to ALU
word aluB = [icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ ,IIADDQ} : valB;icode in { IRRMOVQ, IIRMOVQ } : 0;# Other instructions don't need ALU
];#设置ALU功能。默认加法
## Set the ALU function
word alufun = [icode == IOPQ : ifun;1 : ALUADD;
];#条件码是否需要更新?
## Should the condition codes be updated?
bool set_cc = icode in { IOPQ ,IIADDQ};################ Memory Stage    ##################################### Set read control signal
bool mem_read = icode in { IMRMOVQ, IPOPQ, IRET };## Set write control signal
bool mem_write = icode in { IRMMOVQ, IPUSHQ, ICALL };## Select memory address
word mem_addr = [icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : valE;icode in { IPOPQ, IRET } : valA;# Other instructions don't need address
];## Select memory input data
word mem_data = [# Value from registericode in { IRMMOVQ, IPUSHQ } : valA;# Return PCicode == ICALL : valP;# Default: Don't write anything
];## Determine instruction status
word Stat = [imem_error || dmem_error : SADR;!instr_valid: SINS;icode == IHALT : SHLT;1 : SAOK;
];################ Program Counter Update ############################## What address should instruction be fetched atword new_pc = [# Call.  Use instruction constanticode == ICALL : valC;# Taken branch.  Use instruction constanticode == IJXX && Cnd : valC;# Completion of RET instruction.  Use value from stackicode == IRET : valM;# Default: Use incremented PC1 : valP;
];
#/* $end seq-all-hcl */

C部分

这一部分推荐看完第五章再来完成。

在这一部分中,您将在目录sim/pipe中工作。

图2中的ncopy函数将len元素整数数组src复制到一个不重叠的dst,重新计算src中包含的正整数数。

图2: C版本的ncopy函数。看 sim/pipe/ncopy.c

图3:ncopy函数的Y86-64基线版本。看sim/pipe/ncopy.ys.

在C部分中,您的任务是修改ncopy.ys和pipe-full.hcl,以创建ncopy。让我们尽可能快地运行。
测试了一下默认版本的(即自带的图3),CPE平均为15.18,和文档写的一样,只是熟悉下流程。文档中写道他们最好的版本平均为7.48。

实现iaddq

看了下图3可以发现可以实现iaddq来提高性能,iaddq实现和B部分的一样。参考B部分的seq-full.hcl。

阶段 iaddq V,rB
取值 icode:ifun<-M1[PC]
rA:rB<-M1[PC+1]
valC<-M8[PC+2]
valP<-PC+10
译码
valB<-R[rB]
执行 valE<-valB+valC
Set CC
访存
写回 R[rB]<-valE
更新PC PC<-valP

取值阶段(Fetch Stage)

译码阶段(Decode Stage)

执行阶段(Execute Stage)

其他就不用改了
源文件pipe-full.hcl

#/* $begin pipe-all-hcl */
####################################################################
#    HCL Description of Control for Pipelined Y86-64 Processor     #
#    Copyright (C) Randal E. Bryant, David R. O'Hallaron, 2014     #
###################################################################### Your task is to implement the iaddq instruction
## The file contains a declaration of the icodes
## for iaddq (IIADDQ)
## Your job is to add the rest of the logic to make it work####################################################################
#    C Include's.  Don't alter these                               #
####################################################################quote '#include <stdio.h>'
quote '#include "isa.h"'
quote '#include "pipeline.h"'
quote '#include "stages.h"'
quote '#include "sim.h"'
quote 'int sim_main(int argc, char *argv[]);'
quote 'int main(int argc, char *argv[]){return sim_main(argc,argv);}'####################################################################
#    Declarations.  Do not change/remove/delete any of these       #
######################################################################### Symbolic representation of Y86-64 Instruction Codes #############
wordsig INOP    'I_NOP'
wordsig IHALT   'I_HALT'
wordsig IRRMOVQ 'I_RRMOVQ'
wordsig IIRMOVQ 'I_IRMOVQ'
wordsig IRMMOVQ 'I_RMMOVQ'
wordsig IMRMOVQ 'I_MRMOVQ'
wordsig IOPQ    'I_ALU'
wordsig IJXX    'I_JMP'
wordsig ICALL   'I_CALL'
wordsig IRET    'I_RET'
wordsig IPUSHQ  'I_PUSHQ'
wordsig IPOPQ   'I_POPQ'
# Instruction code for iaddq instruction
wordsig IIADDQ  'I_IADDQ'##### Symbolic represenations of Y86-64 function codes            #####
wordsig FNONE    'F_NONE'        # Default function code##### 引用的Y86-64寄存器的符号表示      #####
wordsig RRSP     'REG_RSP'             # 堆栈指针
wordsig RNONE    'REG_NONE'            # 表示“无寄存器”的特殊值##### ALU函数被显式引用          ##########################
wordsig ALUADD  'A_ADD'            # ALU should add its arguments##### 可能的指令状态值                       #####
wordsig SBUB    'STAT_BUB'    # 泡沫阶段
wordsig SAOK    'STAT_AOK'    # 正常执行
wordsig SADR    'STAT_ADR'    # 无效的内存地址
wordsig SINS    'STAT_INS'    # 无效的指令
wordsig SHLT    'STAT_HLT'    # 停止指令遇到##### 控制逻辑可以引用的信号 ################### 流水线寄存器F ##########################################wordsig F_predPC 'pc_curr->pc'      # PC预测值##### 取值阶段的中间值 ###########################wordsig imem_icode  'imem_icode'      # 指令存储器中的代码字段
wordsig imem_ifun   'imem_ifun'       # 指令存储器中的ifun字段
wordsig f_icode 'if_id_next->icode'  # (可能修改过的)指令代码
wordsig f_ifun  'if_id_next->ifun'   # 获取指令功能
wordsig f_valC  'if_id_next->valc'   # 被取指令的固定数据
wordsig f_valP  'if_id_next->valp'   # 下条指令的地址
boolsig imem_error 'imem_error'        # 来自指令存储器的错误信号
boolsig instr_valid 'instr_valid'    # 获取的指令有效吗?##### 流水线寄存器D ##########################################
wordsig D_icode 'if_id_curr->icode'   # 指令码
wordsig D_rA 'if_id_curr->ra'       # 指令的rA字段
wordsig D_rB 'if_id_curr->rb'       # 指令的rB字段
wordsig D_valP 'if_id_curr->valp'     # 递增PC##### 译码阶段的中间值  #########################wordsig d_srcA     'id_ex_next->srca'  # srcA来自译码指令
wordsig d_srcB   'id_ex_next->srcb'  # srcB来自译码指令
wordsig d_rvalA 'd_regvala'        # 从寄存器文件读取的valA
wordsig d_rvalB 'd_regvalb'        # 从寄存器文件读取的valB##### 流水线寄存器E   ##########################################
wordsig E_icode 'id_ex_curr->icode'   # 指令码
wordsig E_ifun  'id_ex_curr->ifun'    # 指令功能
wordsig E_valC  'id_ex_curr->valc'    # 常量数据
wordsig E_srcA  'id_ex_curr->srca'    # 源A寄存器ID
wordsig E_valA  'id_ex_curr->vala'    # 源 A 值
wordsig E_srcB  'id_ex_curr->srcb'    # 源B寄存器ID
wordsig E_valB  'id_ex_curr->valb'    # 源 B 值
wordsig E_dstE 'id_ex_curr->deste'    # 目的E寄存器ID
wordsig E_dstM 'id_ex_curr->destm'    # 目的M寄存器ID##### 执行阶段的中间值 #########################
wordsig e_valE 'ex_mem_next->vale'     # 由ALU产生的valE
boolsig e_Cnd 'ex_mem_next->takebranch' # 这个条件成立吗?
wordsig e_dstE 'ex_mem_next->deste'      # dstE(可能修改为RNONE)##### 流水线寄存器M                  #########################
wordsig M_stat 'ex_mem_curr->status'     # 指令状态
wordsig M_icode 'ex_mem_curr->icode'   # 指令码
wordsig M_ifun  'ex_mem_curr->ifun'    # 指令功能
wordsig M_valA  'ex_mem_curr->vala'      # 源 A 值
wordsig M_dstE 'ex_mem_curr->deste'    # 目的E寄存器ID
wordsig M_valE  'ex_mem_curr->vale'      # ALU E值
wordsig M_dstM 'ex_mem_curr->destm'    # 目的M寄存器ID
boolsig M_Cnd 'ex_mem_curr->takebranch'    # 状态标志
boolsig dmem_error 'dmem_error'           # 来自指令存储器的错误信号##### 访存阶段的中间值 ##########################
wordsig m_valM 'mem_wb_next->valm' # 由内存产生的valM
wordsig m_stat 'mem_wb_next->status'   # stat(可能修改为SADR)##### 流水线寄存器W ##########################################
wordsig W_stat 'mem_wb_curr->status'     # 指令状态
wordsig W_icode 'mem_wb_curr->icode'   # 指令码
wordsig W_dstE 'mem_wb_curr->deste'    # 目的E寄存器ID
wordsig W_valE  'mem_wb_curr->vale'      # ALU E值
wordsig W_dstM 'mem_wb_curr->destm'    # 目的M寄存器ID
wordsig W_valM  'mem_wb_curr->valm'    # 内存M值####################################################################
#    控制信号的定义。                                  #
#################################################################################### 取值阶段(Fetch Stage)     ##################################### 指令应该在哪个地址取
word f_pc = [# 预测失误的分支。在递增的PC上获取(Mispredicted branch.  Fetch at incremented PC)M_icode == IJXX && !M_Cnd : M_valA;# 完成RET指令W_icode == IRET : W_valM;# 默认值:使用PC的预测值1 : F_predPC;
];## 确定所取指令的代码
word f_icode = [imem_error : INOP;1: imem_icode;
];# 确定ifun
word f_ifun = [imem_error : FNONE;1: imem_ifun;
];# 指令有效吗?
bool instr_valid = f_icode in { INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ,IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ ,IIADDQ};# 确定所取指令的状态代码
word f_stat = [imem_error: SADR;!instr_valid : SINS;f_icode == IHALT : SHLT;1 : SAOK;
];# 获取的指令是否需要寄存器指示符字节?
bool need_regids =f_icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, IIRMOVQ, IRMMOVQ, IMRMOVQ ,IIADDQ};# 获取的指令需要一个常数字吗?
bool need_valC =f_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL ,IIADDQ};# 预测PC的下一个值
word f_predPC = [f_icode in { IJXX, ICALL } : f_valC;1 : f_valP;
];################ 译码阶段(Decode Stage) ######################################## 什么寄存器应该用作A源?
word d_srcA = [D_icode in { IRRMOVQ, IRMMOVQ, IOPQ, IPUSHQ  } : D_rA;D_icode in { IPOPQ, IRET } : RRSP;1 : RNONE; # Don't need register
];## 什么寄存器应该用作B源?
word d_srcB = [D_icode in { IOPQ, IRMMOVQ, IMRMOVQ  ,IIADDQ} : D_rB;D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;1 : RNONE;  # Don't need register
];## E目的地应该使用什么寄存器?
word d_dstE = [D_icode in { IRRMOVQ, IIRMOVQ, IOPQ,IIADDQ} : D_rB;D_icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;1 : RNONE;  # Don't write any register
];## M目的地应该使用什么寄存器?
word d_dstM = [D_icode in { IMRMOVQ, IPOPQ } : D_rA;1 : RNONE;  # Don't write any register
];## A值应该是多少?
## valA进入译码阶段
word d_valA = [D_icode in { ICALL, IJXX } : D_valP; # 使用递增PCd_srcA == e_dstE : e_valE;    # 从execute(执行)转发valEd_srcA == M_dstM : m_valM;    # 从Memory(访存)转发valMd_srcA == M_dstE : M_valE;    # 从Memory(访存)转发valEd_srcA == W_dstM : W_valM;    # 从write back(写回)转发valMd_srcA == W_dstE : W_valE;    # 从write back(写回)转发valE1 : d_rvalA;  # 使用从寄存器文件读取的值
];word d_valB = [d_srcB == e_dstE : e_valE;    # 从execute(执行)转发valEd_srcB == M_dstM : m_valM;    # 从Memory(访存)转发valMd_srcB == M_dstE : M_valE;    # 从Memory(访存)转发valEd_srcB == W_dstM : W_valM;    # 从write back(写回)转发valMd_srcB == W_dstE : W_valE;    # 从write back(写回)转发valE1 : d_rvalB;  # 使用从寄存器文件读取的值
];################ 执行阶段(Execute Stage) ####################################### 选择输入A到ALU
word aluA = [E_icode in { IRRMOVQ, IOPQ } : E_valA;E_icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ ,IIADDQ} : E_valC;E_icode in { ICALL, IPUSHQ } : -8;E_icode in { IRET, IPOPQ } : 8;# 其他指令不需要ALU
];## 选择输入B到ALU
word aluB = [E_icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, IPUSHQ, IRET, IPOPQ ,IIADDQ} : E_valB;E_icode in { IRRMOVQ, IIRMOVQ } : 0;# 其他指令不需要ALU
];## 设置ALU功能
word alufun = [E_icode == IOPQ : E_ifun;1 : ALUADD;
];## 条件码是否需要更新?
bool set_cc = (E_icode == IOPQ || E_icode == IIADDQ) &&# 状态仅在正常操作期间更改!m_stat in { SADR, SINS, SHLT } && !W_stat in { SADR, SINS, SHLT };## 在执行阶段生成valA
word e_valA = E_valA;    # Pass valA through stage# 在未采取有条件移动的情况下,将dstE设置为RNONE
## Set dstE to RNONE in event of not-taken conditional move
word e_dstE = [E_icode == IRRMOVQ && !e_Cnd : RNONE;1 : E_dstE;
];################ 访存阶段(Memory Stage) ######################################## 选择内存地址
word mem_addr = [M_icode in { IRMMOVQ, IPUSHQ, ICALL, IMRMOVQ } : M_valE;M_icode in { IPOPQ, IRET } : M_valA;# Other instructions don't need address
];## 设置读控制信号
bool mem_read = M_icode in { IMRMOVQ, IPOPQ, IRET };## 设置写控制信号
bool mem_write = M_icode in { IRMMOVQ, IPUSHQ, ICALL };#/* $begin pipe-m_stat-hcl */
## 更新状态
word m_stat = [dmem_error : SADR;1 : M_stat;
];
#/* $end pipe-m_stat-hcl */## 设置E端口寄存器ID
word w_dstE = W_dstE;## 设置E端口值
word w_valE = W_valE;## 设置M端口寄存器ID
word w_dstM = W_dstM;## 设置M端口值
word w_valM = W_valM;## 更新处理器状态
word Stat = [W_stat == SBUB : SAOK;1 : W_stat;
];################ 流水线寄存器控制(Pipeline Register Control) ################### 我应该暂停还是向管道寄存器F中注入气泡?
# 其中至多有一个是真的。
bool F_bubble = 0;
bool F_stall =# 加载/使用数据冒险条件E_icode in { IMRMOVQ, IPOPQ} &&E_dstM in { d_srcA, d_srcB } ||# 当ret通过管道时,在获取时延迟IRET in { D_icode, E_icode, M_icode };# 我应该暂停还是向管道寄存器D中注入气泡?
# 其中至多有一个是真的。
bool D_stall = # 加载/使用数据冒险条件E_icode in { IMRMOVQ, IPOPQ} &&E_dstM in { d_srcA, d_srcB };bool D_bubble =# Mispredicted branch(预测失误分支)(E_icode == IJXX && !e_Cnd) ||# 当ret通过管道时,在获取时延迟# 但不是加载/使用数据冒险条件!(E_icode in { IMRMOVQ, IPOPQ} && E_dstM in { d_srcA, d_srcB }) &&IRET in { D_icode, E_icode, M_icode };# 我应该暂停还是向管道寄存器E中注入气泡?
# 其中至多有一个是真的。
bool E_stall = 0;
bool E_bubble =# Mispredicted branch(预测失误分支)(E_icode == IJXX && !e_Cnd) ||# 加载/使用数据冒险条件E_icode in { IMRMOVQ, IPOPQ} &&E_dstM in { d_srcA, d_srcB};# 应该暂停还是向管道寄存器M中注入气泡?
# 其中至多有一个是真的。
bool M_stall = 0;
# 一旦异常通过内存阶段,就开始注入气泡
bool M_bubble = m_stat in { SADR, SINS, SHLT } || W_stat in { SADR, SINS, SHLT };# 应该暂停还是向管道寄存器W中注入气泡?
bool W_stall = W_stat in { SADR, SINS, SHLT };
bool W_bubble = 0;
#/* $end pipe-all-hcl */

在sim/pipe中输入一下命令,测试

linux> ./psim -t ../y86-code/asumi.yo
linux> (cd ../ptest;make SIM=../pipe/psim TFLAGS=-i)
linux> (cd ../ptest;make SIM=../pipe/psim)

测试成功。

CPE:12.70

实现了iaddq指令接下来修改ncopy.ys文件。把这种

irmovq $1, %r10
addq %r10, %rax

改为这种

iaddq $1,%rax

ncopy.ys如下所示

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy:##################################################################
# You can modify this portion# Loop headerxorq %rax,%rax        # count = 0;andq %rdx,%rdx     # len <= 0?jle Done     # if so, goto Done:Loop:    mrmovq (%rdi), %r10 # read val from src...rmmovq %r10, (%rsi)   # ...and store it to dstandq %r10, %r10     # val <= 0?jle Npos     # if so, goto Npos:iaddq $1, %rax       # count++
Npos:   iaddq $-1, %rdx     # len--iaddq $8, %rdi       # src++iaddq $8, %rsi     # dst++andq %rdx,%rdx     # len > 0?jg Loop            # if so, goto Loop:
##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

根据文档每次修改ncopy.ys,可以通过键入重建驱动程序

linux> make drivers

将构造一下两个有用的驱动程序:

  • sdriver.yo:一种小型驱动程序,它在带有4个元素的小数组上测试ncopy函数。如果您的解决方案是正确的,那么这个程序将在复制src数组后在寄存器%rax中以2的值停止。
  • ldriver.yo:一个大型驱动程序,它在带有63个元素的较大数组上测试一个ncopy函数。如果您的解决方案是正确的,那么在复制src数组之后,这个程序将在寄存器%rax中的值为31 (0x1f)时停止

用小的4元素数组测试解决方案

linux> ./psim -t sdriver.yo


测试正确

用大的63元素数组测试解决方案

linux> ./psim -t ldriver.yo


测试正确

在进行其他测试

使用ISA模拟器在块长度范围内测试代码。Perl脚本correctness.pl生成的驱动程序文件块长度从0到某个限制(默认值为65),再加上一些更大的块长度。它模拟它们(默认情况下使用YIS),并检查结果。它生成一个报告,显示每个块长度的状态:

linux> ./correctness.pl

会出现一大堆OK

没问题

在基准程序上测试管道模拟器。一旦你的模拟器能够正确地执行sdriver.ys和ldriver.ys,你应该在…/y86-code中测试Y86-64基准程序:

linux> (cd ../y86-code;make testpsim)

这将在基准测试程序上运行psim,并将结果与YIS进行比较。

没问题

使用大量回归测试测试管道模拟器。一旦可以正确地执行基准测试程序,就应该使用…/ptest中的回归测试来检查它。例如,如果您的解决方案实现了iaddq指令,那么

linux> (cd ../ptest;make SIM=../pipe/psim TFLAGS=-i)


没问题

使用流水线模拟器在一定范围的块长度上测试代码。最后,您可以在管道模拟器上运行与前面使用ISA模拟器所做的相同的代码测试

linux> ./correctness.pl -p

会出现一堆OK

也没问题。

最后来计算CPE值

linux> ./benchmark.pl

从15.18进步到12.70。但是还是0分(尴尬哈哈哈哈)

熟悉了流程。

CPE:12.55

因为采取的是总是选择分支的预测策略,所以这个总是去到ret处。

而很明显的是len<=0的概率肯定没len>0的高,所以改成

上面的测试流程走一遍
最后是CPE:12.55
分数:0

CPE:11.55


注意到这里,第一条指令从内存中读出寄存器%rdi的值,而下一条指令需要该值作为源操作数。所以这里会将下一条指令暂停一个周期,导致执行阶段中插入一个气泡。

每一次循环都要插入一个气泡,对于性能来说是很有点糟糕的。
所以我们可以在两条指令中间插入一条指令。
移动后面的指令,修改为:

可以看到这次就没有暂停了,变成了iaddq指令

运行的CPE为:11.55(0分)

CPE:9.06

老实说,从CPE来看上面都是一些小改动。最主要的是这个循环次数。根据文档上的提示,看了下第五章关于循环的部分。我想到了,一次循环我复制两块的值,整体循环就可以减少差不多一半。2 X 1循环展开
就可以两两复制。根据该思想写出如下代码:
ncopy.ys

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy:##################################################################
# You can modify this portion# Loop headerxorq %rax,%rax        # count = 0;iaddq $-2,%rdxandq %rdx,%rdxjl remianLoop: mrmovq (%rdi), %r10 mrmovq 8(%rdi),%r11 #避免加载使用冒险rmmovq %r10, (%rsi)    andq %r10, %r10     # val <= 0?jle NLoop2iaddq $1,%raxNLoop2:rmmovq %r11,8(%rsi)andq %r11,%r11jle nextLoopiaddq $1,%raxnextLoop:iaddq $16,%rdi      #src=src+2iaddq $16,%rsi      #dst=dst+2iaddq $-2,%rdxjge Loopremian:               iaddq $2,%rdx       #恢复iaddq $-1,%rdxjl Donemrmovq (%rdi), %r10 # iaddq $8, %rdi        # src++rmmovq %r10, (%rsi)    # iaddq $8, %rsi        # dst++iaddq $-1,%rdxandq %r10, %r10      # val <= 0?jle Doneiaddq $1, %rax       # count++
##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

测试一遍没问题。
最后的CPE为:9.06(28.8分。终于有分了)

CPE:8.34

上面经过2 X 1展开CPE降低了很多,后面我又试了3 X 1,4 X 1…到了把寄存器用完就是9 X 1展开,9 X 1展开最后可能剩下8-个元素,对这8-个元素在使用2 X 1展开,使CPE到达了8.34。
代码如下:
ncopy.ys

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy.ys:##################################################################
# You can modify this portion# Loop headerxorq %rax,%rax        # count = 0;andq %rdx,%rdx     # len != 0?jne startretstart:iaddq $-9,%rdx        #判断是否有9个数(含)以上andq %rdx,%rdx        jl LoopLNineLoop:   mrmovq (%rdi), %r8  mrmovq 8(%rdi),%r9  mrmovq 16(%rdi),%r10mrmovq 24(%rdi),%r11mrmovq 32(%rdi),%r12mrmovq 40(%rdi),%r13mrmovq 48(%rdi),%rcxmrmovq 56(%rdi),%rbxmrmovq 64(%rdi),%rbpiaddq $72, %rdi         #src+9rmmovq %r8, (%rsi)   rmmovq %r9,8(%rsi)rmmovq %r10,16(%rsi)rmmovq %r11,24(%rsi)rmmovq %r12,32(%rsi)rmmovq %r13,40(%rsi)rmmovq %rcx,48(%rsi)rmmovq %rbx,56(%rsi)rmmovq %rbp,64(%rsi)iaddq $72, %rsi           #dst+9andq %r8, %r8        jle two         iaddq $1,%rax
two:                        #判断9个数是否>0andq %r9,%r9jle threeiaddq $1, %rax
three:andq %r10,%r10jle fouriaddq $1,%rax
four:andq %r11,%r11jle fiveiaddq $1,%rax
five:andq %r12,%r12jle sixiaddq $1,%rax
six:andq %r13,%r13jle seveniaddq $1,%rax
seven:andq %rcx,%rcxjle eightiaddq $1,%rax
eight:andq %rbx,%rbxjle nineiaddq $1,%rax
nine:andq %rbp,%rbpjle Nposiaddq $1,%rax
Npos:iaddq $-9, %rdx            #下一轮循环andq %rdx,%rdx        jge Loop            LoopLNine:                  #两两复制:#iaddq $9,%rdx         #恢复#iaddq $-2,%rdx          #判断是否有2个数(含)以上iaddq $7,%rdx         #两iaddq二合一andq %rdx,%rdxjl remianLoop2:mrmovq (%rdi),%r10mrmovq 8(%rdi),%r11rmmovq %r10,(%rsi)andq %r10,%r10jle NLoop2iaddq $1,%raxNLoop2:rmmovq %r11,8(%rsi)andq %r11,%r11jle nextLoop2iaddq $1,%raxnextLoop2:iaddq $16,%rdiiaddq $16,%rsiiaddq $-2,%rdxjge Loop2remian:#iaddq $2,%rdx     #恢复#iaddq $-1,%rdx      #判断是否有一个数iaddq $1,%rdx      #两iaddq二合一jl Donemrmovq (%rdi), %r10    # iaddq $8, %rdi        # src++rmmovq %r10, (%rsi)    # iaddq $8, %rsi        # dst++iaddq $-1,%rdxandq %r10, %r10      # val <= 0?jle Doneiaddq $1, %rax       # count++
##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

测试一遍没问题。
最后的CPE为:8.34(43.2分。)

后面我还进行了10 X 1、11 ** X ** 1和12 X 1循环展开,性能已经到了瓶颈了都是8.34
优化了上面的代码,不然寄存器不够用
10 X 1循环展开+剩下的数2 X 1循环展开代码如下:
ncopy.ys:

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy:##################################################################
# You can modify this portion# Loop headerxorq %rax,%rax        # count = 0;andq %rdx,%rdx     # len != 0?jne startretstart:iaddq $-10,%rdx       #判断是否有10个数(含)以上andq %rdx,%rdx       jl LoopLTenLoop:    mrmovq (%rdi), %r8  mrmovq 8(%rdi),%r9  rmmovq %r8, (%rsi)  rmmovq %r9,8(%rsi)andq %r8, %r8     jle two         iaddq $1,%rax
two:                        andq %r9,%r9jle threeiaddq $1, %rax
three:mrmovq 16(%rdi),%r8mrmovq 24(%rdi),%r9rmmovq %r8,16(%rsi)rmmovq %r9,24(%rsi)andq %r8,%r8jle fouriaddq $1,%rax
four:andq %r9,%r9jle fiveiaddq $1,%rax
five:mrmovq 32(%rdi),%r8mrmovq 40(%rdi),%r9rmmovq %r8,32(%rsi)rmmovq %r9,40(%rsi)andq %r8,%r8jle sixiaddq $1,%rax
six:andq %r9,%r9jle seveniaddq $1,%rax
seven:mrmovq 48(%rdi),%r8mrmovq 56(%rdi),%r9rmmovq %r8,48(%rsi)rmmovq %r9,56(%rsi)andq %r8,%r8jle eightiaddq $1,%rax
eight:andq %r9,%r9jle nineiaddq $1,%rax
nine:mrmovq 64(%rdi),%r8mrmovq 72(%rdi),%r9rmmovq %r8,64(%rsi)rmmovq %r9,72(%rsi)andq %r8,%r8jle teniaddq $1,%rax
ten:andq %r9,%r9jle Nposiaddq $1,%rax
Npos:iaddq $80, %rdi            #src+10iaddq $80, %rsi         #dst+10iaddq $-10, %rdx            #下一轮循环andq %rdx,%rdx        jge Loop            LoopLTen:               #剩下的10-两两复制:#iaddq $10,%rdx          #恢复#iaddq $-2,%rdx          #判断是否有2个数(含)以上iaddq $8,%rdx         #两iaddq二合一andq %rdx,%rdxjl remianLoop2:mrmovq (%rdi),%r8mrmovq 8(%rdi),%r9rmmovq %r8,(%rsi)rmmovq %r9,8(%rsi)andq %r8,%r8jle NLoop2iaddq $1,%raxNLoop2:andq %r9,%r9jle nextLoop2iaddq $1,%raxnextLoop2:iaddq $16,%rdiiaddq $16,%rsiiaddq $-2,%rdxjge Loop2remian:#iaddq $2,%rdx     #恢复#iaddq $-1,%rdx      #判断是否有一个数iaddq $1,%rdx      #两iaddq二合一jl Donemrmovq (%rdi), %r10    # iaddq $8, %rdi        # src++rmmovq %r10, (%rsi)    # iaddq $8, %rsi        # dst++iaddq $-1,%rdxandq %r10, %r10      # val <= 0?jle Doneiaddq $1, %rax       # count++
##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

CPE:8.19

既然10 X 1的大头已经遇到性能瓶颈,那就只能从经过10 X 1循环展开剩下的元素下手,把10 X 1 + 2 X 1 循环展开改成10 X 1 + 3 X 1 + 2 X 1循环展开
ncopy.ys:

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy:##################################################################
# You can modify this portion# Loop headerxorq %rax,%rax        # count = 0;andq %rdx,%rdx     # len != 0?jne startretstart:iaddq $-10,%rdx       #判断是否有10个数(含)以上andq %rdx,%rdx       jl LoopLTenLoop:    mrmovq (%rdi), %r8  mrmovq 8(%rdi),%r9  rmmovq %r8, (%rsi)  rmmovq %r9,8(%rsi)andq %r8, %r8     jle two         iaddq $1,%rax
two:                        andq %r9,%r9jle threeiaddq $1, %rax
three:mrmovq 16(%rdi),%r8mrmovq 24(%rdi),%r9rmmovq %r8,16(%rsi)rmmovq %r9,24(%rsi)andq %r8,%r8jle fouriaddq $1,%rax
four:andq %r9,%r9jle fiveiaddq $1,%rax
five:mrmovq 32(%rdi),%r8mrmovq 40(%rdi),%r9rmmovq %r8,32(%rsi)rmmovq %r9,40(%rsi)andq %r8,%r8jle sixiaddq $1,%rax
six:andq %r9,%r9jle seveniaddq $1,%rax
seven:mrmovq 48(%rdi),%r8mrmovq 56(%rdi),%r9rmmovq %r8,48(%rsi)rmmovq %r9,56(%rsi)andq %r8,%r8jle eightiaddq $1,%rax
eight:andq %r9,%r9jle nineiaddq $1,%rax
nine:mrmovq 64(%rdi),%r8mrmovq 72(%rdi),%r9rmmovq %r8,64(%rsi)rmmovq %r9,72(%rsi)andq %r8,%r8jle teniaddq $1,%rax
ten:andq %r9,%r9jle Nposiaddq $1,%rax
Npos:iaddq $80, %rdi            #src+10iaddq $80, %rsi         #dst+10iaddq $-10, %rdx            #下一轮循环andq %rdx,%rdx        jge Loop            LoopLTen:                   #三三复制:#iaddq $10,%rdx            #恢复#iaddq $-3,%rdx          #判断是否有3个数(含)以上iaddq $7,%rdx         #两iaddq二合一andq %rdx,%rdxjl remianLoop2:mrmovq (%rdi),%r8mrmovq 8(%rdi),%r9mrmovq 16(%rdi),%r10rmmovq %r8,(%rsi)rmmovq %r9,8(%rsi)rmmovq %r10,16(%rsi)andq %r8,%r8jle NLoop2iaddq $1,%raxNLoop2:andq %r9,%r9jle NLoop3iaddq $1,%rax
NLoop3:andq %r10,%r10jle nextLoop2iaddq $1,%rax
nextLoop2:iaddq $24,%rdiiaddq $24,%rsiiaddq $-3,%rdxjge Loop2remian:#iaddq $3,%rdx      #恢复#iaddq $-2,%rdx      #判断是否有两个数iaddq $1,%rdx      #两iaddq二合一jne onemrmovq (%rdi), %r8 # mrmovq 8(%rdi), %r9rmmovq %r8, (%rsi)rmmovq %r9, 8(%rsi)andq %r8,%r8jle rLoop2iaddq $1,%rax
rLoop2:andq %r9,%r9jle Doneiaddq $1, %rax       # count++
one:iaddq $1,%rdxjne Donemrmovq (%rdi), %r10    # iaddq $8, %rdi        # src++rmmovq %r10, (%rsi)    # iaddq $8, %rsi        # dst++andq %r10, %r10        # val <= 0?jle Doneiaddq $1, %rax       # count++##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

CPE:7.80

对CPE:8.19的代码进行了优化

  • (%rax)的值默认是0,所以去掉开头的xorq %rax,%rax
  • 仔细观察代码
    andq %rdx,%rdx
    jne start
    ret
    在one中也可以完成判断,所以去掉
  • 以及各种iaddq %rdx后跟andq %rdx的,因为iaddq就会设置条件码,所以去掉andq %rdx,%rdx
    iaddq $-10,%rdx
    andq %rdx,%rdx

ncpoy.ys:

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy:##################################################################
# You can modify this portion# Loop headeriaddq $-10,%rdx       #判断是否有10个数(含)以上jl LoopLTenLoop: mrmovq (%rdi), %r8  mrmovq 8(%rdi),%r9  rmmovq %r8, (%rsi)  rmmovq %r9,8(%rsi)andq %r8, %r8     jle two         iaddq $1,%rax
two:                        andq %r9,%r9jle threeiaddq $1, %rax
three:mrmovq 16(%rdi),%r8mrmovq 24(%rdi),%r9rmmovq %r8,16(%rsi)rmmovq %r9,24(%rsi)andq %r8,%r8jle fouriaddq $1,%rax
four:andq %r9,%r9jle fiveiaddq $1,%rax
five:mrmovq 32(%rdi),%r8mrmovq 40(%rdi),%r9rmmovq %r8,32(%rsi)rmmovq %r9,40(%rsi)andq %r8,%r8jle sixiaddq $1,%rax
six:andq %r9,%r9jle seveniaddq $1,%rax
seven:mrmovq 48(%rdi),%r8mrmovq 56(%rdi),%r9rmmovq %r8,48(%rsi)rmmovq %r9,56(%rsi)andq %r8,%r8jle eightiaddq $1,%rax
eight:andq %r9,%r9jle nineiaddq $1,%rax
nine:mrmovq 64(%rdi),%r8mrmovq 72(%rdi),%r9rmmovq %r8,64(%rsi)rmmovq %r9,72(%rsi)andq %r8,%r8jle teniaddq $1,%rax
ten:andq %r9,%r9jle Nposiaddq $1,%rax
Npos:iaddq $80, %rdi            #src+10iaddq $80, %rsi         #dst+10iaddq $-10, %rdx            #下一轮循环andq %rdx,%rdx        jge Loop            LoopLTen:                   #三三复制:#iaddq $10,%rdx            #恢复#iaddq $-3,%rdx          #判断是否有3个数(含)以上iaddq $7,%rdx         #两iaddq二合一jl remianLoop2:mrmovq (%rdi),%r8mrmovq 8(%rdi),%r9mrmovq 16(%rdi),%r10rmmovq %r8,(%rsi)rmmovq %r9,8(%rsi)rmmovq %r10,16(%rsi)andq %r8,%r8jle NLoop2iaddq $1,%raxNLoop2:andq %r9,%r9jle NLoop3iaddq $1,%rax
NLoop3:andq %r10,%r10jle nextLoop2iaddq $1,%rax
nextLoop2:iaddq $24,%rdiiaddq $24,%rsiiaddq $-3,%rdxjge Loop2remian:#iaddq $3,%rdx      #恢复#iaddq $-2,%rdx      #判断是否有两个数iaddq $1,%rdx      #两iaddq二合一jne onemrmovq (%rdi), %r8 # mrmovq 8(%rdi), %r9rmmovq %r8, (%rsi)rmmovq %r9, 8(%rsi)andq %r8,%r8jle rLoop2iaddq $1,%rax
rLoop2:andq %r9,%r9jle Doneiaddq $1, %rax       # count++
one:iaddq $1,%rdxjne Donemrmovq (%rdi), %r10    # iaddq $8, %rdi        # src++rmmovq %r10, (%rsi)    # iaddq $8, %rsi        # dst++andq %r10, %r10        # val <= 0?jle Doneiaddq $1, %rax       # count++##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

CPE:7.49(满分)

上面的CPE:7.80就是前面的运行的太慢了

要优化这一部分才有降低CPE的可能,那就是从剩下的元素入手。
有一个方法就是让9个方法往下流,然后我们根据剩下的元素来跳转到从哪里开始流即可。然后我有了这个思路,刚好打开了百度查阅到了同思想。
像这样子流:

remain9:mrmovq 64(%rdi),%r8andq %r8,%r8rmmovq %r8,64(%rsi)   remain8:mrmovq 56(%rdi),%r8jle remain82iaddq $1,%raxremain82:rmmovq %r8,56(%rsi)andq %r8,%r8
remain7:mrmovq 48(%rdi),%r8jle remain72iaddq $1,%rax
remain72:rmmovq %r8,48(%rsi)andq %r8,%r8
remain6:mrmovq 40(%rdi),%r8jle remain62iaddq $1,%rax
remain62:rmmovq %r8,40(%rsi)andq %r8,%r8
remain5:mrmovq 32(%rdi),%r8jle remain52iaddq $1,%rax
remain52:rmmovq %r8,32(%rsi)andq %r8,%r8
remain4:mrmovq 24(%rdi),%r8jle remain42iaddq $1,%rax
remain42:rmmovq %r8,24(%rsi)andq %r8,%r8
remain3:mrmovq 16(%rdi),%r8jle remain32iaddq $1,%rax
remain32:rmmovq %r8,16(%rsi)andq %r8,%r8
remain2:mrmovq 8(%rdi),%r8jle remain22iaddq $1,%rax
remain22:rmmovq %r8,8(%rsi)andq %r8,%r8
remain1:mrmovq (%rdi),%r8jle remain12iaddq $1,%rax
remain12:rmmovq %r8,(%rsi)andq %r8,%r8jle Doneiaddq $1,%rax

我们只要根据剩下多少个元素决定从哪里开始即可
这个要快,因为要判断,不可能按顺序判断(9 8 7…)这样1 2越少越慢。所以我们用查找树形结构来处理,像下面这样,。
代码如下

remain:                      #剩余的iaddq $7,%rdx           jl left                 #len<3jg right               #len>3je remain3             #len==3left:iaddq $2,%rdx         #len==1je remain1iaddq $-1,%rdx           #len==2je remain2ret                  #len==0right:iaddq $-3,%rdx           #len<=6jg rightRightje remain6              #len==6iaddq $1,%rdxje remain5                #len==5jmp remain4            #len==4
rightRight:iaddq $-2,%rdxjl remain7je remain8

最后完整的代码
ncopy.ys:

#/* $begin ncopy-ys */
##################################################################
# ncopy.ys - Copy a src block of len words to dst.
# Return the number of positive words (>0) contained in src.
#
# Include your name and ID here.
#
# Describe how and why you modified the baseline code.
#
##################################################################
# Do not modify this portion
# Function prologue.
# %rdi = src, %rsi = dst, %rdx = len
ncopy:##################################################################
# You can modify this portion# Loop headeriaddq $-10,%rdx       #判断是否有10个数(含)以上jl remainLoop:   mrmovq (%rdi), %r8  mrmovq 8(%rdi),%r9  rmmovq %r8, (%rsi)  rmmovq %r9,8(%rsi)andq %r8, %r8     jle two         iaddq $1,%rax
two:                        andq %r9,%r9jle threeiaddq $1, %rax
three:mrmovq 16(%rdi),%r8mrmovq 24(%rdi),%r9rmmovq %r8,16(%rsi)rmmovq %r9,24(%rsi)andq %r8,%r8jle fouriaddq $1,%rax
four:andq %r9,%r9jle fiveiaddq $1,%rax
five:mrmovq 32(%rdi),%r8mrmovq 40(%rdi),%r9rmmovq %r8,32(%rsi)rmmovq %r9,40(%rsi)andq %r8,%r8jle sixiaddq $1,%rax
six:andq %r9,%r9jle seveniaddq $1,%rax
seven:mrmovq 48(%rdi),%r8mrmovq 56(%rdi),%r9rmmovq %r8,48(%rsi)rmmovq %r9,56(%rsi)andq %r8,%r8jle eightiaddq $1,%rax
eight:andq %r9,%r9jle nineiaddq $1,%rax
nine:mrmovq 64(%rdi),%r8mrmovq 72(%rdi),%r9rmmovq %r8,64(%rsi)rmmovq %r9,72(%rsi)andq %r8,%r8jle teniaddq $1,%rax
ten:andq %r9,%r9jle Nposiaddq $1,%rax
Npos:iaddq $80, %rdi            #src+10iaddq $80, %rsi         #dst+10iaddq $-10, %rdx            #下一轮循环jge Loopremain:                       #剩余的iaddq $7,%rdx           jl left                 #len<3jg right               #len>3je remain3             #len==3left:iaddq $2,%rdx         #len==1je remain1iaddq $-1,%rdx           #len==2je remain2ret                  #len==0right:iaddq $-3,%rdx           #len<=6jg rightRightje remain6              #len==6iaddq $1,%rdxje remain5                #len==5jmp remain4            #len==4
rightRight:iaddq $-2,%rdxjl remain7je remain8remain9:mrmovq 64(%rdi),%r8andq %r8,%r8rmmovq %r8,64(%rsi) remain8:mrmovq 56(%rdi),%r8jle remain82iaddq $1,%raxremain82:rmmovq %r8,56(%rsi)andq %r8,%r8
remain7:mrmovq 48(%rdi),%r8jle remain72iaddq $1,%rax
remain72:rmmovq %r8,48(%rsi)andq %r8,%r8
remain6:mrmovq 40(%rdi),%r8jle remain62iaddq $1,%rax
remain62:rmmovq %r8,40(%rsi)andq %r8,%r8
remain5:mrmovq 32(%rdi),%r8jle remain52iaddq $1,%rax
remain52:rmmovq %r8,32(%rsi)andq %r8,%r8
remain4:mrmovq 24(%rdi),%r8jle remain42iaddq $1,%rax
remain42:rmmovq %r8,24(%rsi)andq %r8,%r8
remain3:mrmovq 16(%rdi),%r8jle remain32iaddq $1,%rax
remain32:rmmovq %r8,16(%rsi)andq %r8,%r8
remain2:mrmovq 8(%rdi),%r8jle remain22iaddq $1,%rax
remain22:rmmovq %r8,8(%rsi)andq %r8,%r8
remain1:mrmovq (%rdi),%r8jle remain12iaddq $1,%rax
remain12:rmmovq %r8,(%rsi)andq %r8,%r8jle Doneiaddq $1,%rax##################################################################
# Do not modify the following section of code
# Function epilogue.
Done:ret
##################################################################
# Keep the following label at the end of your function
End:
#/* $end ncopy-ys */

测试:

linux> ./correctness.pl


CPE:7.49(60分。满分)

那个树(以3为根)不一定是最优的我还试了以5为根,CPE大概是7.51左右,差了一点点,我觉得可能是因为64的1 2 3 4的原因,总体来看要最短的。可能还有其他的方法能快那么一点点。

《深入理解计算机系统》实验四Architecture Lab相关推荐

  1. 《深入理解计算机系统》实验四Architecture Lab下载和官方文档机翻

    前言 <深入理解计算机系统>官网:http://csapp.cs.cmu.edu/3e/labs.html 该篇文章是是实验四Architecture Lab中的Writeup(archl ...

  2. 《深入理解计算机系统》Y86-64实验四Architecture Lab环境安装

    前言 第四章提到的Y86-64和实验四Architecture Lab的环境安装. 先从官网下载文件: <深入理解计算机系统>官网:http://csapp.cs.cmu.edu/3e/l ...

  3. 深入理解计算机系统 -资料整理 高清中文版_在所不辞的博客-CSDN博客_深入理解计算机系统第四版pdf

    深入理解计算机系统 -资料整理 高清中文版_在所不辞的博客-CSDN博客_深入理解计算机系统第四版pdf

  4. 计算机系统实验四:二进制程序逆向工程

    参考教材:计算机系统基础 第二版 袁春风 机械工业出版社 参考慕课:计算机系统基础(四):编程与调试实践 https://www.icourse163.org/learn/NJU-1449521162 ...

  5. 《深入理解计算机系统》:Cache Lab

    第1关:Part A 任务描述 本关任务:完成csim.c文件,实现一个cache simulator,模拟Cache的访问过程.替换算法采用最近最少使用替换策略(LRU). 可参考资料:官网实验文档 ...

  6. 深入理解计算机系统第四版_《深入理解计算机系统》读书笔记 —— 第一章 计算机系统漫游...

    本书第一章沿着一个程序的生命周期,简要地介绍一些逐步出现的关键概念.专业术语和组成部分. 一.信息就是位+上下文 在计算机系统中所有的信息都由一串比特来表示. 一串相同的比特(或者几个相同的字节)可以 ...

  7. 哈工大计算机系统实验四——链接

    链接这一块呢,先看了李春凤老师的慕课,然后看一遍课本,然后来做实验,感觉真的懂了一样 把火炬传下去! 实验报告 实 验(四 题     目 LinkLab 链接 专       业 xxxx 学    ...

  8. 深入理解计算机系统第四版_深入理解计算机系统之存储器层次结构

    我的计算机模型是这样的: CPU执行指令,内存犹如一个巨大的字节数组,存储着指令和数据,硬盘保存着各种程序与程序用到的数据.I/O完成输入输出的功能.在本文中我们抛开I/O,谈一谈关于CPU,内存,硬 ...

  9. csapp深入理解计算机系统实验

    文章目录 实验0 环境配置 虚拟机下载 ubuntu系统 下载gcc gdb 和 vim 下载csapp实验包 实验1 datalab-handout 实验0 环境配置 配置了一下午加一晚上的环境,遇 ...

  10. 深入理解计算机系统第四章(4.55-4.58)

    /* ***4.55 */ 思路:将valC的值通过E_valB传过流水线,valP的逻辑不变 #/* $begin pipe-all-hcl */ ######################### ...

最新文章

  1. 取消Eclipse等号、分号、空格代码自动补全
  2. Java List部分截取,获得指定长度子集合
  3. 数据相关,资源相关,控制相关的解决方法
  4. 快速了解Spring Cloud
  5. Shiro和Zuul权限管理整合方案
  6. linux系统密码自动丢失,Linux系统密码丢失后的5种解决方法
  7. 图像增广——图片旋转任意角度(python实现)
  8. PDF加密以及去除密码小妙招
  9. 在浏览器输入一句话之后是如何响应的
  10. msp心形16个闪灯c语言程序,心形流水灯程序
  11. 邮件服务-postfix
  12. Linux解压rar压缩文件的详细方法
  13. cs224u Overview of the Stanford Sentiment Treebank
  14. [Pandas] 分组比例计算求和
  15. 如何粉碎文件 - C#
  16. MATLAB运行程序报错:“等号右侧的输出数目不足,不满足赋值要求。”的解决方法
  17. VR,正在上演一出“风月宝鉴”
  18. 电商网站,商品规格的设计思路
  19. 一场会议让我从初流学到APQP
  20. 【文献翻译】copy and translate 软件

热门文章

  1. 02 Jmonkey3.2.0+Nifty1.4.2实现GUI
  2. 搜狗蜘蛛池快速提升蜘蛛收录排名
  3. 百练2706 麦森数
  4. java实现极简单的 TXT小说阅读器(第四版)
  5. php自动生成phpunit,PHP单元测试利器 PHPUNIT深入用法(三)
  6. Android选择颜色,尺码联动
  7. 炼数成金(dataguru)IT技能修炼
  8. 数学建模预测模型总结
  9. matlab使用记录--读取当前文件夹所有文件、找到最新创建的文件、app designer打开文件选择窗口
  10. 华为普工一个月的工资是多少?