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

2023-11-20

前言

《深入理解计算机系统》实验四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 0
	irmovq stack,%rsp
	call main
	halt

	.align 8
ele1:
	.quad 0x00a
	.quad ele2
ele2:
	.quad 0x0b0
	.quad ele3
ele3:
	.quad 0xc00
	.quad 0

main:
	irmovq ele1,%rdi
	call sum_list
	ret

# long sum_list(list_ptr ls)
# ls in %rdi
sum_list:
	xorq %rax,%rax		# val = 0
	mrmovq (%rdi),%rsi
	andq %rsi,%rsi		# Set CC
	jmp test			# Goto test

loop:
	addq %rsi,%rax		#累加
	mrmovq 8(%rdi),%rdi	#指向下一个节点
	andq %rdi,%rdi		#set CC 下一个节点是否是0
	mrmovq (%rdi),%rsi	#(%rdi)表示节点的值
	
test:
	jne loop		# Stop when 0
	ret				# 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 0
	irmovq stack,%rsp
	call main
	halt

	.align 8
ele1:
	.quad 0x00a
	.quad ele2
ele2:
	.quad 0x0b0
	.quad ele3
ele3:
	.quad 0xc00
	.quad 0

main:
	irmovq ele1,%rdi
	call rsum_list
	ret

# long rsum_list(list_ptr ls)
# ls in %rdi
rsum_list:
	pushq %rbx

	xorq %rax,%rax		# val = 0
	rrmovq %rdi,%rsi	
	andq %rsi,%rsi		#判断当前节点是否为0
	je exit
	mrmovq (%rdi),%rbx	#获取当前节点的值val
	mrmovq 8(%rdi),%rdi	#指向下一节点
	call rsum_list		#递归。返回值(%rax)即rest
	addq %rbx,%rax		#val+rest

	popq %rbx
	ret					# Return

exit:
	popq %rbx
	ret

	.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 0
	irmovq stack,%rsp
	call main
	halt

	.align 8
src:
	.quad 0x00a
	.quad 0x0b0
	.quad 0xc00

dest:
	.quad 0x111
	.quad 0x222
	.quad 0x333

main:
	irmovq src,%rdi
	irmovq dest,%rsi
	irmovq $3,%rdx		#有3个要复制

	call copy_block		#copy_block(%rdi,%rsi,%rdx)

	ret

copy_block:

	pushq %rbx			#%rbx是被调用者保护,入栈

	xorq %rax,%rax
	irmovq $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的复制给dest
	addq %r8,%rsi		#指向下一个复制区

	xorq %rbx,%rax		#计算所有被复制单词的校验和(Xor)

	subq %r9,%rdx		#还剩下几个

	andq %rdx,%rdx		#>0继续循环
	jg loop

exit:
	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 register
	icode in { IRMMOVQ, IPUSHQ } : valA;
	# Return PC
	icode == 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 at

word new_pc = [
	# Call.  Use instruction constant
	icode == ICALL : valC;
	# Taken branch.  Use instruction constant
	icode == IJXX && Cnd : valC;
	# Completion of RET instruction.  Use value from stack
	icode == IRET : valM;
	# Default: Use incremented PC
	1 : 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; # 使用递增PC
	d_srcA == e_dstE : e_valE;    # 从execute(执行)转发valE
	d_srcA == M_dstM : m_valM;    # 从Memory(访存)转发valM
	d_srcA == M_dstE : M_valE;    # 从Memory(访存)转发valE
	d_srcA == W_dstM : W_valM;    # 从write back(写回)转发valM
	d_srcA == W_dstE : W_valE;    # 从write back(写回)转发valE
	1 : d_rvalA;  # 使用从寄存器文件读取的值
];

word d_valB = [
	d_srcB == e_dstE : e_valE;    # 从execute(执行)转发valE
	d_srcB == M_dstM : m_valM;    # 从Memory(访存)转发valM
	d_srcB == M_dstE : M_valE;    # 从Memory(访存)转发valE
	d_srcB == W_dstM : W_valM;    # 从write back(写回)转发valM
	d_srcB == W_dstE : W_valE;    # 从write back(写回)转发valE
	1 : 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 header
	xorq %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 dst
	andq %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 header
	xorq %rax,%rax		# count = 0;

	iaddq $-2,%rdx
	andq %rdx,%rdx
	jl remian

Loop:	
	mrmovq (%rdi), %r10	
	mrmovq 8(%rdi),%r11	#避免加载使用冒险

	rmmovq %r10, (%rsi)	

	andq %r10, %r10		# val <= 0?
	jle NLoop2
	iaddq $1,%rax

NLoop2:
	rmmovq %r11,8(%rsi)
	andq %r11,%r11
	jle nextLoop
	iaddq $1,%rax

nextLoop:
	iaddq $16,%rdi		#src=src+2
	iaddq $16,%rsi		#dst=dst+2
	iaddq $-2,%rdx
	jge Loop

remian:				
	iaddq $2,%rdx		#恢复
	iaddq $-1,%rdx
	jl Done
	mrmovq (%rdi), %r10	# 
	iaddq $8, %rdi		# src++

	rmmovq %r10, (%rsi)	# 
	iaddq $8, %rsi		# dst++

	iaddq $-1,%rdx

	andq %r10, %r10		# val <= 0?
	jle Done
	iaddq $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 header
	xorq %rax,%rax		# count = 0;

	andq %rdx,%rdx		# len != 0?
	jne start
	ret

start:
	iaddq $-9,%rdx		#判断是否有9个数(含)以上

	andq %rdx,%rdx		
	jl LoopLNine

Loop:	
	mrmovq (%rdi), %r8	
	mrmovq 8(%rdi),%r9	
	mrmovq 16(%rdi),%r10
	mrmovq 24(%rdi),%r11
	mrmovq 32(%rdi),%r12
	mrmovq 40(%rdi),%r13
	mrmovq 48(%rdi),%rcx
	mrmovq 56(%rdi),%rbx
	mrmovq 64(%rdi),%rbp
	

	iaddq $72, %rdi			#src+9

	rmmovq %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+9
	
	andq %r8, %r8		
	jle two			
	iaddq $1,%rax
two:						#判断9个数是否>0
	andq %r9,%r9
	jle three
	iaddq $1, %rax		
three:
	andq %r10,%r10
	jle four
	iaddq $1,%rax
four:
	andq %r11,%r11
	jle five
	iaddq $1,%rax
five:
	andq %r12,%r12
	jle six
	iaddq $1,%rax
six:
	andq %r13,%r13
	jle seven
	iaddq $1,%rax
seven:
	andq %rcx,%rcx
	jle eight
	iaddq $1,%rax
eight:
	andq %rbx,%rbx
	jle nine
	iaddq $1,%rax
nine:
	andq %rbp,%rbp
	jle Npos
	iaddq $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,%rdx

	jl remian

Loop2:
	mrmovq (%rdi),%r10
	mrmovq 8(%rdi),%r11

	rmmovq %r10,(%rsi)

	andq %r10,%r10
	jle NLoop2
	iaddq $1,%rax

NLoop2:
	rmmovq %r11,8(%rsi)
	andq %r11,%r11
	jle nextLoop2
	iaddq $1,%rax

nextLoop2:
	iaddq $16,%rdi
	iaddq $16,%rsi
	iaddq $-2,%rdx
	jge Loop2

remian:
	#iaddq $2,%rdx		#恢复
	#iaddq $-1,%rdx		#判断是否有一个数

	iaddq $1,%rdx		#两iaddq二合一
	jl Done
	mrmovq (%rdi), %r10	# 
	iaddq $8, %rdi		# src++

	rmmovq %r10, (%rsi)	# 
	iaddq $8, %rsi		# dst++

	iaddq $-1,%rdx

	andq %r10, %r10		# val <= 0?
	jle Done
	iaddq $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 header
	xorq %rax,%rax		# count = 0;

	andq %rdx,%rdx		# len != 0?
	jne start
	ret

start:
	iaddq $-10,%rdx		#判断是否有10个数(含)以上

	andq %rdx,%rdx		
	jl LoopLTen

Loop:	
	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,%r9
	jle three
	iaddq $1, %rax		
three:
	mrmovq 16(%rdi),%r8
	mrmovq 24(%rdi),%r9

	rmmovq %r8,16(%rsi)
	rmmovq %r9,24(%rsi)

	andq %r8,%r8
	jle four
	iaddq $1,%rax
four:
	andq %r9,%r9
	jle five
	iaddq $1,%rax
five:
	mrmovq 32(%rdi),%r8
	mrmovq 40(%rdi),%r9

	rmmovq %r8,32(%rsi)
	rmmovq %r9,40(%rsi)
	andq %r8,%r8
	jle six
	iaddq $1,%rax
six:
	andq %r9,%r9
	jle seven
	iaddq $1,%rax
seven:
	mrmovq 48(%rdi),%r8
	mrmovq 56(%rdi),%r9

	rmmovq %r8,48(%rsi)
	rmmovq %r9,56(%rsi)
	andq %r8,%r8
	jle eight
	iaddq $1,%rax
eight:
	andq %r9,%r9
	jle nine
	iaddq $1,%rax
nine:
	mrmovq 64(%rdi),%r8
	mrmovq 72(%rdi),%r9

	rmmovq %r8,64(%rsi)
	rmmovq %r9,72(%rsi)

	andq %r8,%r8
	jle ten
	iaddq $1,%rax
ten:
	andq %r9,%r9
	jle Npos
	iaddq $1,%rax
Npos:
	
	iaddq $80, %rdi			#src+10
	iaddq $80, %rsi			#dst+10

	iaddq $-10, %rdx			#下一轮循环

	andq %rdx,%rdx		
	jge Loop			

LoopLTen:				#剩下的10-两两复制:
	#iaddq $10,%rdx			#恢复
	#iaddq $-2,%rdx			#判断是否有2个数(含)以上

	iaddq $8,%rdx			#两iaddq二合一

	andq %rdx,%rdx

	jl remian

Loop2:
	mrmovq (%rdi),%r8
	mrmovq 8(%rdi),%r9

	rmmovq %r8,(%rsi)
	rmmovq %r9,8(%rsi)


	andq %r8,%r8
	jle NLoop2
	iaddq $1,%rax

NLoop2:
	andq %r9,%r9
	jle nextLoop2
	iaddq $1,%rax

nextLoop2:
	iaddq $16,%rdi
	iaddq $16,%rsi
	iaddq $-2,%rdx
	jge Loop2

remian:
	#iaddq $2,%rdx		#恢复
	#iaddq $-1,%rdx		#判断是否有一个数

	iaddq $1,%rdx		#两iaddq二合一
	jl Done
	mrmovq (%rdi), %r10	# 
	iaddq $8, %rdi		# src++

	rmmovq %r10, (%rsi)	# 
	iaddq $8, %rsi		# dst++

	iaddq $-1,%rdx

	andq %r10, %r10		# val <= 0?
	jle Done
	iaddq $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 header
	xorq %rax,%rax		# count = 0;

	andq %rdx,%rdx		# len != 0?
	jne start
	ret

start:
	iaddq $-10,%rdx		#判断是否有10个数(含)以上

	andq %rdx,%rdx		
	jl LoopLTen

Loop:	
	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,%r9
	jle three
	iaddq $1, %rax		
three:
	mrmovq 16(%rdi),%r8
	mrmovq 24(%rdi),%r9

	rmmovq %r8,16(%rsi)
	rmmovq %r9,24(%rsi)

	andq %r8,%r8
	jle four
	iaddq $1,%rax
four:
	andq %r9,%r9
	jle five
	iaddq $1,%rax
five:
	mrmovq 32(%rdi),%r8
	mrmovq 40(%rdi),%r9

	rmmovq %r8,32(%rsi)
	rmmovq %r9,40(%rsi)
	andq %r8,%r8
	jle six
	iaddq $1,%rax
six:
	andq %r9,%r9
	jle seven
	iaddq $1,%rax
seven:
	mrmovq 48(%rdi),%r8
	mrmovq 56(%rdi),%r9

	rmmovq %r8,48(%rsi)
	rmmovq %r9,56(%rsi)
	andq %r8,%r8
	jle eight
	iaddq $1,%rax
eight:
	andq %r9,%r9
	jle nine
	iaddq $1,%rax
nine:
	mrmovq 64(%rdi),%r8
	mrmovq 72(%rdi),%r9

	rmmovq %r8,64(%rsi)
	rmmovq %r9,72(%rsi)

	andq %r8,%r8
	jle ten
	iaddq $1,%rax
ten:
	andq %r9,%r9
	jle Npos
	iaddq $1,%rax
Npos:
	
	iaddq $80, %rdi			#src+10
	iaddq $80, %rsi			#dst+10

	iaddq $-10, %rdx			#下一轮循环

	andq %rdx,%rdx		
	jge Loop			

LoopLTen:					#三三复制:
	#iaddq $10,%rdx			#恢复
	#iaddq $-3,%rdx			#判断是否有3个数(含)以上

	iaddq $7,%rdx			#两iaddq二合一

	andq %rdx,%rdx

	jl remian

Loop2:
	mrmovq (%rdi),%r8
	mrmovq 8(%rdi),%r9
	mrmovq 16(%rdi),%r10

	rmmovq %r8,(%rsi)
	rmmovq %r9,8(%rsi)
	rmmovq %r10,16(%rsi)

	andq %r8,%r8
	jle NLoop2
	iaddq $1,%rax

NLoop2:
	andq %r9,%r9
	jle NLoop3
	iaddq $1,%rax
NLoop3:
	andq %r10,%r10
	jle nextLoop2
	iaddq $1,%rax
nextLoop2:
	iaddq $24,%rdi
	iaddq $24,%rsi
	iaddq $-3,%rdx
	jge Loop2

remian:
	#iaddq $3,%rdx		#恢复
	#iaddq $-2,%rdx		#判断是否有两个数

	iaddq $1,%rdx		#两iaddq二合一
	jne one
	mrmovq (%rdi), %r8	# 
	mrmovq 8(%rdi), %r9

	rmmovq %r8, (%rsi)
	rmmovq %r9, 8(%rsi)

	andq %r8,%r8
	jle rLoop2
	iaddq $1,%rax
rLoop2:
	andq %r9,%r9
	jle Done
	iaddq $1, %rax		# count++
one:
	iaddq $1,%rdx
	jne Done

	mrmovq (%rdi), %r10	# 
	iaddq $8, %rdi		# src++

	rmmovq %r10, (%rsi)	# 
	iaddq $8, %rsi		# dst++
	andq %r10, %r10		# val <= 0?
	jle Done
	iaddq $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 header
	iaddq $-10,%rdx		#判断是否有10个数(含)以上
		
	jl LoopLTen

Loop:	
	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,%r9
	jle three
	iaddq $1, %rax		
three:
	mrmovq 16(%rdi),%r8
	mrmovq 24(%rdi),%r9

	rmmovq %r8,16(%rsi)
	rmmovq %r9,24(%rsi)

	andq %r8,%r8
	jle four
	iaddq $1,%rax
four:
	andq %r9,%r9
	jle five
	iaddq $1,%rax
five:
	mrmovq 32(%rdi),%r8
	mrmovq 40(%rdi),%r9

	rmmovq %r8,32(%rsi)
	rmmovq %r9,40(%rsi)
	andq %r8,%r8
	jle six
	iaddq $1,%rax
six:
	andq %r9,%r9
	jle seven
	iaddq $1,%rax
seven:
	mrmovq 48(%rdi),%r8
	mrmovq 56(%rdi),%r9

	rmmovq %r8,48(%rsi)
	rmmovq %r9,56(%rsi)
	andq %r8,%r8
	jle eight
	iaddq $1,%rax
eight:
	andq %r9,%r9
	jle nine
	iaddq $1,%rax
nine:
	mrmovq 64(%rdi),%r8
	mrmovq 72(%rdi),%r9

	rmmovq %r8,64(%rsi)
	rmmovq %r9,72(%rsi)

	andq %r8,%r8
	jle ten
	iaddq $1,%rax
ten:
	andq %r9,%r9
	jle Npos
	iaddq $1,%rax
Npos:
	
	iaddq $80, %rdi			#src+10
	iaddq $80, %rsi			#dst+10

	iaddq $-10, %rdx			#下一轮循环

	andq %rdx,%rdx		
	jge Loop			

LoopLTen:					#三三复制:
	#iaddq $10,%rdx			#恢复
	#iaddq $-3,%rdx			#判断是否有3个数(含)以上

	iaddq $7,%rdx			#两iaddq二合一

	jl remian

Loop2:
	mrmovq (%rdi),%r8
	mrmovq 8(%rdi),%r9
	mrmovq 16(%rdi),%r10

	rmmovq %r8,(%rsi)
	rmmovq %r9,8(%rsi)
	rmmovq %r10,16(%rsi)

	andq %r8,%r8
	jle NLoop2
	iaddq $1,%rax

NLoop2:
	andq %r9,%r9
	jle NLoop3
	iaddq $1,%rax
NLoop3:
	andq %r10,%r10
	jle nextLoop2
	iaddq $1,%rax
nextLoop2:
	iaddq $24,%rdi
	iaddq $24,%rsi
	iaddq $-3,%rdx
	jge Loop2

remian:
	#iaddq $3,%rdx		#恢复
	#iaddq $-2,%rdx		#判断是否有两个数

	iaddq $1,%rdx		#两iaddq二合一
	jne one
	mrmovq (%rdi), %r8	# 
	mrmovq 8(%rdi), %r9

	rmmovq %r8, (%rsi)
	rmmovq %r9, 8(%rsi)

	andq %r8,%r8
	jle rLoop2
	iaddq $1,%rax
rLoop2:
	andq %r9,%r9
	jle Done
	iaddq $1, %rax		# count++
one:
	iaddq $1,%rdx
	jne Done

	mrmovq (%rdi), %r10	# 
	iaddq $8, %rdi		# src++

	rmmovq %r10, (%rsi)	# 
	iaddq $8, %rsi		# dst++
	andq %r10, %r10		# val <= 0?
	jle Done
	iaddq $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),%r8
	andq %r8,%r8
	rmmovq %r8,64(%rsi)	

remain8:
	mrmovq 56(%rdi),%r8
	jle remain82
	iaddq $1,%rax

remain82:
	rmmovq %r8,56(%rsi)
	andq %r8,%r8
remain7:
	mrmovq 48(%rdi),%r8
	jle remain72
	iaddq $1,%rax
remain72:
	rmmovq %r8,48(%rsi)
	andq %r8,%r8
remain6:
	mrmovq 40(%rdi),%r8
	jle remain62
	iaddq $1,%rax
remain62:
	rmmovq %r8,40(%rsi)
	andq %r8,%r8
remain5:
	mrmovq 32(%rdi),%r8
	jle remain52
	iaddq $1,%rax
remain52:
	rmmovq %r8,32(%rsi)
	andq %r8,%r8
remain4:
	mrmovq 24(%rdi),%r8
	jle remain42
	iaddq $1,%rax
remain42:
	rmmovq %r8,24(%rsi)
	andq %r8,%r8
remain3:
	mrmovq 16(%rdi),%r8
	jle remain32
	iaddq $1,%rax
remain32:
	rmmovq %r8,16(%rsi)
	andq %r8,%r8
remain2:
	mrmovq 8(%rdi),%r8
	jle remain22
	iaddq $1,%rax
remain22:
	rmmovq %r8,8(%rsi)
	andq %r8,%r8
remain1:
	mrmovq (%rdi),%r8
	jle remain12
	iaddq $1,%rax
remain12:
	rmmovq %r8,(%rsi)
	andq %r8,%r8
	jle Done
	iaddq $1,%rax

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

remain:						#剩余的
	iaddq $7,%rdx			
	jl left					#len<3
	jg right				#len>3
	je remain3				#len==3

left:
	iaddq $2,%rdx			#len==1
	je remain1
	iaddq $-1,%rdx			#len==2
	je remain2
	ret 					#len==0

right:
	iaddq $-3,%rdx			#len<=6
	jg rightRight
	je remain6 				#len==6
	
	iaddq $1,%rdx
	je remain5 				#len==5
	jmp remain4 			#len==4
rightRight:
	iaddq $-2,%rdx
	jl remain7
	je 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 header

	iaddq $-10,%rdx		#判断是否有10个数(含)以上
	jl remain

Loop:	
	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,%r9
	jle three
	iaddq $1, %rax		
three:
	mrmovq 16(%rdi),%r8
	mrmovq 24(%rdi),%r9

	rmmovq %r8,16(%rsi)
	rmmovq %r9,24(%rsi)

	andq %r8,%r8
	jle four
	iaddq $1,%rax
four:
	andq %r9,%r9
	jle five
	iaddq $1,%rax
five:
	mrmovq 32(%rdi),%r8
	mrmovq 40(%rdi),%r9

	rmmovq %r8,32(%rsi)
	rmmovq %r9,40(%rsi)

	andq %r8,%r8
	jle six
	iaddq $1,%rax
six:
	andq %r9,%r9
	jle seven
	iaddq $1,%rax
seven:
	mrmovq 48(%rdi),%r8
	mrmovq 56(%rdi),%r9

	rmmovq %r8,48(%rsi)
	rmmovq %r9,56(%rsi)

	andq %r8,%r8
	jle eight
	iaddq $1,%rax
eight:
	andq %r9,%r9
	jle nine
	iaddq $1,%rax
nine:
	mrmovq 64(%rdi),%r8
	mrmovq 72(%rdi),%r9

	rmmovq %r8,64(%rsi)
	rmmovq %r9,72(%rsi)

	andq %r8,%r8
	jle ten
	iaddq $1,%rax
ten:
	andq %r9,%r9
	jle Npos
	iaddq $1,%rax
Npos:
	
	iaddq $80, %rdi			#src+10
	iaddq $80, %rsi			#dst+10

	iaddq $-10, %rdx			#下一轮循环

	jge Loop

remain:						#剩余的
	iaddq $7,%rdx			
	jl left					#len<3
	jg right				#len>3
	je remain3				#len==3

left:
	iaddq $2,%rdx			#len==1
	je remain1
	iaddq $-1,%rdx			#len==2
	je remain2
	ret 					#len==0

right:
	iaddq $-3,%rdx			#len<=6
	jg rightRight
	je remain6 				#len==6
	
	iaddq $1,%rdx
	je remain5 				#len==5
	jmp remain4 			#len==4
rightRight:
	iaddq $-2,%rdx
	jl remain7
	je remain8

remain9:
	mrmovq 64(%rdi),%r8
	andq %r8,%r8
	rmmovq %r8,64(%rsi)	

remain8:
	mrmovq 56(%rdi),%r8
	jle remain82
	iaddq $1,%rax

remain82:
	rmmovq %r8,56(%rsi)
	andq %r8,%r8
remain7:
	mrmovq 48(%rdi),%r8
	jle remain72
	iaddq $1,%rax
remain72:
	rmmovq %r8,48(%rsi)
	andq %r8,%r8
remain6:
	mrmovq 40(%rdi),%r8
	jle remain62
	iaddq $1,%rax
remain62:
	rmmovq %r8,40(%rsi)
	andq %r8,%r8
remain5:
	mrmovq 32(%rdi),%r8
	jle remain52
	iaddq $1,%rax
remain52:
	rmmovq %r8,32(%rsi)
	andq %r8,%r8
remain4:
	mrmovq 24(%rdi),%r8
	jle remain42
	iaddq $1,%rax
remain42:
	rmmovq %r8,24(%rsi)
	andq %r8,%r8
remain3:
	mrmovq 16(%rdi),%r8
	jle remain32
	iaddq $1,%rax
remain32:
	rmmovq %r8,16(%rsi)
	andq %r8,%r8
remain2:
	mrmovq 8(%rdi),%r8
	jle remain22
	iaddq $1,%rax
remain22:
	rmmovq %r8,8(%rsi)
	andq %r8,%r8
remain1:
	mrmovq (%rdi),%r8
	jle remain12
	iaddq $1,%rax
remain12:
	rmmovq %r8,(%rsi)
	andq %r8,%r8
	jle Done
	iaddq $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的原因,总体来看要最短的。可能还有其他的方法能快那么一点点。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《深入理解计算机系统》实验四Architecture Lab 的相关文章

  • Win11微软账号登录不上?Win11登录Microsoft账户出错的解决方法

    Win11微软账号登录不上 近期有部分Win11用户反映在登录微软账号会出现一直转圈 无法登录的情况 这样导致部分功能都不能正常使用了 为此十分令人头疼 那么对于这一情况 有没有什么方法可以有效的解决呢 下面小编教给大家操作方法 大家可以去
  • 小白学协程笔记2-c语言实现协程-2021-2-10

    文章目录 前言 一 c语言中协程切换方式 二 使用setjmp 和 longjmp实现协程切换 1 setjmp和longjmp函数简介 2 协程实现 三 使用switch case实现协程切换 1 switch case小技巧 2 协程实
  • windows下命令行修改系统时间;修改系统时间的软件

    找了很久 都没有找到 还找了关键词 dos下修改系统时间 因为看到linux下修改系统时间是用hwclock 命令写入主板芯片 而我由于某些原因想自动化修改系统时间 所以找windows下修改系统时间的软件 没有找到 有一个 意天禁止修改系
  • x86寄存器

    通用寄存器 GPR寄存器 AX Accumulator 累加寄存器 也叫累加器 BX Base 基地址寄存器 CX Count 计数器寄存器 DX Data 数据寄存器 指针寄存器 SP Stack Pointer 堆栈指针寄存器 BP B
  • 计算机领域中随处可见的抽象

    想要管理多种具体的东西 那么需要遵守每种东西的规范 如果想要提供一种通用模式来对这些具体的东西统一管理 需要使用一种古老的技术 抽象 抽象是将多种具体的东西 管理时需要遵守的规范 的共同点抽取出来 放入到更高一层的抽象层 在抽象层不定义或少
  • unix环境高级编程——文件IO

    本期主题 unix环境高级编程 文件IO 文件IO 0 引言 1 文件描述符 2 IO编程中常用的API接口 1 open函数 2 close函数 3 read函数 4 write函数 5 lseek函数 3 函数sync fsync和fd
  • 操作系统学习(九)进程通信

    一 知识总览 二 定义 进程通信是指进程之间的信息交换 每个进程都拥有自己的内存空间 是相互独立的 这样在每个进程执行时 才不会被其他进程所干扰 三 进程通信的方式 1 共享存储 1 两个进程对共享区的访问必须是互斥的 即在同一时间内 只允
  • Linux使用nvida-smi查看GPU类型

    nvida smi提供一个查看GPU信息的方法 然而这种方式不能查看GPU型号 型号被省略成了GeForce RTX 208 如果我们需要查看GPU的型号 只需要运行nvidia smi L即可 mrfive ubuntu nvidia s
  • 红帽7.9部署telnet服务

    升级ssh 为预防万一提前配置telnet服务 安装软件包 yum install telnet server yum install xinetd xinetd加入开机自启 systemctl enable xinetd service
  • 自己动手写操作系统(一)

    本系列文章将一步步实现一个简单的操作系统 实验环境是在Linux系统下通过Bochs虚拟机运行我们自己写的操作系统 一 实验环境搭建 1 Ubuntu的安装 Windows用户可以选择在虚拟机中安装Ubuntu 具体安装教程可自行搜索 2
  • Linux 内核中的 Device Mapper 机制

    Linux 内核中的 Device Mapper 机制 尹 洋 在读博士生 尹洋 中科院计算所国家高性能计算机工程技术研究中心的在读博士生 主要从事服务部署和存储资源管理以及Linux块设备一级的开发和研究工作 简介 本文结合具体代码对 L
  • Ubuntu9.04太多乱码(中文不能正常显示)

    最近在使用Ubuntu9 04的过程中 发现有好多地方都出现乱码 其实是中文不能正常显示 现在把我所遇到的所有乱码问题集中一下 方便以后查阅参考 一 Flash乱码 在终端输入 sudo gedit etc fonts conf d 49
  • 由于回车符引起的shell错误

    今天弟弟写shell时出现一个错误 源代码如下 zip r 1 2 执行时出现错误 我也写了相同的语句 发现是可以执行的 把两个文件对比一看 差别在于 出错shell 正确shell 在linux下的回车是 n 在win下面的回车是 r n
  • linux 使用systemctl 启动服务报错: Error: No space left on device

    By default Linux only allocates 8192 watches for inotify which is ridiculously low And when it runs out the error is als
  • 使用ShellJS提升你的开发效率(一)

    Shelljs Unix shell commands for Node js Shelljs是Node js下的脚本语言解析器 具有丰富且强大的底层操作 Windows Linux OS X 权限 Shelljs本质就是基于node的一层
  • [原创]C++98升级到C++20的复习旅途-从汇编及逆向角度去分析“constexpr“关键字

    简介 常用网名 猪头三 出生日期 1981 XX XX QQ 643439947 个人网站 80x86汇编小站 https www x86asm org 编程生涯 2001年 至今 共22年 职业生涯 20年 开发语言 C C 80x86A
  • Linux(13):例行性工作排程

    例行性工程 听谓的排程是将工作安排执行的流程之意 Linux 排程就是透过 crontab 与 at 这两个东西 两种工作排程的方式 一种是例行性的 就是每隔一定的周期要来办的事项 一种是突发性的 就是这次做完以后就没有的那一种 at at
  • Linux(12):磁盘配额(Quota)与进阶文件系统管理

    磁盘配额 Quota 的应用与实作 Quota 的一般用途 针对 www server 例如 每个人的网页空间的容量限制 针对 mail server 例如 每个人的邮件空间限制 针对 file server 例如 每个人最大的可用网络硬盘
  • DOSBOX 快捷键及 MS-DOS 命令

    1 全屏 退出全屏 alt enter 2 释放鼠标 ctrl F10 3 exit 退出DOSBOX 4 dir 显示目录内容 可选参数 w 只显示文件名 P 显示部分内容 exe 筛选出可执行文件 5 cd 进入目录 cd 退回上一级目
  • 【go语言】AST抽象语法树详解&实践之扫描代码生成错误码文档

    背景 为了能识别出代码中抛出错误码的地址和具体的错误码值 再根据错误码文件获取到错误码的具体值和注释 方便后续的排错 这里使用AST进行语法分析获取到代码中的目标对象 一 编译过程 在开始解析代码之前先补充了解一下编译过程 编译过程是将高级

随机推荐

  • MySQL常用基础 - 小白必看(二)

    MySQL数据库基本操作 一 DDL 概念 是一个数据定义语言 该语言部分包括 1 对数据库的常用操作 创建数据库 1 create database 数据库名 直接删除 2 create database if not exists 数据
  • 《effective java》中关于解决构造函数/方法签名包含大量参数的解决方法

    针对构造方法 重叠构造器模式 重叠构造器模式是一种编程中的反模式 指的是一个类有多个构造函数 每个构造函数都有不同数量的参数 从而可以根据不同的情况创建对象 这种方式会导致代码可读性和可维护性降低 因为构造函数过多 参数顺序容易混淆 Jav
  • 使用 Composer 安装 JWT 失败错误 The "https://packagist.org/packages.json" file could not be downloaded 解决方案

    错误信息 The https packagist laravel china org packages json file could not be downloaded SSL operation failed with code 1 O
  • Redis3.0集群方案分析

    在Redis3 0集群出来之前 大家都对作者antirez寄予厚望 因为Redis从来没有让我们失望过 现在Redis3 0集群出来了 网上出了很多评论文章 都说他的功能多么强大 包括下面这张图是彻底把我欺骗了 等到我把Redis3 0客户
  • Qmake VS Cmake 对比讲解

    用 cmake 构建Qt工程 对比qmake进行学习 cmake vs qmake qmake 是为 Qt 量身打造的 使用起来非常方便 cmake 使用上不如qmake简单直接 但复杂换来的是强大的功能 内置的 out of source
  • 一点浩然气,千里快哉风

    到英国访学一年 也认识了一些其他来自国内的访问学者 平时周末也经常一起徒步聚餐 从今年1月份以来 基本每个月有一个小伙伴回国 随着身边的小伙伴越来越少 以及自己也要不久回国了 心里不免有些人走茶凉 曲终人散的落寞 总体上 来英国的访问学者很
  • 【模板】快速排序

    题目链接 洛谷 P1177 模板 快速排序 1960年由查尔斯 安东尼 理查德 霍尔 Charles Antony Richard Hoare 缩写为C A R Hoare 提出 如下图所示 快速排序的执行流程为 从序列中选择一个轴点元素
  • C/C++ getcwd 获取项目的运行路径

    在Linux下做QT项目时 需要获取项目的运行路径 于是用getcwd函数进行获取 然后在Windows下进行测试 发现获取到的是程序的项目路径 即代码文件路径 然后再Linux QT中测试 获取到的又是运行路径 这就很纳闷了 经过再三测试
  • 2-1、Lua数据结构

    2 1 Lua数据结构 文章目录 2 1 Lua数据结构 1 数组 2 矩阵和多维数组 3 链表 4 队列和双向队列 5 集合和包 6 字符串缓冲 table是Lua中唯一的数据结构 其他语言所提供的数据结构 如 arrays record
  • python crop函数-图片裁剪函数

    crop 函数的参数形式是 x1 y1 x2 y2 这个元组是作为一个参数的 参考代码 from PIL import Image im Image open d 22 jpg im1 im crop im size 0 4 im size
  • linux中进入目录命令是什么,linux进入目录的命令是什么

    linux进入目录的命令是 cd 该命令的作用是切换至指定目录下 语法格式为 cd dirName 参数 dirName 表示要切换的目标目录 可以是绝对路径或相对路径 若目录名称省略 则变换至使用者的home目录 本教程操作环境 Red
  • bp神经网络时间序列预测,bp神经网络有几个阶段

    什么是BP神经网络 BP算法的基本思想是 学习过程由信号正向传播与误差的反向回传两个部分组成 正向传播时 输入样本从输入层传入 经各隐层依次逐层处理 传向输出层 若输出层输出与期望不符 则将误差作为调整信号逐层反向回传 对神经元之间的连接权
  • SwiftUI接入穿山甲开屏广告

    研究了一下SwiftUI怎么接入穿山甲 基于穿山甲sdk版本 4 7 0 8 例子地址 1 首先要先注册一个账号 穿山甲地址 在广告变现 gt 流量 gt 应用中创建一个应用并记录下应用ID 在广告变现 gt 流量 gt 代码位创建一个代码
  • vue-excel导出-单表头,多表头导出,Export2Excel.js Blob.js

    效果如图 一级导出 二级导出 如下图 三级导出 Export2Excel js Blob js 等 安装依赖 npm install S file saver npm install save xlsx 0 10 0 npm install
  • 蓝牙ble tips3-MAC地址

    和计算机网络IP地址类似 BLE也会有属于自己的一个地址 BLE设备地址 蓝牙地址 也称作 Bluetooth MAC Media Access Control 地址 是一个48位的唯一硬件标识符 用于在蓝牙设备之间建立连接和通信 它由全球
  • TRMF 辅助论文:最小二乘法复现TRMF

    1 目标函数 总 论文笔记 Temporal Regularized Matrix Factorization forHigh dimensional Time Series Prediction UQI LIUWJ的博客 CSDN博客 1
  • 蓝桥杯第23天(Python)(疯狂刷题第6天)

    题型 1 思维题 杂题 数学公式 分析题意 找规律 2 BFS DFS 广搜 递归实现 深搜 deque实现 3 简单数论 模 素数 只需要判断到 int sqrt n 1 gcd lcm 快速幂 位运算移位操作 大数分解 分解为质数的乘积
  • Deque接口简介说明

    转自 Deque接口简介说明 下文笔者讲述Deque接口的简介说明 如下所示 Deque简介 Deque接口是一个双端队列 可以对队列的头尾进行操作 所以也可以当做栈来使用 Queue和Deque接口的相对应方法 Queue方法 Deque
  • 完美解决SpringMVC中org.springframework.web.servlet.DispatcherServlet.noHandlerFound No mapping 404错误

    错误原因描述 出现该错误的原因主要是无法扫描注册 Controller注解的类的实例进入IOC容器而导致的 从而从一下几个方面来分析 MVC配置文件中 component scan 标签扫描包路径是否正确 且是否误写了排除 Controll
  • 《深入理解计算机系统》实验四Architecture Lab

    前言 深入理解计算机系统 实验四Architecture Lab下载和官方文档机翻请看 深入理解计算机系统 实验四Architecture Lab下载和官方文档机翻 我觉得这个文档对整个实验很有帮助 如果你的Y86 64环境还没安装好可以看