elena-lang icon indicating copy to clipboard operation
elena-lang copied to clipboard

PowerPC support

Open bencz opened this issue 6 years ago • 23 comments

Since Linux support already exists, we might check the possibility of adding PowerPC support in JIT.

The big problem is in the existing assembly code, it would take a lot of effort to port the GC and other parts written in Asssembly to PPC Assembly Recalling an issue (which I could not find), of porting all assembly code to C, would make it easier to add to new architectures

bencz avatar Aug 20 '18 16:08 bencz

Yes, this would be an option. I do plan to move the assembly code to C, but not now. First Linux version should be migrated to ELENA 3.4 first.

arakov avatar Aug 21 '18 05:08 arakov

I already have an IBM PowerPC computer, with OpenSuse installed, ready to start the implementation for PPC64 :)

bencz avatar Aug 30 '18 03:08 bencz

😄

arakov avatar Aug 30 '18 05:08 arakov

My current plan consists of two parts : first I move functions to prepare the program start. Then in October I will migrate GC, but part of the code will remain written in assembler : like command set, core api.

arakov avatar Aug 30 '18 07:08 arakov

I would like to know if there has been any progress on implementation for ppc, ppc64 or ppc64el ?

neosaldina avatar Dec 20 '19 08:12 neosaldina

Hi, currently it is on hold. The person who would like to do it initially is no longer interested in the project. If there will be someone who could help me with it, I will reopen the issue.

arakov avatar Dec 20 '19 08:12 arakov

Actually, I'm still interested my great friend @arakov!!! :) @neosaldina I just started the backend development for PowerPC, but as @arakov said he would migrate much of the Assembly code to C, I decided to wait :)

bencz avatar Dec 21 '19 11:12 bencz

@neosaldina To start development for PowerPC, I will initially have to know how support for Linux is ... I currently know it is stopped.

The steps I will follow to implement ppc support (32bits only initially)

  • Analyze everything that will need to be modified in source code to support big endian
  • Assembler Implementation
  • GC and basic e-code conversion to ppc
  • Linker modification to generate ELF for ppc
  • Development of JIT for ppc

are quite big modifications ... but over time will be developed As said by Mr. @arakov on issue #493 , he intends to finish refactoring development by the end of January, at exactly the time I will be moving house, city and state ... so the start will be slow... I have a prototype started, for ppc and s390 ... but, it's just prototype ....

bencz avatar Jan 01 '20 22:01 bencz

Just saving a document that IBM has already removed from their site containing the ppc32 documentation

6xx_pem.pdf

bencz avatar Jan 02 '20 09:01 bencz

Thanks, I will add support of ppc32 to asm2binx. After it we could look into 64 bit versions as well (after amd64 support of course)

arakov avatar Jan 02 '20 09:01 arakov

Ok! The things I added in asm2binx are pretty simple ... basically all registers and the implementation of a method to encode opcode...

        enum OperandType
        {
            otUnknown = 0,
            otNone = 0,

            otDD = 0x00100005,
            otDB = 0x00200005,
            otDW = 0x00400005,
            otDQ = 0x02000005,

            // ******************************
            // *** General Purpose Registers
            // ******************************
            otR0 =  0x00000000,
            otR1  = 0x00000001,
            otR2  = 0x00000002,
            otR3  = 0x00000003,
            otR4  = 0x00000004,
            otR5  = 0x00000005,
            otR6  = 0x00000006,
            otR7  = 0x00000007,
            otR8  = 0x00000008,
            otR9  = 0x00000009,
            otR10 = 0x0000000A,
            otR11 = 0x0000000B,
            otR12 = 0x0000000C,
            otR13 = 0x0000000D,
            otR14 = 0x0000000E,
            otR15 = 0x0000000F,
            otR16 = 0x00000010,
            otR17 = 0x00000011,
            otR18 = 0x00000012,
            otR19 = 0x00000013,
            otR20 = 0x00000014,
            otR21 = 0x00000015,
            otR22 = 0x00000016,
            otR23 = 0x00000017,
            otR24 = 0x00000018,
            otR25 = 0x00000019,
            otR26 = 0x0000001A,
            otR27 = 0x0000001B,
            otR28 = 0x0000001C,
            otR29 = 0x0000001D,
            otR30 = 0x0000001E,
            otR31 = 0x0000001F,

            // ****************************
            // *** Float point registers
            // ****************************
            otF0 =  0x00000000,
            otF1 =  0x00000001,
            otF2 =  0x00000002,
            otF3 =  0x00000003,
            otF4 =  0x00000004,
            otF5 =  0x00000005,
            otF6 =  0x00000006,
            otF7 =  0x00000007,
            otF8 =  0x00000008,
            otF9 =  0x00000009,
            otF10 = 0x0000000A,
            otF11 = 0x0000000B,
            otF12 = 0x0000000C,
            otF13 = 0x0000000D,
            otF14 = 0x0000000E,
            otF15 = 0x0000000F,
            otF16 = 0x00000010,
            otF17 = 0x00000011,
            otF18 = 0x00000012,
            otF19 = 0x00000013,
            otF20 = 0x00000014,
            otF21 = 0x00000015,
            otF22 = 0x00000016,
            otF23 = 0x00000017,
            otF24 = 0x00000018,
            otF25 = 0x00000019,
            otF26 = 0x0000001A,
            otF27 = 0x0000001B,
            otF28 = 0x0000001C,
            otF29 = 0x0000001D,
            otF30 = 0x0000001E,
            otF31 = 0x0000001F,
        };
PPCAssembler::Operand PPCAssembler::defineRegister(TokenInfo& token)
{
    // ******************************
    // *** General Purpose Registers
    // ******************************
    if (token.check("r0")) {
        return PPCHelper::otR0;
    }
    else if (token.check("r1")) {
        return PPCHelper::otR1;
    }
    else if (token.check("r2")) {
        return PPCHelper::otR2;
    }
    else if (token.check("r3")) {
        return PPCHelper::otR3;
    }
    else if (token.check("r4")) {
        return PPCHelper::otR4;
    }
    else if (token.check("r5")) {
        return PPCHelper::otR5;
    }
    else if (token.check("r6")) {
        return PPCHelper::otR6;
    }
    else if (token.check("r7")) {
        return PPCHelper::otR7;
    }
    else if (token.check("r8")) {
        return PPCHelper::otR8;
    }
    else if (token.check("r9")) {
        return PPCHelper::otR9;
    }
    else if (token.check("r10")) {
        return PPCHelper::otR10;
    }
    else if (token.check("r11")) {
        return PPCHelper::otR11;
    }
    else if (token.check("r12")) {
        return PPCHelper::otR12;
    }
    else if (token.check("r13")) {
        return PPCHelper::otR13;
    }
    else if (token.check("r14")) {
        return PPCHelper::otR14;
    }
    else if (token.check("r15")) {
        return PPCHelper::otR15;
    }
    else if (token.check("r16")) {
        return PPCHelper::otR16;
    }
    else if (token.check("r17")) {
        return PPCHelper::otR17;
    }
    else if (token.check("r18")) {
        return PPCHelper::otR18;
    }
    else if (token.check("r19")) {
        return PPCHelper::otR19;
    }
    else if (token.check("r20")) {
        return PPCHelper::otR20;
    }
    else if (token.check("r21")) {
        return PPCHelper::otR21;
    }
    else if (token.check("r22")) {
        return PPCHelper::otR22;
    }
    else if (token.check("r23")) {
        return PPCHelper::otR23;
    }
    else if (token.check("r24")) {
        return PPCHelper::otR24;
    }
    else if (token.check("r25")) {
        return PPCHelper::otR25;
    }
    else if (token.check("r26")) {
        return PPCHelper::otR26;
    }
    else if (token.check("r27")) {
        return PPCHelper::otR27;
    }
    else if (token.check("r28")) {
        return PPCHelper::otR28;
    }
    else if (token.check("r29")) {
        return PPCHelper::otR29;
    }
    else if (token.check("r30")) {
        return PPCHelper::otR30;
    }
    else if (token.check("r31")) {
        return PPCHelper::otR31;
    }

    // ****************************
    // *** Float point registers
    // ****************************
    else if (token.check("f0")) {
        return PPCHelper::otF0;
    }
    else if (token.check("f1")) {
        return PPCHelper::otF1;
    }
    else if (token.check("f2")) {
        return PPCHelper::otF2;
    }
    else if (token.check("f3")) {
        return PPCHelper::otF3;
    }
    else if (token.check("f4")) {
        return PPCHelper::otF4;
    }
    else if (token.check("f5")) {
        return PPCHelper::otF5;
    }
    else if (token.check("f6")) {
        return PPCHelper::otF6;
    }
    else if (token.check("f7")) {
        return PPCHelper::otF7;
    }
    else if (token.check("f8")) {
        return PPCHelper::otF8;
    }
    else if (token.check("f9")) {
        return PPCHelper::otF9;
    }
    else if (token.check("f10")) {
        return PPCHelper::otF10;
    }
    else if (token.check("f11")) {
        return PPCHelper::otF11;
    }
    else if (token.check("f12")) {
        return PPCHelper::otF12;
    }
    else if (token.check("f13")) {
        return PPCHelper::otF13;
    }
    else if (token.check("f14")) {
        return PPCHelper::otF14;
    }
    else if (token.check("f15")) {
        return PPCHelper::otF15;
    }
    else if (token.check("f16")) {
        return PPCHelper::otF16;
    }
    else if (token.check("f17")) {
        return PPCHelper::otF17;
    }
    else if (token.check("f18")) {
        return PPCHelper::otF18;
    }
    else if (token.check("f19")) {
        return PPCHelper::otF19;
    }
    else if (token.check("f20")) {
        return PPCHelper::otF20;
    }
    else if (token.check("f21")) {
        return PPCHelper::otF21;
    }
    else if (token.check("f22")) {
        return PPCHelper::otF22;
    }
    else if (token.check("f23")) {
        return PPCHelper::otF23;
    }
    else if (token.check("f24")) {
        return PPCHelper::otF24;
    }
    else if (token.check("f25")) {
        return PPCHelper::otF25;
    }
    else if (token.check("f26")) {
        return PPCHelper::otF26;
    }
    else if (token.check("f27")) {
        return PPCHelper::otF27;
    }
    else if (token.check("f28")) {
        return PPCHelper::otF28;
    }
    else if (token.check("f29")) {
        return PPCHelper::otF29;
    }
    else if (token.check("f30")) {
        return PPCHelper::otF30;
    }
    else if (token.check("f31")) {
        return PPCHelper::otF31;
    }

    else return Operand(PPCHelper::otUnknown);
}

The big secret is how to encode opcode, which is not at all complex....

        static void writeOpSegment(MemoryWriter* code, int opCode, int size, int position)
        {
            unsigned int tmpOpCode = opCode;
            int mask = (1 << size) - 1;
            tmpOpCode &= mask;
            tmpOpCode <<= (wordsize - 1 - position);
            code->writeDWord(tmpOpCode);
        }

Here, a small sample program:

#include <stdio.h>

#define WORD_SIZE 32

typedef unsigned int u32;
u32 OpHex = 0;

void WriteIntToFile(const char* desc, int val)
{
	printf("%s = %08X\n", desc, val);
}

int GetShiftNum(int endPos)
{
	return (WORD_SIZE - 1 - endPos);
}

int GetOpSegment(int val, int size, int pos)
{
  	int mask = (1 << size) - 1;
  	val &= mask;
  	val <<= GetShiftNum(pos);
	return val;
}

void STW(const char* desc, int DestReg, int AddressReg, int Immediate)
{
    // STW opcode = 0x24

	OpHex = GetOpSegment(0x24, 6, 5);
	OpHex |= GetOpSegment(DestReg, 5, 10);
	OpHex |= GetOpSegment(AddressReg, 5, 15);
	OpHex |= GetOpSegment(Immediate, 16, 31);
	WriteIntToFile(desc, OpHex);
}

void STWU(const char* desc, int DestReg, int AddressReg, int Immediate)
{
    // STW opcode = 0x25

	OpHex = GetOpSegment(0x25, 6, 5);
	OpHex |= GetOpSegment(DestReg, 5, 10);
	OpHex |= GetOpSegment(AddressReg, 5, 15);
	OpHex |= GetOpSegment(Immediate, 16, 31);
	WriteIntToFile(desc, OpHex);
}

void OR(const char* desc, int DestReg, int SourceReg1, int SourceReg2)
{
    // OR opcode = 0x1F

	OpHex = GetOpSegment(0x1F, 6, 5);
	OpHex |= GetOpSegment(SourceReg1, 5, 10);
	OpHex |= GetOpSegment(DestReg, 5, 15);
	OpHex |= GetOpSegment(SourceReg2, 5, 20);
	OpHex |= GetOpSegment(444, 10, 30);
	WriteIntToFile(desc, OpHex);
}

int main()
{
    STWU("stwu\tr1, -0x20(r1)", 0x00000001, 0x00000001, -0x20);
    STW ("stw \tr31, +0x4(r1)", 0x0000001F, 0x00000001, 28);
    OR("or  \tr31,r1,r1", 31, 1, 1);
    STW ("stw \tr31, +0x18(r31)", 0x00000003, 0x0000001F, 8);
    STW ("stw \tr31, +0x14(r31)", 0x00000004, 0x0000001F, 12);
    STW ("stw \tr31, +0x10(r31)", 0x00000005, 0x0000001F, 16);
    STW ("stw \tr31, +0xC0(r31)", 0x00000006, 0x0000001F, 20);

    return 0;
}

image

bencz avatar Jan 02 '20 10:01 bencz

One thing I don't know how complex it will be to implement is the PowerPC branch system... Branch instructions in PowerPC use the distance from the offset of the branch instruction to the next instruction to be executed, look at picture... there is two instructions with the same opcode encoding... the last byte "0x14" is the distance of offset 0x00010898 to the next instruction to be executed, on offset 0x000108AC ... this value could be positive or negative...

image

bencz avatar Jan 02 '20 10:01 bencz

Yes, it is similar to x86.

arakov avatar Jan 02 '20 11:01 arakov

I was seeing where to add in TODO.TXT, about this implementation, but, I don't know what is the correct tag to use, ydev, xdev and etc ...

bencz avatar Jan 06 '20 13:01 bencz

it doesn't matter, you may use xdev for example

arakov avatar Jan 06 '20 13:01 arakov

So what operation system should be supported? Probably Linux?

arakov avatar Jan 07 '20 10:01 arakov

Yeap, for ppc32 and ppc64, only Linux, a old version of Ubuntu and Debian Ports

bencz avatar Jan 07 '20 13:01 bencz

#77 issue : GC routine will be moved into C code, so the most complex part of CPU-dependent code will be removed. Remaining issue is floating-point opcodes in coreapi and core

arakov avatar Jan 10 '20 09:01 arakov

great!! That was the part that was scaring me the most ... I understood only part of the code! The floating point is not such a big problem ...

bencz avatar Jan 10 '20 12:01 bencz

👍

arakov avatar Jan 10 '20 12:01 arakov

The Power8 ISA is the Power ISA v.2.07 : https://en.wikipedia.org/wiki/Power_ISA#Power_ISA_v.2.07

The P8 are LittleEndian

PowerISA_V2.07B.pdf

bencz avatar Nov 18 '20 18:11 bencz

Some good resource to learn: https://godbolt.org/z/Mf9MM6

bencz avatar Nov 18 '20 18:11 bencz

The simplest program is now supported for ppc64le

arakov avatar Sep 19 '21 07:09 arakov

done

arakov avatar Mar 06 '23 14:03 arakov