Modifying GCC to work with my FPGA computer

This is a followup of my original post.

In this text I will talk about the modification of the GCC compiler in order to work with my FPGA platform. I wanted to make a cross-compiler that would be able to compile C programs for my FPGA platform. This post will describe how far I have reached. Currently, a modified GCC compiler produces assembly code for my platform as a result of C program compilation.

When I say a cross-compiler, I think of a compiler that would compile C code on my PC, but the executable would be for my FPGA computer. GCC already supports a lot of cross-compilers and all you have to do is to choose the appropriate target when building GCC. That way, you will build a cross-compiler that would produce an executable for the target platform. However, if you have created a new platform, then you need to add a cross-compiler code to the GCC, and then build a cross-compiler for that new platform. That step is very complicated. Trying to add your own platform into the GCC is almost impossible job if you have not done something like that already (I haven't).

I have found a very useful blog post that describes how GCC generates code:

https://kristerw.blogspot.com/2017/08/writing-gcc-backend_4.html

Besides that blog, there is a simple GCC cross-compiler that is present in the list of supported cross compilers - moxie. The author is Anthony Green and he has initially made a blog about modifying GCC for a fictional platform - moxie:

http://atgreen.github.io/ggx/

The project managed to become an official part of GCC and is now incorporated in the GCC source tree.

There is a sandboxed environment made for this platform - moxiebox. The code is on the github repository: https://github.com/jgarzik/moxiebox

I have forked that repo and added my own modification of a moxie cross compiler that is adjusted for my own FPGA platform:

https://github.com/milanvidakovic/moxiebox

So, how can you use moxie to make your own gcc cross-compiler? We need to know at least fundamentals of GCC compiler to do so. First of all, there is a frontend and there is a backend. Frontend deals with the actual compiling and produces a target-independent representation code, which is a passed to the backend, which in turn generates target platform code. Between frontend and backend is an optimizer, whose job is obvious.

Backend starts target platform code generation by processing insns. An insn is a kind of a virtual assembly instruction created by the frontend during compilation. Your cross-compiler now need to generate a real machine instruction(s) out of an insn. That is where I have started to investigate moxie.

First of all, I have downloaded moxiebox from the github and unpacked that on the disk. Then I have installed necessary packages to be able to build moxiebox on my Ubuntu:

sudo apt install device-tree-compiler texinfo flex  build-essential libgmp-dev libmpfr-dev libmpc-dev
sudo apt install git subversion cvs

Then I have executed the
/moxiebox/contrib/download-tools-sources.sh script. After that, the moxiebox is ready to start building. You do so by executing the
/moxiebox/contrib/build-moxiebox-tools.sh script. It takes about an hour to build everything.

To make moxie-based gcc tools present in the path, you need to add them to PATH and LD_LIBRARY_PATH in your .bashrc file (at the end):

export PATH=/moxiebox/contrib/root/usr/bin:$PATH
export LD_LIBRARY_PATH=/moxiebox/contrib/root/usr/lib:$LD_LIBRARY_PATH

Now it is a good moment to start changing original moxie cross-compiler in order to work with my platform. Fortunately, moxie is quite similar to my FPGA CPU, so it was not a huge job.

First of all, I have changed /moxiebox/contrib/gcc/gcc/config/moxie/moxie.md file to generate my FPGA instructions instead of moxie ones.  Here is one example:

(define_insn "*movsi"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,W,A,r,r,B,r")
(match_operand:SI 1 "moxie_general_movsrc_operand" "O,r,i,r,r,W,A,r,B"))]
  "register_operand (operands[0], SImode)
   || register_operand (operands[1], SImode)"
  "@
   xor.w\\t%0, %0
   mov.w\\t%0, %1
   mov.w\\t%0, %1
   st.w\\t%0, %1
   st.w\\t[%0], %1
   ld.w\\t%0, %1
   ld.w\\t%0, [%1]
   st.w\\t%0, %1
   ld.w\\t%0, %1"
  [(set_attr "length" "2,2,6,2,6,2,6,6,6")])

Then I have changed moxie.c and moxie.h in order to use my own register names and to generate stack frame epilogue and prologue the way I am used to. Prologue:

emit_insn (gen_movsi_push (hard_frame_pointer_rtx));
emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
moxie_compute_frame ();

And epilogue:

emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
emit_insn (gen_movsi_pop (hard_frame_pointer_rtx, hard_frame_pointer_rtx));
emit_jump_insn (gen_returner ());

I have tried to make a standard stack frame and to pass all the arguments over the stack frame, instead of registers (it is slower, but I understand it better). I have placed the patch which substitutes original moxie cross-compiler files here:

https://github.com/milanvidakovic/moxiebox/blob/master/contrib/contrib.zip

When I try to build the whole package I still get a lot of errors, but I now have the moxiebox-gcc compiler which (unfortunately) cannot build the whole executable, but can generate assembly file by using the -S argument:

moxiebox-gcc -S test.c -o test.s

After that, it was easy to use the customasm assembler to generate the executable for my platform.

Conclusion

I have done just a half of the job. Currently, only the assembly files are being generated out of the C files. Next step is to change GCC assembler (and linker) to produce a proper executable.



Comments

Comments powered by Disqus