Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2bc2b792 authored by Paul Lind's avatar Paul Lind
Browse files

Add MIPS support to pixelflinger.

See the comment-block at the top of MIPSAssembler.cpp for
implementation overview.

Change-Id: Id492c10610574af8c89c38d19e12fafc3652c28a
parent ae8927aa
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@ PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
endif

ifeq ($(TARGET_ARCH),mips)
PIXELFLINGER_SRC_FILES += codeflinger/MIPSAssembler.cpp
PIXELFLINGER_SRC_FILES += codeflinger/mips_disassem.c
PIXELFLINGER_SRC_FILES += arch-mips/t32cb16blend.S
PIXELFLINGER_CFLAGS += -fstrict-aliasing -fomit-frame-pointer
endif
+146 −0
Original line number Diff line number Diff line
@@ -76,6 +76,11 @@ void ARMAssembler::reset()
    mComments.clear();
}

int ARMAssembler::getCodegenArch()
{
    return CODEGEN_ARCH_ARM;
}

// ----------------------------------------------------------------------------

void ARMAssembler::disassemble(const char* name)
@@ -444,5 +449,146 @@ void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
    *mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
}

#if 0
#pragma mark -
#pragma mark Addressing modes...
#endif

int ARMAssembler::buildImmediate(
        uint32_t immediate, uint32_t& rot, uint32_t& imm)
{
    rot = 0;
    imm = immediate;
    if (imm > 0x7F) { // skip the easy cases
        while (!(imm&3)  || (imm&0xFC000000)) {
            uint32_t newval;
            newval = imm >> 2;
            newval |= (imm&3) << 30;
            imm = newval;
            rot += 2;
            if (rot == 32) {
                rot = 0;
                break;
            }
        }
    }
    rot = (16 - (rot>>1)) & 0xF;

    if (imm>=0x100)
        return -EINVAL;

    if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
        return -1;

    return 0;
}

// shifters...

bool ARMAssembler::isValidImmediate(uint32_t immediate)
{
    uint32_t rot, imm;
    return buildImmediate(immediate, rot, imm) == 0;
}

uint32_t ARMAssembler::imm(uint32_t immediate)
{
    uint32_t rot, imm;
    int err = buildImmediate(immediate, rot, imm);

    LOG_ALWAYS_FATAL_IF(err==-EINVAL,
                        "immediate %08x cannot be encoded",
                        immediate);

    LOG_ALWAYS_FATAL_IF(err,
                        "immediate (%08x) encoding bogus!",
                        immediate);

    return (1<<25) | (rot<<8) | imm;
}

uint32_t ARMAssembler::reg_imm(int Rm, int type, uint32_t shift)
{
    return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
}

uint32_t ARMAssembler::reg_rrx(int Rm)
{
    return (ROR<<5) | (Rm&0xF);
}

uint32_t ARMAssembler::reg_reg(int Rm, int type, int Rs)
{
    return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
}

// addressing modes...
// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
uint32_t ARMAssembler::immed12_pre(int32_t immed12, int W)
{
    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
                        immed12);
    return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
            ((W&1)<<21) | (abs(immed12)&0x7FF);
}

uint32_t ARMAssembler::immed12_post(int32_t immed12)
{
    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
                        immed12);

    return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
}

uint32_t ARMAssembler::reg_scale_pre(int Rm, int type,
        uint32_t shift, int W)
{
    return  (1<<25) | (1<<24) |
            (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
            reg_imm(abs(Rm), type, shift);
}

uint32_t ARMAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
{
    return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
}

// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
uint32_t ARMAssembler::immed8_pre(int32_t immed8, int W)
{
    uint32_t offset = abs(immed8);

    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
                        immed8);

    return  (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
            ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
}

uint32_t ARMAssembler::immed8_post(int32_t immed8)
{
    uint32_t offset = abs(immed8);

    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
                        immed8);

    return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
            (((offset&0xF0)<<4) | (offset&0xF));
}

uint32_t ARMAssembler::reg_pre(int Rm, int W)
{
    return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
}

uint32_t ARMAssembler::reg_post(int Rm)
{
    return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
}

}; // namespace android
+41 −8
Original line number Diff line number Diff line
@@ -52,11 +52,42 @@ public:
    virtual void    reset();

    virtual int     generate(const char* name);
    virtual int     getCodegenArch();

    virtual void    prolog();
    virtual void    epilog(uint32_t touched);
    virtual void    comment(const char* string);


    // -----------------------------------------------------------------------
    // shifters and addressing modes
    // -----------------------------------------------------------------------

    // shifters...
    virtual bool        isValidImmediate(uint32_t immed);
    virtual int         buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);

    virtual uint32_t    imm(uint32_t immediate);
    virtual uint32_t    reg_imm(int Rm, int type, uint32_t shift);
    virtual uint32_t    reg_rrx(int Rm);
    virtual uint32_t    reg_reg(int Rm, int type, int Rs);

    // addressing modes...
    // LDR(B)/STR(B)/PLD
    // (immediate and Rm can be negative, which indicates U=0)
    virtual uint32_t    immed12_pre(int32_t immed12, int W=0);
    virtual uint32_t    immed12_post(int32_t immed12);
    virtual uint32_t    reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
    virtual uint32_t    reg_scale_post(int Rm, int type=0, uint32_t shift=0);

    // LDRH/LDRSB/LDRSH/STRH
    // (immediate and Rm can be negative, which indicates U=0)
    virtual uint32_t    immed8_pre(int32_t immed8, int W=0);
    virtual uint32_t    immed8_post(int32_t immed8);
    virtual uint32_t    reg_pre(int Rm, int W=0);
    virtual uint32_t    reg_post(int Rm);


    virtual void    dataProcessing(int opcode, int cc, int s,
                                int Rd, int Rn,
                                uint32_t Op2);
@@ -83,21 +114,23 @@ public:
    virtual uint32_t* pcForLabel(const char* label);

    virtual void LDR (int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0));
                int Rn, uint32_t offset = __immed12_pre(0));
    virtual void LDRB(int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0));
                int Rn, uint32_t offset = __immed12_pre(0));
    virtual void STR (int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0));
                int Rn, uint32_t offset = __immed12_pre(0));
    virtual void STRB(int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0));
                int Rn, uint32_t offset = __immed12_pre(0));
    virtual void LDRH (int cc, int Rd,
                int Rn, uint32_t offset = immed8_pre(0));
                int Rn, uint32_t offset = __immed8_pre(0));
    virtual void LDRSB(int cc, int Rd, 
                int Rn, uint32_t offset = immed8_pre(0));
                int Rn, uint32_t offset = __immed8_pre(0));
    virtual void LDRSH(int cc, int Rd,
                int Rn, uint32_t offset = immed8_pre(0));
                int Rn, uint32_t offset = __immed8_pre(0));
    virtual void STRH (int cc, int Rd,
                int Rn, uint32_t offset = immed8_pre(0));
                int Rn, uint32_t offset = __immed8_pre(0));


    virtual void LDM(int cc, int dir,
                int Rn, int W, uint32_t reg_list);
    virtual void STM(int cc, int dir,
+8 −115
Original line number Diff line number Diff line
@@ -32,77 +32,15 @@ ARMAssemblerInterface::~ARMAssemblerInterface()
{
}

int ARMAssemblerInterface::buildImmediate(
        uint32_t immediate, uint32_t& rot, uint32_t& imm)
{
    rot = 0;
    imm = immediate;
    if (imm > 0x7F) { // skip the easy cases
        while (!(imm&3)  || (imm&0xFC000000)) {
            uint32_t newval;
            newval = imm >> 2;
            newval |= (imm&3) << 30;
            imm = newval;
            rot += 2;
            if (rot == 32) {
                rot = 0;
                break;
            }
        }
    }
    rot = (16 - (rot>>1)) & 0xF;

    if (imm>=0x100)
        return -EINVAL;

    if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
        return -1;

    return 0;
}

// shifters...
// --------------------------------------------------------------------

bool ARMAssemblerInterface::isValidImmediate(uint32_t immediate)
{
    uint32_t rot, imm;
    return buildImmediate(immediate, rot, imm) == 0;
}
// The following two functions are static and used for initializers
// in the original ARM code. The above versions (without __), are now
// virtual, and can be overridden in the MIPS code. But since these are
// needed at initialization time, they must be static. Not thrilled with
// this implementation, but it works...

uint32_t ARMAssemblerInterface::imm(uint32_t immediate)
{
    uint32_t rot, imm;
    int err = buildImmediate(immediate, rot, imm);

    LOG_ALWAYS_FATAL_IF(err==-EINVAL,
                        "immediate %08x cannot be encoded",
                        immediate);

    LOG_ALWAYS_FATAL_IF(err,
                        "immediate (%08x) encoding bogus!",
                        immediate);

    return (1<<25) | (rot<<8) | imm;
}

uint32_t ARMAssemblerInterface::reg_imm(int Rm, int type, uint32_t shift)
{
    return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
}

uint32_t ARMAssemblerInterface::reg_rrx(int Rm)
{
    return (ROR<<5) | (Rm&0xF);
}

uint32_t ARMAssemblerInterface::reg_reg(int Rm, int type, int Rs)
{
    return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
}

// addressing modes... 
// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
uint32_t ARMAssemblerInterface::immed12_pre(int32_t immed12, int W)
uint32_t ARMAssemblerInterface::__immed12_pre(int32_t immed12, int W)
{
    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
@@ -111,30 +49,7 @@ uint32_t ARMAssemblerInterface::immed12_pre(int32_t immed12, int W)
            ((W&1)<<21) | (abs(immed12)&0x7FF);
}

uint32_t ARMAssemblerInterface::immed12_post(int32_t immed12)
{
    LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
                        "LDR(B)/STR(B)/PLD immediate too big (%08x)",
                        immed12);

    return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
}

uint32_t ARMAssemblerInterface::reg_scale_pre(int Rm, int type, 
        uint32_t shift, int W)
{
    return  (1<<25) | (1<<24) | 
            (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
            reg_imm(abs(Rm), type, shift);
}

uint32_t ARMAssemblerInterface::reg_scale_post(int Rm, int type, uint32_t shift)
{
    return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
}

// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
uint32_t ARMAssemblerInterface::immed8_pre(int32_t immed8, int W)
uint32_t ARMAssemblerInterface::__immed8_pre(int32_t immed8, int W)
{
    uint32_t offset = abs(immed8);

@@ -146,28 +61,6 @@ uint32_t ARMAssemblerInterface::immed8_pre(int32_t immed8, int W)
            ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
}

uint32_t ARMAssemblerInterface::immed8_post(int32_t immed8)
{
    uint32_t offset = abs(immed8);

    LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
                        "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
                        immed8);

    return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
            (((offset&0xF0)<<4) | (offset&0xF));
}

uint32_t ARMAssemblerInterface::reg_pre(int Rm, int W)
{
    return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
}

uint32_t ARMAssemblerInterface::reg_post(int Rm)
{
    return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
}


}; // namespace android
+31 −23
Original line number Diff line number Diff line
@@ -62,33 +62,40 @@ public:
        LSAVED = LR4|LR5|LR6|LR7|LR8|LR9|LR10|LR11 | LLR
    };

    enum {
        CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS
    };

    // -----------------------------------------------------------------------
    // shifters and addressing modes
    // -----------------------------------------------------------------------

    // shifters...
    static bool        isValidImmediate(uint32_t immed);
    static int         buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
    // these static versions are used for initializers on LDxx/STxx below
    static uint32_t    __immed12_pre(int32_t immed12, int W=0);
    static uint32_t    __immed8_pre(int32_t immed12, int W=0);

    virtual bool        isValidImmediate(uint32_t immed) = 0;
    virtual int         buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm) = 0;

    static uint32_t    imm(uint32_t immediate);
    static uint32_t    reg_imm(int Rm, int type, uint32_t shift);
    static uint32_t    reg_rrx(int Rm);
    static uint32_t    reg_reg(int Rm, int type, int Rs);
    virtual uint32_t    imm(uint32_t immediate) = 0;
    virtual uint32_t    reg_imm(int Rm, int type, uint32_t shift) = 0;
    virtual uint32_t    reg_rrx(int Rm) = 0;
    virtual uint32_t    reg_reg(int Rm, int type, int Rs) = 0;

    // addressing modes... 
    // LDR(B)/STR(B)/PLD
    // (immediate and Rm can be negative, which indicates U=0)
    static uint32_t    immed12_pre(int32_t immed12, int W=0);
    static uint32_t    immed12_post(int32_t immed12);
    static uint32_t    reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
    static uint32_t    reg_scale_post(int Rm, int type=0, uint32_t shift=0);
    virtual uint32_t    immed12_pre(int32_t immed12, int W=0) = 0;
    virtual uint32_t    immed12_post(int32_t immed12) = 0;
    virtual uint32_t    reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0) = 0;
    virtual uint32_t    reg_scale_post(int Rm, int type=0, uint32_t shift=0) = 0;

    // LDRH/LDRSB/LDRSH/STRH
    // (immediate and Rm can be negative, which indicates U=0)
    static uint32_t    immed8_pre(int32_t immed8, int W=0);
    static uint32_t    immed8_post(int32_t immed8);
    static uint32_t    reg_pre(int Rm, int W=0);
    static uint32_t    reg_post(int Rm);
    virtual uint32_t    immed8_pre(int32_t immed8, int W=0) = 0;
    virtual uint32_t    immed8_post(int32_t immed8) = 0;
    virtual uint32_t    reg_pre(int Rm, int W=0) = 0;
    virtual uint32_t    reg_post(int Rm) = 0;

    // -----------------------------------------------------------------------
    // basic instructions & code generation
@@ -98,6 +105,7 @@ public:
    virtual void reset() = 0;
    virtual int  generate(const char* name) = 0;
    virtual void disassemble(const char* name) = 0;
    virtual int  getCodegenArch() = 0;
    
    // construct prolog and epilog
    virtual void prolog() = 0;
@@ -143,22 +151,22 @@ public:

    // data transfer...
    virtual void LDR (int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0)) = 0;
                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
    virtual void LDRB(int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0)) = 0;
                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
    virtual void STR (int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0)) = 0;
                int Rn, uint32_t offset = __immed12_pre(0)) = 0;
    virtual void STRB(int cc, int Rd,
                int Rn, uint32_t offset = immed12_pre(0)) = 0;
                int Rn, uint32_t offset = __immed12_pre(0)) = 0;

    virtual void LDRH (int cc, int Rd,
                int Rn, uint32_t offset = immed8_pre(0)) = 0;
                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
    virtual void LDRSB(int cc, int Rd, 
                int Rn, uint32_t offset = immed8_pre(0)) = 0;
                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
    virtual void LDRSH(int cc, int Rd,
                int Rn, uint32_t offset = immed8_pre(0)) = 0;
                int Rn, uint32_t offset = __immed8_pre(0)) = 0;
    virtual void STRH (int cc, int Rd,
                int Rn, uint32_t offset = immed8_pre(0)) = 0;
                int Rn, uint32_t offset = __immed8_pre(0)) = 0;

    // block data transfer...
    virtual void LDM(int cc, int dir,
Loading