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).
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/moxieboxSo, 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-devsudo apt install git subversion
cvsThen 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:$PATHexport
LD_LIBRARY_PATH=/moxiebox/contrib/root/usr/lib:$LD_LIBRARY_PATHNow 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.zipWhen
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.sAfter 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.