基地址寄存器
出自 MBA智库百科(https://wiki.mbalib.com/)
基地址寄存器(Base Address Register,BAR)
目录 |
什么是基地址寄存器[1]
基地址寄存器指基数位移定址系统中存放基地址的寄存器。每条捐令的地址部都记有和基地址对应的相对地址,因此执行时要将基地址和相对地址相加才能得到实际地址。
基地址寄存器的加载[2]
设当前正在执行过程的静态层号是i,则当前过程调用记录前部的区头地址表共i+1个单元。当需要访问本过程中说明的简单变量或形式参数时,只要求SP+该变量的位移地址,即得该变量所分配的存储单元地址。而若要访问在嵌套深度为k(k<i)的过程中说明的变量或形式参数时,其存储单元地址为(SP+k)+该变量的位移地址。这样看来,对程序中变量的存取问题似乎已经解决。但是,由于具体机器指令格式上限制,还需要根据具体机器指令格式,进一步讨论这一问题。
机器指令格式是一个和硬件有关的问题。以前面假想的计算机为例,和内存有关的机器指令的汇编指令格式是
OP R1,d2(R2)
其中,R2是和第二操作数有关的基地址寄存器,d2则是第二操作数的位移地址。在形成实际地址时,基地址寄存器中地址和位移地址相加
(R2) + d2
得到第二操作数地址。一般说来,机器指令中位移区的位数较少(例如12位),这种指令格式完全是为了缩短每一条指令长度而设计的。但是,它给编译程序形成有效指令带来了困难。如果指令的位移区只占12位,则该条指令只能访问相对于基地址的位移在4095个单元内的存储单元。对于相对地址超出4095的内存单元来说,该条指令是无法进行存取的。要存取相对于基地址的位移在4095个单元外的存储单元中内容,程序必须首先修改基地址寄存器中地址。由此可见,一个过程数据区从存储分配上看是一个整体,但从具体指令的编址上看,过程数据区又可以划分成彼此相连的若干块。块的大小和具体机器指令格式有关。为了访问块内某存储单元,必须首先将该块的首地址取至基地址寄存器,然后按相对于该块的首地址的位移量来访问此存储单元。
前面说过,r3是代码生成阶段的一个保留寄存器,用做特定的用途。例如,可以规定r3用做基地址寄存器。由于硬件特点,r3还被用来存放转子指令执行后的下一条指令地址。当程序流进入一个过程时,运行时刻执行的过程数据区初始化子程序将该过程数据区首地址送入基地址寄存器r3。换句话说,当过程体刚开始执行时,当前过程调用记录的第0块首地址已在r_3中。如果所访问的存储单元落在当前过程调用记录的第O块,则代码生成程序就利用r3和保存在符号表登记项的位移地址直接形成指令;否则,必须修改基地址寄存器的值,即将该存储单元所属块的首地址取至基地址寄存器。这个工作可以让一个专门子程序CHECKBP完成。
运行时刻子程序CHECKBP工作时需要两个参数:变量所属过程的嵌套深度和所属块号。变量所属过程的嵌套深度可以从符号表该标识符所属登记项中得到。变量所属块的块号也可以从保存在符号表登记项的相对地址求得,用逻辑乘截出该相对地址高位变量,就是所属块号。块号和每块长度相乘,然后再加上此过程调用记录首地址就得到块首址:
- 块首址=过程调用记录首址+块号*块长度
其中,过程调用记录首址可以根据变量所属过程的静态嵌套深度从当前过程调用记录的区头地址表中得到。
为了避免经常调用运行子程序CHECKBP,应当注意到下述程序变量访问的就近原则:程序员在编制程序时,往往将一段程序中所用到的变量集中在一起进行说明。这就使得在一段程序中所访问的量往往集中于同一块或者集中于本过程数据区的第0块。由于假想计算机的寄存器已经分配完毕,可以在运行程序工作区中设立两个工作单元SP和BP。SP中存放当前正在执行的过程的调用记录的首地址,BP则存放当前访问变量所属数据块的首地址。运行子程序CHECKBP并不将变量所属块的首地址直接送往r3,而是将此地址送往运行时刻的工作单元BP。运行时刻子程序CHECKBP的代码书写工作读者是不难完成的。
为了知道运行时刻r3、SP和BP的情况,在代码生成程序中设立三个工作变量X、Y和zoX、Y和Z三个变量各有两个域:levelno和bloekno,分别记录了运行时刻r3、SP和BP中地址所对应的过程嵌套深度和块号。进入过程时,运行时刻的过程数据区初始化子程序将当前过程调用记录的首地址送人r3、SP和BP。与此相对应的代码生成程序动作必须将此过程的嵌套深度和第0块标记0送入变量X、Y和Z中。此后,每当代码生成程序要生成访问运行栈存储单元的指令时,都必须检查所要访问的变量的所属块首址是否已在寄存器r3中。如果该地址并不在k3中,而在工作单元BP(或工作单元SP)中,则生成将BP值传送到r3的指令(或SP值传送到r_3的指令)。否则,代码生成程序生成转运行时刻子程序CHECKBP的转子指令,以便将所属块的首地址取至工作单元BP,然后再生成将BP值传送到r3的指令。上述工作可以由子程序CHECKr3来完成,读者不难写出该子程序的代码。注意,和REGVALUE工作区及REGSTATE工作区必须正确反映上一条指令生成后寄存器的值和状态的道理一样,代码生成程序的工作变量X,Y和z也必须正确反映运行时刻r3,SP和BP中地址所对应的过程嵌套深度和块号。
基地址寄存器的设定[3]
地址的表示方法是基地址寄存器B加上变址寄存器中的相对地址构成,但是基地址寄存器的设定则需在程序中完成。基地址寄存器的设定方法有两种:以下以12号寄存器为例说明:
例1:BEGINl START
XXXX USING*,12
SAVE(14,12)
LR12,15
…
因为15号寄存器是程序始址(即XXXX),将15号寄存器的内容取到12号寄存器,则基地址寄存器12将XXXX作为基地址置入。
例2:BEGIN2 START
SAVE(14,12)
USING*,12
YYYY BAlR 12
…
因为BALR指令是将下一条指令地扯存入12号寄存器中,而USING是指示汇编程序以现行值为基地址汇编,因此基地址寄存器12将YYYY作为基地址置入。但需注意,在这里不能把BALR和USING指令写颠倒了,否则出错。