您的位置:首页 > 其它

jpcsp源码解读8:cpu状态

2012-03-22 16:13 232 查看
从通用寄存器开始说起。

通用寄存器用一个类public class GprState来表示,其中的成员变量只有一个:

public final int[] gpr = new int[32];

也就是用32个整形数模拟32个32位通用寄存器。

这个类提供了操作这些寄存器的接口,例子如:

public void reset()

把32个寄存器都复位清零

public final void doSLL(int rd, int rt, int sa)

把rt号寄存器中的数据左移sa位,结果存放到rd号寄存器中

其余的还有:两个寄存器rs,rt的内容相加,结果存放到寄存器rd中 等等这样的方法,这里不一一列出,看源码就很清楚。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

注意,这里只是提供了操作寄存器的方法,而不是具体的指令。指令由另外的类来描述,他们的联系在于,每个指令的实现动作会调用特定的操作寄存器的方法。关于指令类的内容,将在下一篇日志中详解。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

现在,我们只有关于32个通用寄存器的描述,但是这还不足以描述一个完整的处理器。

在mips架构中,为乘法和除法另外定义了两个寄存器,hi和lo。两个32位数相乘,结果应该是64位。hi就是high的意思,是64位结果的高32位。lo就是low的意思,64位结果的低32位。在除法的情形,则分别用来存放商(lo)和余数(hi)。

在jpcsp中采取的手法是,将乘除法单元定义为前述通用寄存器类GprState的子类。这样,这个子类就继承了父类的所有成员变量和方法。也就是说,子类的实例可以引用父类中的所有方法,子类实例中包含了父类中定义的所有成员变量。

乘除法单元类:

public class MduState extends GprState

mdu的意思就是Multiply Divide Unit

这个子类中另外加入的成员变量只有一个(再次提醒,他已经继承了父类中的32个通用寄存器):

public long hilo;

也就是将两个32位寄存器打包在一个long型变量中。在这个类中定义了操作hilo寄存器的接口,如 乘法,除法,乘加 等。还有mfhi,mflo这样的方法。同样的,这些只是操作寄存器的方法,而不是指令。指令类的具体实例会调用这些方法。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

用同样的手法,定义MduState的子类,把访存单元包含进来:

public class LsuState extends MduState

看一下其中引入的成员变量:

public static final Memory memory = Memory.getInstance();

protected static final boolean CHECK_ALIGNMENT = true;

看到了内存类Memory,很好很强大。也就是说,cpu状态中把内存状态也包含进来了。

这个类提供的方法在这里列出两个:

public void doLB(int rt, int rs, int simm16)

public void doSH(int rt, int rs, int simm16)

(LB就是load byte,SH就是store half)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

继续定义LsuState的子类,这次加入的是分支控制单元(Branch Control Unit):

public class BcuState extends LsuState

新加入的成员变量:

public int pc;

public int npc;

也就是当前的pc(program counter)值,以及当前指令的下一条指令地址。

提供了一些关于分支动作的接口:

public boolean doJR

public boolean doBLTZ

public void nextPc

jr表示jump register;bltz表示branch on less than zero;nextPC就是没有分支,顺序推进pc值。



这些动作会更改pc值。还提供了两个方法,根据当前pc值从内存中取指令:

public int fetchOpcode()

public int nextOpcode()

现在,我们有了通用寄存器,hilo,内存,pc和npc,还有取指方法,还有更改各个寄存器的方法,处理器的状态机已经构建起来。

因为mips架构下,I/O操作和内存访问采用统一编址,所以有理由相信,I/O操作被封装进了Memory类中。也可能因为系统调用被包含进了虚拟机,导致根本不需要牵涉I/O操作的访存指令。这些都是此刻的臆想和猜测,分析Memory类的源码之后就会明晰。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

现在,将浮点单元加入进来:

public class FpuState extends BcuState

成员变量:

public static final class Fcr0

public float[] fpr;

public Fcr31 fcr31;

其中fpr和fcr31在构建函数中的初始化:

fpr = new float[32];

fcr31 = new Fcr31();

fpr是32个32位浮点寄存器。fcr31和fcr0是控制寄存器。

fcr0中我们这里只实现两个字段:

浮点单元实现编号imp = 0

浮点指令集版本号rev = 0

fcr31中实现3个字段:

rm,双精度浮点数据类型是否实现

c,浮点条件码;记录浮点比较结果,用于条件跳转或转移

fs,冲刷到0;这位设置时,非正常运算的结果将被设为0,而不是产生一个例外

这个类提供了浮点操作和控制接口,如浮点运算,读取或配置浮点控制寄存器等,具体见源码,不在此处列出。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

加入向量单元:

public class VfpuState extends FpuState

具体成员变量,寄存器,操作等内容,比较庞杂,暂且不去研究这个问题,以后再补上。现在先着力于摸清模拟器架构,所以对于已经知道的东西,就顺带附上些细节。对于庞杂的没研究过的枝叶,先放一边。

也可以参考这个网页:http://hitmen.c02.at/files/yapspd/psp_doc/chap4.html#sec4.5.1也就是其中的4.5.1章节。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

关于hitmen

http://hitmen.c02.at/files/yapspd/psp_doc/

这个网站提供了详尽的关于psp的硬件信息,作者声称其中内容全部出自猜测。应该是破解人员艰苦工作的成果,在此向他们致敬,呵呵。这个网站中的内容,如其标题所述,是psp硬件的英文文档。而我在写的东西,旨在阐明硬件和模拟器源码的对应关系,也就是说明模拟器的架构和设计方法。希望这会对一些人产生意义。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

回到正题,再继承一次VfpuState,就得到了一个完整的处理器类:

public class CpuState extends VfpuState

其中没有增加任何东西,只是一次外层包装,换个名字,在逻辑上更加清晰和一致。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

现在来看这个cpu状态类,其中包括了 通用寄存器,乘除法单元,访存单元(含内存),分支控制单元,浮点单元,向量单元;并且包含对这些单元的操作方法。

只要外面再加一层封装,初始化某一块只读的内存单元,其中装载固件,然后操作这个cpu,取指令,解析指令并调用这个cpu状态类的相应方法,虚拟机就运行起来了。

对于I/O,可以在访存单元中判定访存地址,来确定实际操作的硬件单元,然后将这些操作映射到我们虚拟的硬件设备上(比如用一个画布类虚拟出来的游戏机屏幕)。

另一种可选方案是,截获用户的所有系统调用,并且在虚拟机中完成这些系统调用请求的功能(硬件I/O,内存管理等)(而不是在虚拟机上运行的固件中完成)。

对于中断,可以作为一个事件传递给cpu实例,要求其作出适当响应。

指令的异常可以作为exception给throw出去。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: