• CS:APP2e Y86处理器模拟器∗指南


    CS:APP2e Y86处理器模拟器∗指南

    Randal E.Bryant

    David R. O’Hallaron

    2013年7月29日

      本文档描述了处理器模拟器,伴随的表示在第4章Y86处理器架构的计算机系统:一个程序员的角度来看,第二版。这些模拟器模型的三种不同的处理器设计:SEQ,SEQ +和PIPE。

    1. 安装

      模拟器的代码通常是分布于一个名叫sim.tar的文件之中,tar格式文件。你可以从CS:APP2e Web site (csapp.cs.cmu.edu)这个网站获取一份拷贝的文件。在tar文件的目录中安装代码,执行以下步骤:

    unix> tar xf sim.tar
    unix> cd 
    sim unix> make clean 
    unix> make
    

      默认情况下,这个生成GUI(图形用户界面graphic user interface)版本的模拟器要求你有在系统中安装Tcl/Tk。若你没安装,那么你可以选择安装TTY-only版本,TTY-only的标准输出是ASCII文本。参见README文件如何生成GUI和TTY版本。

      Sim目录包含以下子目录:

      Misc:源代码文件中的实用工具,例如:YAS(Y86j集合),YIS(Y86指令集模拟器)和HCL2C(HCL翻译到C)。它还包括isa,c源文件所使用的所有处理器模拟器。

      Seq:SEQ和SEQ+模拟器的源代码。4.49和4.50包含HCL文件作业问题。参见README对不同版本的模拟器编译的说明。

      Pipe:pipe模拟器的源代码。4.52-4.57包括HCL文件问题。参见README对不同版本的模拟器编译的说明。

      Y86-code:Y86汇编代码的那一张中所示的实例程序。你可以在这些基础程序上测试你修改的模拟器。参见README文件对如何运行这些测试进行说明。作为一个运行的实例,我们将使用在这个子目录中的asum.ys。这个程序在CS:APP2e的图4.8中说明。编译后的版本如图一所示。

      Ptest:生成在不同的指令,不同的可能性和不同的风险下系统回归测试的脚本。这些脚本能够很好的帮助你在你的工程中发现bug。

    1 | # Execution begins at address 0 
    2 0x000: | .pos 0 
    3 0x000: 30f400010000 | init: irmovl Stack, %esp # Set up stack pointer 
    4 0x006: 30f500010000 | irmovl Stack, %ebp # Set up base pointer 
    5 0x00c: 8024000000 | call Main # Execute main program 
    6 0x011: 00 | halt # Terminate program 
    7 | 
    8 | # Array of 4 elements 
    9 0x014: | .align 4 
    10 0x014: 0d000000 | array: .long 0xd 
    11 0x018: c0000000 | .long 0xc0 
    12 0x01c: 000b0000 | .long 0xb00 
    13 0x020: 00a00000 | .long 0xa000 
    14 | 
    15 0x024: a05f | Main: pushl %ebp 
    16 0x026: 2045 | rrmovl %esp,%ebp 
    17 0x028: 30f004000000 | irmovl $4,%eax 
    18 0x02e: a00f | pushl %eax # Push 4 
    19 0x030: 30f214000000 | irmovl array,%edx 
    20 0x036: a02f | pushl %edx # Push array 
    21 0x038: 8042000000 | call Sum # Sum(array, 4) 
    22 0x03d: 2054 | rrmovl %ebp,%esp 
    23 0x03f: b05f | popl %ebp 
    24 0x041: 90 | ret 
    25 | 
    26 | # int Sum(int *Start, int Count) 
    27 0x042: a05f | Sum: pushl %ebp 
    28 0x044: 2045 | rrmovl %esp,%ebp 
    29 0x046: 501508000000 | mrmovl 8(%ebp),%ecx # ecx = Start 
    30 0x04c: 50250c000000 | mrmovl 12(%ebp),%edx # edx = Count 
    31 0x052: 6300 | xorl %eax,%eax # sum = 0 
    32 0x054: 6222 | andl %edx,%edx # Set condition codes 
    33 0x056: 7378000000 | je End 
    34 0x05b: 506100000000 | Loop: mrmovl (%ecx),%esi # get *Start 
    35 0x061: 6060 | addl %esi,%eax # add to sum 
    36 0x063: 30f304000000 | irmovl $4,%ebx # 
    37 0x069: 6031 | addl %ebx,%ecx # Start++ 
    38 0x06b: 30f3ffffffff | irmovl $-1,%ebx # 
    39 0x071: 6032 | addl %ebx,%edx # Count-
    40 0x073: 745b000000 | jne Loop # Stop when 0 
    41 0x078: 2054 | End: rrmovl %ebp,%esp 
    42 0x07a: b05f | popl %ebp 
    43 0x07c: 90 | ret 
    44 | 
    45 | # The stack starts here and grows to lower addresses 
    46 0x100: | .pos 0x100 
    47 0x100: | Stack:
    

    图1:代码实例。这段代码在y86-code子目录中的asum.yo文件中。

      2、 实用程序

      安装完成后,misc目录中包含两种有用的代码。

      YAS:Y86汇编程序。这需要一个有.ys扩展名的Y86文件,用.yo文件生成一个.ys文件。生成的文件包括一个ASCII版本的代码,像图一所示(相同的程序所示在CS:APP2e的图4.8中)最简单的方法来调用一个汇编程序,可以以使用或者建立一个汇编到y-86 code这个子目录文件中。例如,想要汇编这个目录中的asum.ys文件,我们可以使用这样的命令:

    unix> make asum.yo
    

      YIS:Y86指令模拟器。这个程序在Y86机器级执行指令根据指令集定义。例如,假设你想运行在y86代码目录下的程序asum.yo。简单的运行:

    unix> ../misc/yis asum.yo
    

      YIS模拟执行程序然后打印所有改变的寄存器或者是主存在终端上。就像CS:APP2e 4.1节所述。

      3、处理器模拟器

      对于SEQ,SEQ+和PIPE三个处理器,我们分别提供了SSIM,SSIM+和PSIM。每一个模拟器可以在TTY和GUI模式下运行。

      TTY模式 使用一个简单的,面对终端的接口。打印所有在终端输出上。虽然调试不是很方便,但可以安装在任何系统,可用于自动化测试。默认对所有模拟器。

      GUI模式 有一个图形界面,不久将被描述,对于观察处理机活动和调试修改版本很有用。然而,它需要在你的系统上安装Tcl/Tk。使用-g调用命令行选项。

      3.1 命令行选项

      你可以从命令行使用下列选项:

    -h 打印所有命令行选项的摘要
    -g 在GUI模式下运行模拟器(默认TTY模式)
    -t 运行处理器和ISA模拟器,比较内存的结果的值,寄存器文件和条件代码。如果没有发现差异,就打印“ISA检查成功”。否则,打印关于寄存器文件或者内存不同的信息。这个功能对于测试处理器设计非常有用。
    -l m设置指令限制,在停止之前最多执行m条指令(默认10000指令)
    -v n信息显示级别设置为n,这个值默认是2,在0-2之间。
    

      模拟器中在GUI模式上运行必须调用一个文件对象的名称在命令行上。在TTY模式下文件的名称是可选的,默认情况下来自stdin。

      下面是一些调用模拟器的典型(从y86-code子目录):

    unix> ../seq/ssim -h 
    unix> ../seq/ssim -t < asum.yo 
    unix> ../pipe/psim -t -g asum.yo
    

      第一种情况打印了SSIM在命令行选项的摘要。第二种选项在TTY下运行SEQ模拟器,从stdin中读取目标文件asum.yo。第三种情况在GUI模式下运行PIPE模拟器,执行指令对象文件asum.yo。在第二中和第三种情况之中,将结果与更高级ISA模拟器的结果相对比。

      3.2 SEQ和SEQ+模拟器

      SEQ处理器的GUI版本在命令行中被对象文件名调用:

    unix> ../seq/ssim -g asum.yo &
    

      在最后有“&”的命令允许模拟器在后台模式运行。启动模拟器程序并创建三个窗口,如图2-4.

    第一个窗口(图二)是主要的控制面板。如果HCL被HCL2C用-n 选项编译了,主控制面板的标题将显示“Y86处理器:名称”。否则只显示“Y86处理器”

      主控制窗口包含处理器控制按钮以及处理器的信息处理状态。窗口不同的部分在途中有所标记:

      控制:位于顶部的按钮控制模拟器。点击退出按钮退出模拟器。单机Go按钮可以使模拟器开始运行。单机停止按钮使模拟器暂时停止。单机步骤按钮可以使模拟器执行一条指令然后停止。单机重置按钮使模拟器回到初始状态,程序计数器的地址0,寄存器设置变为0,内存除了程序清零,设定条件规范ZF=1,CF=0,OF=0。程序状态设定为AOK。

    图二:SEQ模拟器主控制面板

    图三:SEQ模拟器代码显示窗口

    图四:SEQ模拟器内存显示窗口

      当模拟器运行时,按钮下面的滑块可以控制模拟器的速度。向右移动可以使模拟器运行速度更快。

      阶段信号:这一部分显示不同处理器信号在当前的指令求值期间的值。这些信号几乎是相同的,如CSAPP2e中的图4.23所示。主要的区别在于模拟器显示在Instr中指令的名称,而不是icode和ifun的数值。同样所有寄存器标识符显示他们的名字,而不是他们的数值,用”----”表示不需要注册访问。

      寄存器文件:这部分显示了8个程序寄存器的值。已经更新的了最新的寄存器会浅蓝色显示。寄存器的内容不会显示,指导第一次设置为非零的值。 注意当一条指令写入程序寄存器时,指到下一个时钟周期的开始,寄存器文件不会更新。这意味着你必须一步一步的看到寄存器更新。

      状态:显示当前正在执行指令的状态。这些值可能是:

    AOK:没有问题
    ADR:寻址错误,试图读取一个指令或者试图去读写一个数据。地址不能超过0X0fff。
    INS:遇到非法指令。
    HLT:遇到停止指令。

      状态代码:显示三个状态标志:ZF,SF和OF。

      注意:当一个指令改编状态代码,直到下一个时钟周期开始,状态代码寄存器不更新。这意味着你要一步一步看到更新。

      处理器asum第38行第二线程执行状态如图2所示。程序yo如图一所示,我们可以看见程序计数器在0X06b,它处理指令将%ebx,%ecx相加,寄存器%eax存储0xcd,前两个数组的和。%edx保存3,计数递减。寄存器%ecx保存0x1c,第三个数组的地址。寄存器%ebx存储4(从第36行)但有一个0xFFFFFFFF写入这个寄存器(由于dstE存放在%ebx中,数值是0xFFFFFFFF)。写入将在下个始终周期开始。

      窗口(图三所示)描述了目标代码已经被模拟器执行了。编辑框标识被执行的程序的文件名。你可以编辑文件名在这个窗口,点击登陆按钮登陆新的程序。左边显示已经被执行的对象代码,右边显示了汇编代码的文本文件。中心有一个星号表示指令目前正在被模拟。这相对应于图一所示asum.yo的第38行。

      图四所示关于内存的内容。它只显示当程序开始执行时最大值和最小值地址的位置。每一行显示内存的数据。因此每一行显示内存16字节的内存,这些字节地址只有最低有效位16字节。左边的内容是根地址,最低有效位的位置显示”-”。每一列之后对应最低地址位数0x0,0x4,0x8,0xc。图四所示的例子中有箭头表明存储器地址0x00e8,0x00e4,0x00e8,0x00ec。

      图中描述了关于求和程序在运行时,asum.yo程序在存储器中堆栈的内容。我们可以看到到目前为止堆栈的运行情况,我们能够看到%esp和%ebp被初始化为0x100(3行和4行所示)。在第五行推出调用返回指针0x011,被写入地址0x00fc。程序通过推出%ebp开始,将0x100写入0x00f8。然后退出%eax的值(18行),将0x4写入0x00f4和%edx(20行)。将0x14(数组)写入0x00f0。在第21行调用Sum导致返回指针0x3d被写入地址0x00ec。在运行sum时,存储器先推出%ebp的值导致0xf8被写入地址0x00e8。这归因于将数值在存储器和堆栈指针被设定为0xe8.

      图5显示了在执行相同代码文件和有相同点的程序的SEQ+模拟器的控制面板窗口。我们可以看出唯一不同的就是排序不同的流程和不同的信号列表。这些信号在CSAPP2e图4.40中有对应。SEQ+模拟器还声称代码和存储器窗口。在SEQ模拟器中他们的格式相同。

      3.3 PIPE模拟器

      PIPE模拟器也生成三种窗口。图6显示了控制面板。它的控制有相同的设定,寄存器文件和条件代码有相同的显示。中间的部分显示了寄存器的状态。不同的字段在CSAPP2e的图4.52中有相应的对应。在面板的底部显示数据的周期模拟(不包括最初的周期),完成数据的指令,结果CPI。

      见图7的观察图,每个pipeline寄存器显示了两个部分。上面白色框中的数值显示了最近pipeline寄存器中的数值。较低的灰色背景中的数值显示了pipeline中的输出。除非寄存器。。。。。。,这些在下一个时钟周期被寄存器载入。

      通过PIPE模拟器的流量和在SEQ和SEQ+模拟器中的不一样。在SEQ和SEQ+中,控制面板显示执行单一命令的数值结果。每一步执行模拟器处理一条指令。在PIPE中,控制面板显示多种通过pipeline的命令流。每一步执行模拟器执行这一阶段每一条命令的数值计算。

      图八显示了PIPE模拟器的代码显示。格式类似于SEQ和SEQ+,除了执行命令时单一的标记指示,用字符F、D、E、M和W来显示pipeline每一阶段的取回、解码、执行、内存、重写阶段。

    5:SEQ+模拟器的主控制界面

     

    6:PIPE模拟器的主控制界面

      

    7:PIPE模拟器主控板查看单一PIPE寄存器

     

    8:PIPE模拟器代码显示窗口

     

      PIPE模拟器同样生成一个窗口来显示存储目录,SEQ模拟器有相同的格式。(图4)

      图6和图8的例子显示了当执行图1,34-40行的循环时显示pipeline的状态。我们可以看见模拟器开始第二轮迭代,每个阶段的状态如下:

    重写:loop-closing指令(40行)完成。
    存储:mrmov指令(24行)从地址0x018读出。我们可以看见在pipeline寄存器M中valE的地址,和pipeline寄存器W中作为valM的输入,从存储器中读取的数值。
    执行:这一阶段包含一个气泡。这个气泡的产生是由于mrmovl命令(34行)和addl命令(35行)之间的以来关系。这个泡沫就像是nop指令。它解释了为什么没有指令在图8中标记”E”。
    解码:addl指令(第35行)刚刚从寄存器%eax读取0x00D。也从寄存器%esi读到数据0x00D。但是我们可以看到转发逻辑并没有使用刚刚从内存(在pipeline寄存器W中视为对valM的输入)中读取到的数据0x0C0作为valA的新值(在pipeline寄存器E中视为对valA的输入)
    读取:irmovl指令(38行)刚从地址0x063获取到,电脑的新值预计是0x069。
    

      每个阶段用他们的状态字段统计联系起来。这一字段显示了指令在pipeline中那一阶段的状态。AOK状态意味着没有遇到任何异常。状态BUB表明了在次阶段中有一个泡沫 ,并不是一个标准的指令。另一种一些可能的状态是:ADR:当一个无效的内存地址被引用时;INS:遇到一个不合法的指令代码;PIP:当在pipeline中遇到问题时(这常常发生在停止和某些被设置为1的pipeline寄存器出现泡沫信号);HTL:与带了一个停止命令。当遇到上述的四种情况,模拟器会停止。

      一些建议:

      以下是一些其它的技巧,我们从学习使用这些模拟器的经验。

      熟悉这些模拟器的操作。尝试去运行一些在y86-code目录中的示例代码。确保你理解每条指令是如何处理一些小的例子。看一些有趣的情况,例如:如在驱动的装置,程序的返回值。

      你需要寻找信息。看到数据转发的影响时尤其棘手。有七个可能的源信号valA流水线寄存器E,和六个可能的源信号valB。选择哪一个,你需要比较这些流水线寄存器输入字段值的可能来源。可能的来源有:

    R[d srcA] 源寄存器被输入在流水线寄存器srcA E中。寄存器内容显示在底部。
    R(d srcB) 源寄存器被输入在流水线寄存器srcB E中。寄存器内容显示在底部。
    D valP  这个值是流水线寄存器状态的一部分。
    e valE  这个值是valE的输入字段在流水线寄存器M中。
    M valE 这个值是M流水线寄存器的状态的一部分。
    m valM 这个值是valE的输入字段在流水线寄存器W中。
    W valE  这个值是W流水线寄存器的状态的一部分。
    W valM 这个值是M流水线寄存器的状态的一部分。
    

      你不要写重复的代码。由于数据和代码共享相同的地址空间,很容易有一个项目覆盖一些代码,在它试图再次执行指令时导致完全混乱,。重要的是设置距代码足够远的堆栈来避免这种情况。

      避免大的地址值。模拟器不允许任何大于 0x0FFF的地址。此外,如果你修改内存位置时地址较大内存显示会慢。

      注意一些GUI模式模拟器的“特性”(SSIM SSIM +,PSIM)

    • 你必须从他们的主目录执行程序。换句话说,去运行SSIM或SSIM+,你一定要处于seq目录中,然而你运行PSIM子目录必须在管道中。这个需求出现是由于Tcl解释器定位模拟器配置文件的方式。
    • 如果你是在Unix机器上运行GUI模式,记得要初始化显示环境变量:

      unix> setenv DISPLAY myhost.edu:0
      
    • 在一些Unix X窗口管理器中,把“程序代码”窗口开始运行作为一个封闭的图标。如果您没有看到这个窗口当模拟器启动时,你需要手动点击来扩大它。

    • 一些微软的windows X服务器,当存储内容更改时存储内容的窗口不会自动调整自己的大小,在这种情况下,你需要自己去手动调整来查看内存的值
    • 如果你要求他们执行一个不是有限的Y86文件,模拟器将因错误而终止。
  • 相关阅读:
    QtCreator 常用快捷键
    Qt 键值对照表
    数据管理类设计与实现
    linux free 命令下free/available区别
    Google “战败”后,C++20 用微软的提案进入协程时代!
    怎么看源代码?
    一文教你如何高效使用C语言
    用 gdb 学 C 语言
    Java中 BigDecimal,80%的人都用错了....
    C++11 实现的 100行 线程池
  • 原文地址:https://www.cnblogs.com/20145336yang/p/6211760.html
Copyright © 2020-2023  润新知