On Wed, Jun 24, 2009 at 09:30:11PM -0400, Gabriel Michael Black wrote:
> > Also, is it the case that you can write the PC with any opcode?  I vaguely
> > recall hearing that that was deprecated at some point.
> >
> 
> I don't know. I saw some places in the ARM manual where it said some  
> uses of R15 cause undefined behavior. I don't know where to find a  
> concise description of where it is and isn't allowed.

I've also been looking at this problem. I want to get the O3 CPU working with
the ARM ISA, and I've been making some progress. The two sticking points are 
predicated execution and the PC's "pseudo-GPR" nature. So, hopefully I
can contribute something to your discussion.

As I see it, the big problem is when the PC is a destination for
an operation that normally produces a GPR. As a source, you
can always get the right behaviour quite easily (as you said, + 8):
> >> Example reading code:
> >> Rn = (RN == PCReg) ? xc->readPC() : xc->readIntRegOperand(this, 0);

I've gone through the ARM ARM, looked at all the integer instructions,
and the writes to PC *always* fall into one of the following categories:
1. Performed via an explicit branch instruction (b, blx, etc.)
2. Performed by load multiple (e.g. ldmia).
3. Performed by an ALU or load operation that writes to Rd, with Rd =
   15. (Rd is machine code bits 15..12 as defined in operands.isa).

Case 1 is easy, same as any other CPU. Case 2 is only slightly more
difficult, because you can generate a special "write to PC" uop
resembling a conditional branch.

Case 3 is the difficulty. But it's not so bad, because-
* The PC is *always* written via Rd. Not Rs, Rm, etc.
* No other registers are updated (except Cpsr).

Here are the instructions that fall into case 3:
ADC     ADD     AND     BIC
CLZ     EOR     LDR     LDRB
LDRBT   LDRH    LDRSB   LDRSH
LDRT    MOV     MVN     ORR     
RSB     RSC     SBC     SUB

It is possible to specify r15 as the output of some other instructions
(e.g. MUL, MLA), but the results are not defined by the ISA.

Clearly, there are a number of ways to handle this. Any of these
instructions could write the PC, creating a branch. 

Here is my suggestion for how to handle case 3 instructions. I am
relatively new to M5, so this may not be the best way, but some
preliminary tests suggest it will work. First, the control flags need 
to change if the instruction writes to r15:

    // base_dyn_inst.hh:
    bool isControl()      const
    { return staticInst->isControl() || isPCLoad(); }
    bool isIndirectCtrl() const
    { return staticInst->isIndirectCtrl() || isPCLoad(); }
    bool isCondCtrl()     const
    { return staticInst->isCondCtrl() || isPCLoad(); }

The new function isPCLoad() returns true if the ISA is ARM
and one of the destination registers is 15 (before renaming):

    bool isPCLoad(void) const
    {
#if THE_ISA == ARM_ISA
        for (int i = 0; i < numDestRegs(); i++) {
            if (staticInst->destRegIdx(i) == TheISA::PCReg) {
                return true;
            }
        }
#endif  
        return false;
    }

This way, we don't have to change the ISA definitions for case 3 
instructions. They automatically become branches if rD = 15. 

However, this still leaves the problem of operations that load the new
PC from memory, such as:
    ldreq   pc, [sp], #4

On O3, these are tricky because the new PC is not known until the 
load completes (LSQUnit::writeback), but branch mispredictions are only 
recognised when the load starts (LSQUnit::executeLoad). My suggestion
for these is to generate a branch misprediction in LSQUnit::writeback,
if (inst->isPCLoad()&&inst->mispredicted), and don't generate a branch
misprediction in the regular place if inst->isPCLoad().


-- 
Jack Whitham
j...@cs.york.ac.uk

_______________________________________________
m5-dev mailing list
m5-dev@m5sim.org
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to