CGEN

These are notes on my encounter with CGEN, tool to auto-generate new targets for gnu binutils.

Well, first of all, before even coming close to CGEN, you have to create libbfd port for your target. See my notes for more info on how to do that.

CGEN docs sudgest that you use existing port, and work by modifying it. I'm not sure it is right way to go, especialy if it's your first encounter with project like binutils. Looking at other port is of course usefull, but copying some completely different architecture and modifying it to suit your needs... What I did, was open docs, understand basic format of CPU describtion (if you have ever seen Scheme before, you already know it), and then just start defining elements one by one. For start, imagine your arch has only one model, one isa, one cou, etc. Also, imagine it only has one insn (instruction) format. Write it, get it to compile, get it to assemble test file, and then to disassemble it. Rest is just matter of typing.

Few gotcha's I run into while working on CPU describtion. Nastiest one was related to <arch>.opc file: I didn't override disassembler hashing macros, and was getting "*unknown*" for some insns. Problem was solved when I found message, describing very similar issue on cgen list. Another little gotcha for .opc files: don't forget to divide them into parts with /* -- ... */ markers.

Once you are done with writing machine describtion, you have to modify build system of opcodes, gas, etc. to make them aware of your new arch.

Opcodes

  1. Makefile.am:

    Add <cpu>-{dis|opc}.c to CFILES list
    Add respective .lo files to ALL_MACHINES list
    Add targets for .lo files:

    <arch>-dis.lo: <arch>-dis.c sysdep.h config.h $(INCDIR)/ansidecl.h \
      $(INCDIR)/dis-asm.h $(BFD_H) $(INCDIR)/symcat.h $(INCDIR)/opcode/<arch>.h
    <arch>-opc.lo: <arch>-opc.c $(INCDIR)/opcode/<arch>.h
      	     
    Add special dependancies for CGEN_MAINT case (search for if CGEN_MAINT.
    Add special targets like this:
    $(srcdir)/<arch>-desc.h $(srcdir)/<arch>-desc.c $(srcdir)/<arch>-opc.h \
    		$(srcdir)/<arch>-opc.c $(srcdir)/<arch>-ibld.c \
    		$(srcdir)/<arch>-opinst.c $(srcdir)/<arch>-asm.c \
    		$(srcdir)/<arch>-dis.c: $(<ARCH>_DEPS)
    	@true
    stamp-<arch>: $(CGENDEPS) $(CPUDIR)/<arch>.cpu <arch>.opc
    	$(MAKE) run-cgen arch=<arch> prefix=<arch> options=opinst extrafiles=opinst
    	     

  2. configure.in:

    Find list of arches (starts arround line 170).Add yours like this: bfd_<arch>_arch) ta="$ta <arch>-dis.lo <arch>-opc.lo" ;;

  3. disassemble.c:

    Add #define ARCH_<arch> to #ifdef ARCH_all
    Add

    #ifdef ARCH_<arch>
        case bfd_arch_<arch>:
            disassemble = print_insn_<arch>;
    	break;
    #endif
    		
    to big switch statement in disassembler_ftype disassembler (bfd* abfd)

  4. $srcdir/include/dis-asm.h: add declaration of print_insn_<arch>:
    extern int print_insn_<arch> PARAMS ((bfd_vma, disassemble_info*));

ld

  1. Makefile.am:

    Add your emaultaion names to ALL_EMULATIONS list.
    Add target for your emulation .c file.

  2. configure.tgt:

    Add your target there

  3. Create emulparams/<arch>.sh

gas

  1. Makefile.am:

    Add <arch> \ to CPU_TYPES list.
    Add <arch> to CPU_OBJ_VALID for all appropriate formats.
    Add config/tc-<arch>.c \ to TARGET_CPU_CFILES.
    Add config/tc-<arch>.h \ to TARGET_CPU_HFILES.
    Add DETC_<arch>_<format> variables for each format supported by your arch. Look at similar definitions for examples. Don't forget cgen related deps ($(INCDIR)/opcode/cgen.h cgen.h)
    Now do same thing with DEPOBJ and DEP vars.

  2. configure.in:

    Add your targets to big case statemt to set output file format, etc. Add your cpu to bfd_gas check (arround line 509). This seems to be optional, though. Make sure using_cgen=1 is set.

  3. tc-<arch>.[ch] -- these have to be written by hand. For info on how to do it, look elsewhere. Approach I took, was to take exsisting port (frv) and examine it looking simulteniously at internals.texi in gas/docs/

Building

OK, now you are almost ready to build your new and improved binutils. Use separate directory for build process (it will save you lot of trouble later, when you decide that you want to use same source tree to build binutils for other targets).


Now run configure:
../binutils-cvs/configure \
    --target=bsp \
    --enable-cgen-maint \
    --prefix=/crossdev/$TARCH \
    --enable-targets="<arch>"

Once you got configure to run successfully, you need to run cgen to regenerate files. From CGEN FAQ-o-Matic: While some dependencies are recorded in the Makefiles, most or all are approximate and incomplete (e.g., including only the .cpu file but not .opc; including some .scm files of cgen itself but not all). The safest way is to regenerate cgen stuff by hand. The problem is remembering what each build directory's regeneration make target is:

opcodes:                         make stamp-TARGET
sim/TARGET:                      make stamp-arch stamp-cpu stamp-desc
sid/component/cgen-cpu/TARGET:   make cgen-all   
cgen puts the modified files back in the source tree.