CSAPP ArchLab

实验内容

实验提供了一个Y86-64处理器,要求我们编写汇编、添加处理器指令、优化汇编程序。

注意在make时如果出现 tk.h: No such file or directory 这样的报错,需要进Makefile根据指示注释掉几行代码。

PartA

第一部分要求我们根据提供的C程序,编写对应汇编程序。在misc目录下make得到的yas可以把汇编程序转换为相应的机器码,yis可以模拟机器码在Y86-64处理器上的执行。

/* linked list element */
typedef struct ELE {
  long val;
  struct ELE *next;
} *list_ptr;

Y86-64上的汇编指令比较少,在书上都有提供,编写下来比较简单,别忘了整个程序前后的声明即可。

/* sum_list - Sum the elements of a linked list */
long sum_list(list_ptr ls)
{
  long val = 0;
  while (ls) {
	  val += ls->val;
	  ls = ls->next;
  }
  return val;
}

# Execution begins at address 0
  .pos 0
  irmovq stack, %rsp
  call main
  halt

  .align 8

# Source block
src:
  .quad 0x00a
  .quad 0x0b0
  .quad 0xc00

# Destination block
dest:
  .quad 0x111
  .quad 0x222
  .quad 0x333

main:
  irmovq $3, %rdx
  irmovq dest, %rsi
  irmovq src, %rdi
  call copy_block
  ret

copy_block:
  irmovq $8, %r8
  irmovq $0xffffffffffffffff, %r9
  xorq %rax, %rax

loop:
  andq %rdx, %rdx
  je end
  
  mrmovq (%rdi), %r10
  rmmovq %r10, (%rsi)
  xorq %r10, %rax
  addq %r8, %rdi
  addq %r8, %rsi
  addq %r9, %rdx
  jmp loop

end:
  ret

# Stack starts here
  .pos 0x200
stack:
/* rsum_list - Recursive version of 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;
  }
}

main:
  irmovq ele1, %rdi
  call rsum_list
  ret

rsum_list:
  irmovq $8, %r8
  xorq %rax, %rax
  andq %rdi, %rdi
  je end

  mrmovq (%rdi), %r9
  addq %r8, %rdi
  mrmovq (%rdi), %rdi
  pushq %r9
  call rsum_list
  popq %r9
  addq %r9, %rax

end:
  ret
/* copy_block - Copy src to dest and return xor checksum of src */
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;
}

main:
  irmovq ele1, %rdi
  call sum_list
  ret

sum_list: 
  irmovq $8, %r8
  xorq %rax, %rax
  jmp test

loop:
  mrmovq (%rdi), %r9
  addq %r9, %rax
  addq %r8, %rdi  #指针移动到next的位置
  mrmovq (%rdi), %rdi
  jmp test
  
test:
  andq %rdi, %rdi #测试%rdi是否为0
  jne loop

  ret

运行程序后将寄存器的值与文档里的值进行对比即可。

PartB

这一部分需要修改seq里的硬件描述文件seq-full.c,添加一条iaddq指令,实现立即数和整数的加法运算。需要添加的部分有:

#有效指令
bool instr_valid = icode in 
	{ INOP, IHALT, IRRMOVQ, IIRMOVQ, IRMMOVQ, IMRMOVQ,
	       IOPQ, IJXX, ICALL, IRET, IPUSHQ, IPOPQ, IIADDQ };

#需要寄存器
bool need_regids =
	icode in { IRRMOVQ, IOPQ, IPUSHQ, IPOPQ, 
		     IIRMOVQ, IRMMOVQ, IMRMOVQ, IIADDQ };

#有立即数valC
bool need_valC =
	icode in { IIRMOVQ, IRMMOVQ, IMRMOVQ, IJXX, ICALL, IIADDQ };

#srcB是寄存器值rB
word srcB = [
	icode in { IOPQ, IRMMOVQ, IMRMOVQ, IIADDQ  } : rB;
	icode in { IPUSHQ, IPOPQ, ICALL, IRET } : RRSP;
	1 : RNONE;  # Don't need register
];

#寄存器的写入位置为rB
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
];

#ALU的计算符号位Add
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
];

#ALU的B值位valB,即为寄存器rB
word aluB = [
	icode in { IRMMOVQ, IMRMOVQ, IOPQ, ICALL, 
		      IPUSHQ, IRET, IPOPQ, IIADDQ } : valB;
	icode in { IRRMOVQ, IIRMOVQ } : 0;
	# Other instructions don't need ALU
];

#计算后需要设置条件码
bool set_cc = icode in { IOPQ, IIADDQ };

随后根据文档里的要求进行程序测试即可。

PartC

这一部分给定了一个ncopy.ys的汇编代码,运行在一个流水线处理器上。要求我们修改ncopy.ys,使其性能尽可能的好,CPE越低,分数越高。

首先需要为这个处理器添加iaddq指令,大致内容与PartB相同,后面需要用到iaddq设置条件码来进行判断。

然后就是对ncopy.ys进行修改,未修改的ncopy.ys内容如下:

    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:
	irmovq $1, %r10
	addq %r10, %rax		# count++
Npos:	
    irmovq $1, %r10
	subq %r10, %rdx		# len--
	irmovq $8, %r10
	addq %r10, %rdi		# src++
	addq %r10, %rsi		# dst++
	andq %rdx,%rdx		# len > 0?
	jg Loop			# if so, goto Loop:

我做的时候用了两种优化方法:

第一种为错开一部分指令,避免因为load/use才产生的气泡。

第二种为循环展开,由于ncopy最多只能用1000字节,所以循环展开的路数不能太大。这里我的展开方式为12路——4路——2路——1路。即先每12个元素并为一个循环,如果元素个数不满12,则每4个元素并为一个循环......

##################################################################
# You can modify this portion
  #对%rbx进行iaddq测试是否大于等于12
  rrmovq %rdx, %rbx 

L12:
  iaddq $-12, %rbx
  jl Start4

#12路展开,错开部分指令避免Load/Use
l12_1:
  mrmovq (%rdi), %r8
  mrmovq $0x8(%rdi), %r9
  rmmovq %r8, (%rsi)
  andq %r8, %r8
  jle l12_2
  iaddq $0x1, %rax

l12_2:
  mrmovq $0x10(%rdi), %r10
  rmmovq %r9, $0x8(%rsi)
  andq %r9, %r9
  jle l12_3
  iaddq $0x1, %rax

l12_3:
  mrmovq $0x18(%rdi), %r8
  andq %r10, %r10
  rmmovq %r10, $0x10(%rsi)
  jle l12_4
  iaddq $0x1, %rax

l12_4:
  mrmovq $0x20(%rdi), %r9
  andq %r8, %r8
  rmmovq %r8, $0x18(%rsi)
  jle l12_5
  iaddq $0x1, %rax

l12_5:
  mrmovq $0x28(%rdi), %r10
  andq %r9, %r9
  rmmovq %r9, $0x20(%rsi)
  jle l12_6
  iaddq $0x1, %rax

l12_6:
  mrmovq $0x30(%rdi), %r8
  andq %r10, %r10
  rmmovq %r10, $0x28(%rsi)
  jle l12_7
  iaddq $0x1, %rax

l12_7:
  mrmovq $0x38(%rdi), %r9
  andq %r8, %r8
  rmmovq %r8, $0x30(%rsi)
  jle l12_8
  iaddq $0x1, %rax

l12_8:
  mrmovq $0x40(%rdi), %r10
  andq %r9, %r9
  rmmovq %r9, $0x38(%rsi)
  jle l12_9
  iaddq $0x1, %rax

l12_9:
  mrmovq $0x48(%rdi), %r8
  andq %r10, %r10
  rmmovq %r10, $0x40(%rsi)
  jle l12_10
  iaddq $0x1, %rax

l12_10:
  mrmovq $0x50(%rdi), %r9
  andq %r8, %r8
  rmmovq %r8, $0x48(%rsi)
  jle l12_11
  iaddq $0x1, %rax

l12_11:
  mrmovq $0x58(%rdi), %r10
  andq %r9, %r9
  rmmovq %r9, $0x50(%rsi)
  jle l12_12
  iaddq $0x1, %rax

l12_12:
  andq %r10, %r10
  rmmovq %r10, $0x58(%rsi)
  jle l12_13
  iaddq $0x1, %rax

l12_13:
  iaddq $-12, %rdx
  iaddq $0x60, %rdi
  iaddq $0x60, %rsi
  jmp L12


Start4:
  rrmovq %rdx, %rbx

L4:
  iaddq $-4, %rbx
  jl Start2

l4_1:
  mrmovq (%rdi), %r8
  mrmovq $0x8(%rdi), %r9
  andq %r8, %r8
  rmmovq %r8, (%rsi)
  jle l4_2
  iaddq $0x1, %rax

l4_2:
  mrmovq $0x10(%rdi), %r10
  andq %r9, %r9
  rmmovq %r9, $0x8(%rsi)
  jle l4_3
  iaddq $0x1, %rax

l4_3:
  mrmovq $0x18(%rdi), %r8
  andq %r10, %r10
  rmmovq %r10, $0x10(%rsi)
  jle l4_4
  iaddq $0x1, %rax

l4_4:
  andq %r8, %r8
  rmmovq %r8, $0x18(%rsi)
  jle l4_5
  iaddq $0x1, %rax

l4_5:
  iaddq $-4, %rdx
  iaddq $0x20, %rdi
  iaddq $0x20, %rsi
  jmp L4

Start2:
  rrmovq %rdx, %rbx

L2:
  iaddq $-2, %rbx
  jl Start1

l2_1:
  mrmovq (%rdi), %r8
  mrmovq $0x8(%rdi), %r9
  andq %r8, %r8
  rmmovq %r8, (%rsi)
  jle l2_2
  iaddq $0x1, %rax

l2_2:
  andq %r9, %r9
  rmmovq %r9, $0x8(%rsi)
  jle l2_3
  iaddq $0x1, %rax

l2_3:
  iaddq $-2, %rdx
  iaddq $0x10, %rdi
  iaddq $0x10, %rsi
  jmp L2

#从2路转到1路说明最多只剩一个元素待copy了
Start1:
  mrmovq (%rdi), %r8
  andq %rdx, %rdx
  jle Done
  rmmovq %r8, (%rsi)
  andq %r8, %r8
  jle Done
  iaddq $0x1, %rax


##################################################################

上面有些指令旁路即可解决相关,但是还是被我错开了(在写完了才发现,不想改回来了),不过不影响性能。

./correctness.pl测试正确性: 

./benchmark.pl测试性能:

后面琢磨了一下,想要优化得更好,可能还需要改变一下循环展开的路数和层级。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值