Page 1 of 2

Reference doc question

PostPosted: Thu Jan 05, 2017 10:09 am
by upcFrost
Hi,

I'm trying to make a simple llvm backend for Epiphany CPU (originally based on Hoenchen's code, later decided to rewrite it from scratch using Cpu0 backend writing manual as a reference), and I'm getting stuck at some places.
As subject states, it's about arch reference doc. In the instruction set table (Appendix C of the PDF) there's a number of empty spaces, e.g. in MOV(imm)32 instruction. I originally assumed those spaces to be zeros, but after compiling the same code with e-gcc and my backend it turned out that bits 16-19 (empty ones) should be assigned to 0b0010, similar to MOV(reg)32 instructions. There's also a number of empty spaces in math-related instructions, so i want to ask if i'm missing something, or maybe there's a full table somewhere with those spaces filled?

BR,
Petr

P.S. I'm working with LLVM 3.9.0, the code is partially available at https://github.com/upcFrost/Epiphany. Partially, as it also requires some changes in the other parts of the LLVM tree except /lib/Target. I'll publish them as a patch later. Atm, the backend can resolve asm for basic algebra (int/float) and simple moves/ldr/str, and it can generate ELFs which i'm currently trying to fix. No array/struct/branching support atm, working on it.
P.P.S. Btw, is it ok if i'll use some algorithms for missing functions from e-gcc, such as div or srem?

Re: Reference doc question

PostPosted: Thu Jan 05, 2017 6:18 pm
by aolofsson
That is very cool!
For the irregular instructios that are one or two operand i structions, we make RN=RM to simplify HW.

Most up to date doc sources are here. If there is something missing or unclear we will fix it.

https://github.com/adapteva/epiphany-do ... x-A_isa.md

Re: Reference doc question

PostPosted: Thu Jan 05, 2017 10:04 pm
by upcFrost
Thanks for the link!

So, I was talking about MOV IMM 32 instruction from IMM-INT section. In both pdf and .md file over the link, bits 19:16 are marked as "xxxx" aka "Don't care, should be zero for forward compatibility".
But e-gcc sets them as 0b0010, similar to all other MOV instructions. And using e-objdump to disasm the ELF results in *unknown* instruction unless those bits are set to 0b0010. Which way is correct, zeros or e-gcc way?
Those bits are neither RM nor RN in any other instructions.

Re: Reference doc question

PostPosted: Mon Jan 09, 2017 4:25 pm
by olajep
Hi Petr,

You are right, that seems wrong.
Added issue here for tracking:
https://github.com/adapteva/epiphany-sdk/issues/71

I have no possibility to confirm whether they're really "dont-care" so I'd suggest you stick the the below toolchain definition because we know that one works.

Here is the definition the Epiphany toolchain uses:
https://github.com/adapteva/epiphany-cg ... .cpu#L3056
Code: Select all
        (+ OP4_IMM32 (f-opc-4-1 #x0) (f-opc-19-4 #x2) (f-dc-28-1 #x0) rd6 imm16)



Thanks,
Ola

Re: Reference doc question

PostPosted: Mon Jan 09, 2017 9:12 pm
by upcFrost
Hi Ola,

Thanks for opening the ticket.
Just one more question about e-gcc behaviour. It generates quite a huge file in terms of prologue and epilogue, like couple of hundreds of instructions for smth like "return 0". I've seen some of those explicitly stated in e-gcc source, but i was unable to find any reference on what should be done in the doc.
Is there some sequence of actions that I should do before and after executing the actual code? Like, starting the core, setting up the int/float mode, etc.
I can reverse the asm from e-gcc, but maybe it's mentioned somewhere else.

Thanks,
Petr

p.s. just finished fixing the backend ELF generator, now it can almost properly compile this test: https://github.com/adapteva/epiphany-examples/tree/2015.1/test/e-main. Almost - still hitting the wall with STR/LDR, for some weird reason LLVM makes them 32-bit in any case, while I want to make them 16-bit where it's possible (though it is still correct). Also, default calling convention is strange, but ok-tier for now. Will try to run it tomorrow

Re: Reference doc question

PostPosted: Tue Jan 10, 2017 4:32 pm
by sebraa
Please don't confuse the code generation with the runtime environment. In addition to the code generated from your C code by the compiler, additional code is linked into every executable. This includes the interrupt vector table (and the vectors themself), startup code and other stuff. All of this is part of the C library and (at least partially) implemented in assembly language. This object (called crt0.o or crt0.s) is is responsible for bringing up the core from whatever state it is in after power-on and initializing any data structures needed, calling static constructors/destructors appropriately and similar.

I have written a tiny startup code, which I have attached for reference. It is based on startup code I have written for some ARM Cortex-M platforms, and I haven't tested it much on the Epiphany. While I can't guarantee that it works completely, it might still serve as a starting point.

Re: Reference doc question

PostPosted: Tue Jan 10, 2017 5:26 pm
by olajep
upcFrost wrote:Just one more question about e-gcc behaviour. It generates quite a huge file in terms of prologue and epilogue, like couple of hundreds of instructions for smth like "return 0". I've seen some of those explicitly stated in e-gcc source, but i was unable to find any reference on what should be done in the doc.

W/o any optimization flags the compiler always saves/restores the frame pointer to the stack, but other than that there is no large prologue / epilogue for trivial code like int main() { return 0; }.

upcFrost wrote:Is there some sequence of actions that I should do before and after executing the actual code? Like, starting the core, setting up the int/float mode, etc.

Inside the function you need to store / restore the stack pointer if you use the stack + frame pointer + callee save registers.

To start with I recommend to just compile the function you want to test to a separate object file with clang, and then compile main with e-gcc and link in the clang object file.
Code: Select all
// foo.c
int foo(int a, int b)
{
return a + b;
}

// main.c
extern int foo(int a, int b);
int main()
{
  return foo(1,2) == 3 ? 0 : 1;
}

$ clang -c foo.c
$ e-gcc main.c foo.o

Later you should figure out how to link with newlib (the libc we use). Passing -v to gcc will tell you all the libraries and object files gcc links with (and in which order) to create a program.
There should be a clang equivalent to libgcc that you should use instead. You might be able to user crti and crtn from libgcc or write your own.
https://github.com/adapteva/epiphany-gc ... g/epiphany

If you want to understand the startup sequence go look here:
https://github.com/adapteva/epiphany-ne ... any/crt0.S

The entry point is _start, which should be placed at 0x0 which happens to be SYNC interrupt vectory entry.

upcFrost wrote:I can reverse the asm from e-gcc, but maybe it's mentioned somewhere else.

I did that once myself, this might be helpful (or confuse you :p)
https://github.com/parallella/pal/blob/ ... der.c#L608

HTH, Ola

Re: Reference doc question

PostPosted: Thu Jan 12, 2017 4:08 pm
by upcFrost
Thanks Ola, i've actually mixed up link and compilation for some reason.
I'm now trying to somehow process everything that both you and @sebraa told me.
As for the current state - it compiles, it links with e-gcc, and it even runs. I'm talking about the example code you gave me in your post.
I have only two problems with it atm. First - there's some strange bug if i assemble it with -O0, it tries to write to 0x0. Second, i've missed that STR/LDR actually shifts the imm value by the type size, so i need to be more careful with the stack adjustment.
In any case, it almost works, at least for this simple example.

BR,
Petr

Re: Reference doc question

PostPosted: Fri Jan 13, 2017 6:32 pm
by upcFrost
Ok, i've fixed the stack and frame pointers handling, as well as store/load instructions. Can't say that it is the most beautiful solution in this world, but i really don't want to mess with LLVM's stack calculation process. It's easier just to declare store-load as special cases with additiona shift provided in both asm and machine code printers instead of telling LLVM how exactly it should calculate stack offsets in each case.

In any case - hurray, it works :D Both the example from Ola and the https://github.com/adapteva/epiphany-ex ... est/e-main. The test from the second example reports success.
So, well, probably i'll continue with function calls now, as they're not yet implemented.

BR,
Petr

Re: Reference doc question

PostPosted: Tue Jan 24, 2017 3:04 pm
by upcFrost
Just a small update to indicate that the backend development is still alive. I've added calls, so now some simple functions like the following work.

Code: Select all
int foo() {
  return 2;
}

int main() {
  int a = foo();
  if (a > 1) return 0;
    return 5;
}


I'm currently working on branch optimization, as it generates useless jumps to the very next instructions without it.