不安全的指针操作

时间:2013-03-03 07:34:36

标签: c# .net pointers unsafe fixed-point

我正在尝试用C#编写CPU模拟器。机器的对象如下所示:

class Machine 
{
    short a,b,c,d; //these are registers.

    short[] ram=new short[0x10000];  //RAM organised as 65536 16-bit words

    public void tick() { ... } //one instruction is processed
}

当我执行一条指令时,我有一个switch语句,它决定指令的结果将被存储在哪一个(寄存器或RAM字)

我希望能够做到这一点:

short* resultContainer;

if (destination == register)
{
    switch (resultSymbol) //this is really an opcode, made a char for clarity
    {
       case 'a': resultContainer=&a;
       case 'b': resultContainer=&b;
       //etc
    }
}
else
{
    //must be a place in RAM
    resultContainer = &RAM[location];
}

然后,当我执行指令时,我可以简单地存储结果,如:

*resultContainer = result;

我一直试图弄清楚如何在不惹恼C#的情况下做到这一点。

如何使用unsafe{}fixed(){ }以及其他我不知道的事情来实现这一目标?

3 个答案:

答案 0 :(得分:1)

如果我们从另一个视角看问题怎么办?执行指令并将结果存储在变量(result)中,然后决定应该将结果放在何处。不行吗?

答案 1 :(得分:1)

这是我实现它的方式:

class Machine
{
    short a, b, c, d;
    short[] ram = new short[0x10000];

    enum AddressType
    {
        Register,
        DirectMemory,
    }

    // Gives the address for an operand or for the result.
    // `addressType`and `addrCode` are extracted from instruction opcode
    // `regPointers` and `ramPointer` are fixed pointers to registers and RAM.
    private unsafe short* GetAddress(AddressType addressType, short addrCode, short*[] regPointers, short* ramPointer)
    {
        switch (addressType)
        {
            case AddressType.Register:
                return regPointers[addrCode]; //just an example implementation
            case AddressType.DirectMemory:
                return ramPointer + addrCode; //just an example implementation
            default:
                return null;
        }
    }

    public unsafe void tick()
    {
        fixed (short* ap = &a, bp = &b, cp = &c, dp = &d, ramPointer = ram)
        {
            short*[] regPointers = new short*[] { ap, bp, cp, dp };

            short* pOperand1, pOperand2, pResult;
            AddressType operand1AddrType, operand2AddrType, resultAddrType;
            short operand1AddrCode, operand2AddrCode, resultAddrCode;

            // ... decipher the instruction and extract the address types and codes

            pOperand1 = GetAddress(operand1AddrType, operand1AddrCode, regPointers, ramPointer);
            pOperand2 = GetAddress(operand2AddrType, operand2AddrCode, regPointers, ramPointer);
            pResult = GetAddress(resultAddrType, resultAddrCode, regPointers, ramPointer);

            // execute the instruction, using `*pOperand1` and `*pOperand2`, storing the result in `*pResult`.

        }
    }
}

要获取寄存器和RAM阵列的地址,必须使用fixed语句。此外,您只能使用fixed块中获取的指针。所以你必须传递指针。

答案 2 :(得分:0)

一个很好的选择,我曾计划用于DevKit但尚未实现,是生成您的仿真代码。这是一个历史悠久,久经考验的解决方案。对于每个操作码/寄存器组合或某个有效子集,分别为ADD A,B和SUB X,Y生成代码。您可以使用位掩码来获取您正在寻找的特定情况,并只需执行正确的代码。编译器应该能够在引擎盖下使用跳转表,并且没有查找,没有条件,应该非常有效。