Porting
*******

This chapter describes how to do a CGEN port. It focuses on doing binutils and simulator ports, but the procedure should be generally applicable.

Introduction to porting
=======================

Doing a GNU tools port for a new processor basically consists of porting the following components more or less in order.  The order can be changed, of course, but the following order is reasonable.  Certainly things like BFD and opcodes need to be finished earlier than others.  Bugs in earlier pieces are often not found until testing later pieces so each piece isn't necessarily finished until they all are.

  * DejaGNU

  * BFD

  * CGEN

  * Opcodes

  * GAS

  * Binutils

  * Linker (ld)

  * newlib

  * libgloss

  * simulator

  * GCC

  * GDB

The use of CGEN affects the opcodes, GAS, and simulator portions only. As always, the M32R port is a good reference base.

One goal of CGEN is to describe the CPU in an application independent manner so that program generators can do all the repetitive work of generating code and tables for each CPU that is ported.

For opcodes, several files are generated.  No additional code need be written in the opcodes directory although as an escape hatch the user can add target specific code to file <arch>.opc in the CGEN cpu source directory.  These functions will be included in the relevant generated files.  An example of when you need to create an <arch>.opc file is when there are special pseudo-ops that need to be parsed, for example the high/shigh pseudo-ops of the M32R. See Doing an opcodes port.

For GAS, no files are generated (except test cases!) so the port is done more or less like the other GAS ports except that the assembler uses the CGEN-built opcode table plus toplevel/gas/cgen.[ch].

For the simulator, several files are built, and other support files need to be written.  See Doing a simulator port.

Supported Guile versions
========================

In order to avoid suffering from the bug of the day when using snapshots, CGEN development has been confined to Guile releases only. CGEN has been tested with and supports Guile versions 1.6.8 and 1.8.5. As time passes older versions of Guile will no longer be supported.

Running configure
=================

When doing porting or maintenance activity with CGEN, it's a good idea to configure the build tree with the --enable-cgen-maint option. This adds the necessary dependencies to the toplevel/opcodes and toplevel/sim directories so that when the .cpu file is changed the makefiles will regenerated the corresponding sources.

CGEN uses Guile so it must be installed.

Writing a CPU description file
==============================

The first step in doing a CGEN port is writing a CPU description file. The best way to do that is to take an existing file (such as the M32R) and use it as a template.

Writing a CPU description file generally involves writing each of the following types of entries, in order.  See RTL, for detailed descriptions of each type of entry that appears in the description file.

Conventions
-----------

First a digression on conventions and programming style.

  * define-foo vs. define-normal-foo

     Each CPU description define- entry generally provides two forms: the normal form and the general form.  The normal form has a simple, fixed-argument syntax that allows one to specify the most popular elements.  When one needs to specify more obscure elements of the entry one uses the long form which is a list of name/value pairs.  The naming convention is to call the normal form define-normal-foo and the general form define-foo.

  * Parentheses placement

     Consider:

          (define-normal-insn-enum
            insn-op1 "insn format enums" () f-op1 OP1_
            (ADD ADDC SUB SUBC
             AND OR   XOR INV)
          )

     All Lisp/Scheme code I've read puts the trailing parenthesis on the previous line.  CGEN programming style says the last trailing parenthesis goes on a line by itself.  If someone wants to put forth an argument of why this should change, please do.  I like putting the very last parenthesis on a line by itself in column 1 because it makes it easier to traverse the file with a parenthesis matching keystroke.

  * StudlyCaps vs. _ vs. -

     The convention is to have most things lowercase with words separated by -.  Things that are uppercase are fixed and well defined: enum values and mode names. This convention must be followed.

  * Integers

     There are two things to keep in mind regarding integers in CGEN.

      1. Unspecified width

          Integers in CGEN generally don't specify a width. The width is imposed by context.

      2. RTL canonicalization

          Integers in RTL may simply be written as a number, or in the full canonical form as (const [<option-list>] [<mode>] <value>).

          The ``option list'', if specified, must be () as there are currently no options for constants. It is optional and is generally elided when written.

          The ``mode'' of the number specifies the precision. The default mode is INT meaning arbitrary precision.

          In RTL, whether to write just the number, e.g. 24, or the full canonical form, e.g., (const () INT 24), or anything in between is a matter of style.

simplify.inc
------------

The file simplify.inc provides several pmacros that help simplify writing .cpu files.

To use it add the following to your .cpu file.

     (include "simplify.inc")

simplify.inc provides the following pmacros:

  * define-normal-enum (see define-normal-enum)

  * define-normal-insn-enum (see define-normal-insn-enum)

  * define-normal-ifield (see define-normal-ifield)

  * df (see df)

  * dnf (see dnf)

  * define-normal-multi-ifield (see define-normal-multi-ifield)

  * dnmf (see dnmf)

  * dsmf (see dsmf)

  * define-normal-hardware (see define-normal-hardware)

  * dnh (see dnh)

  * define-simple-hardware (see define-simple-hardware)

  * dsh (see dsh)

  * define-normal-operand (see define-normal-operand)

  * dno (see dno)

  * dnop (see dnop)

  * dndo

  * define-normal-insn (see define-normal-insn)

  * dni (see dni)

  * define-normal-macro-insn (see define-normal-macro-insn)

  * dnmi (see dnmi)

Names and comments
------------------

Most description entries have a few fields in common: name, comment, and attrs (for attributes).

The name and comment fields have a special property to help simplify writing description files.

The proper type for a name is a symbol and the proper type for a comment is string.  It is sometimes useful, however, to construct names and comments from a list of values.  To support this without forcing the description file writer to have to explicitly construct a name or comment from pieces, CGEN accepts a list as a valid name or comment field, and will (recursively) append each element automagically.  Each list must consist of symbols, strings, and numbers, or lists. CGEN will automagically convert the value to a symbol for a name field, and a string for a comment field.

Example:

     (define-insn (name (add 3))
                  (comment (("This is a" " comment")
                            " constructed as a list."))
                  ...)

The name of this instruction is ``add3'' and the comment is "This is a comment constructed as a list.".

Writing define-arch
-------------------

Various simple and architecture-wide common things like the name of the processor must be defined somewhere, so all of this stuff is put under define-arch.

This must be the first entry in the description file.

See Architecture variants, for details.

Here's an example from m32r.cpu:

     (define-arch
       (name m32r) ; name of cpu family
       (comment "Renesas M32R")
       (default-alignment aligned)
       (insn-lsb0? #f)
       (machs m32r m32rx m32r2)
       (isas m32r)
     )

Writing define-isa
------------------

There are two purposes to define-isa. The first is to specify parameters needed to decode instructions.

The second is to give the instruction set a name.  This is important for architectures like the ARM where one CPU can execute multiple instruction sets.

See Architecture variants, for details.

Here's an example from arm.cpu:

     (define-isa
       (name thumb)
       (comment "ARM Thumb instruction set (16 bit insns)")
       (base-insn-bitsize 16)
       (decode-assist (15 14 13 12 11 10 9 8))
       (setup-semantics (set-quiet (reg h-gr 15) (add pc 4)))
     )

Writing define-cpu
------------------

CPU families are an internal and artificial classification designed to collect processor variants that are sufficiently similar together under one roof for the simulator.  What is ``sufficiently similar'' is up to the programmer.  For example, if the only difference between two processor variants is that one has a few extra instructions, there's no point in treating them separately in the simulator.

When simulating the variant without the extra instructions, said instructions are marked as ``invalid''.  On the other hand, putting 32 and 64 bit variants of an architecture under one roof is problematic since the word size is different.  What ``under one roof'' means is left fuzzy for now, but basically the simulator engine has a collection of structures defining internal state, and ``CPU families'' minimize the number of copies of generated code that manipulate this state.

See Architecture variants, for details.

Here's an example from openrisc.cpu:

     (define-cpu
       ; CPU names must be distinct from the architecture name and machine names.
       ; The "b" suffix stands for "base" and is the convention.
       ; The "f" suffix stands for "family" and is the convention.
       (name openriscbf)
       (comment "OpenRISC base family")
       (endian big)
       (word-bitsize 32)
     )

Writing define-mach
-------------------

CGEN uses ``mach'' in the same sense that BFD uses ``mach''. ``Mach'', which is short for `machine', defines a variant of the architecture.

See Architecture variants, for details.

Here's an example from m32r.cpu:

     (define-mach
       (name m32rx)
       (comment "M32RX cpu")
       (cpu m32rxf)
     )

Writing define-model
--------------------

When describing a CPU, in any context, there is ``architecture'' and there is ``implementation''.  In CGEN parlance, a ``model'' is an implementation of a ``mach''.  Models specify pipeline and other performance related characteristics of the implementation.

Some architectures bring pipeline details up into the architecture (rather than making them an implementation detail).  It's not clear yet how to handle all the various possibilities so at present this is done on a case-by-case basis.  Maybe a straightforward solution will emerge.

See Model variants, for details.

Here's an example from arm.cpu:

     (define-model
       (name arm710)
       (comment "ARM 710 microprocessor")
       (mach arm7tdmi)
       (unit u-exec "Execution Unit" ()
     	1 1 ; issue done
     	() () () ())
     )

Writing define-hardware
-----------------------

The registers of the processor are specified with define-hardware.  Also, immediate constants and addresses are defined to be ``hardware''.  By convention, all hardware elements names are prefaced with h-.  This convention must be followed.

Pre-defined hardware elements are:

h-memory
     Normal CPU memory (A temporary simplifying assumption is to treat all memory identically.  Being able to specify various kinds of memory (e.g. on-chip RAM,ROM) is work-in-progress.)

h-sint
     signed integer

h-uint
     unsigned integer

h-addr
     an address

h-iaddr
     an instruction address

Where are floats you ask?  They'll be defined when the need arises.

The program counter is named h-pc and must be specified. It is not a builtin element as sometimes architectures need to modify its behaviour (in the get/set specs).

See Hardware elements, for details.

Here's an example from arm.cpu:

     (define-hardware
       (name h-gr)
       (comment "general registers")
       (attrs PROFILE CACHE-ADDR)
       (type register WI (16))
       (indices extern-keyword gr-names)
     )

Writing define-ifield
---------------------

Writing instruction field entries involves analyzing the instruction set and creating an entry for each field.  If a field has multiple purposes, one can create separate entries for each intended purpose.  The names should generally follow the names used by the architecture reference manual.

By convention, all instruction field names are prefaced with f-.  This convention must be followed.

CGEN tries to allow the use of the bit numbering as found in the architecture reference manual.  This minimizes transcription errors both when writing the .cpu file and later when communicating field info to people.

There are two key pieces of data that CGEN uses to organize field specification: the default insn word size (in bits), and whether bit number 0 is the LSB (least significant bit) or the MSB (most significant bit).

In the general case, fields are described with 4 numbers: word-offset, word-length, start, and length. All instruction fields live in exactly one word and must be contiguous. (This doesn't include fields like multi-ifields.) Non-contiguous fields are specified with ``multi-ifields'' which are fields built up out of several smaller typically disjoint fields. The size of the word depends on the context.  word-offset specifies the offset in bits from the start of the insn to the word containing the field, it must be a multiple of 8. word-length specifies the size in bits of the word containing the field, it also must be a multiple of 8. start specifies the position of the MSB of the field in the word. length specifies the size in bits of the field.

See Instruction fields, for details.

Example.

Suppose an ISA has instructions that are normally 16 bits, but has instructions that may take an additional 32 bit immediate and optionally an additional 16 bit immediate after that. Also suppose the ISA numbers the bits starting from the LSB.

default-insn-word-bitsize = 16, lsb0? = #t

An instruction with four 4 bit fields, one 32 bit immediate and one 16 bit immediate might be:

       +-----+-----+----+----+--------+--------+
       | op1 | op2 | r1 | r2 | simm32 | simm16 |
       +-----+-----+----+----+--------+--------+

                 word-offset  word-length  start  length
     f-op1:           0            16        15      4
     f-op2:           0            16        11      4
     f-r1:            0            16         7      4
     f-r2:            0            16         3      4
     f-simm32:       16            32        31     32
     f-simm16:       48            16        15     16

If lsb0? = #f, then the example becomes:

                 word-offset  word-length  start  length
     f-op1:           0            16         0      4
     f-op2:           0            16         4      4
     f-r1:            0            16         8      4
     f-r2:            0            16        12      4
     f-simm32:       16            32         0     32
     f-simm16:       48            16         0     16

Endianness for the purposes of this example is irrelevant. In the word containing op1,op2,r1,r2, op1 is in the most significant nibble and r2 is in the least significant nibble.

For a large number of cases specifying all four numbers is excessive. With careful redefinition of the starting bit number, one can get away with only specifying start,length. Imagine several words of the default insn word size laid out from the start of the insn.  On top of that lay the field.  Now pick the minimal set of words that are required to contain the field.  That is the ``word'' we use. The start value is basically computed by adding the offset of the first containing word to the starting bit of the field in the word.  It's slightly more complicated than that because lsb0? and the word's size must be taken into account.  This is best illustrated by rewriting the above example:

     lsb0? = #t

                 start  length
     f-op1:        15      4
     f-op2:        11      4
     f-r1:          7      4
     f-r2:          3      4
     f-simm32:     47     32
     f-simm16:     63     16

     lsb0? = #f

                 start  length
     f-op1:         0      4
     f-op2:         4      4
     f-r1:          8      4
     f-r2:         12      4
     f-simm32:     16     32
     f-simm16:     48     16

Note: This simpler definition doesn't work in all cases.  Where it doesn't the full-blown definition must be used.

There are currently no shorthand macros for specifying the full-blown definition.  It is recommended that if you have to use one that you write a macro to reduce typing.

Written out the full blown way, the f-op1 field would be specified as:

     (define-ifield
       (name f-op1)
       (comment "f-op1")
       (attrs) ; no attributes, could be elided if one wants
       (word-offset 0)
       (word-length 16)
       (start 15)
       (length 4)
       (mode UINT)
       (encode #f) ; no special encoding, could be elided if one wants
       (decode #f) ; no special encoding, could be elided if one wants
     )

A macro to simplify that could be written as:

     ; dwf: define-word-field (??? pick a better name)

     (define-pmacro (dwf x-name x-comment x-attrs
                         x-word-offset x-word-length x-start x-length
                         x-mode x-encode x-decode)
       "Define a field including its containing word."
       (define-ifield
         (name x-name)
         (comment x-comment)
         (.splice attrs (.unsplice x-attrs))
         (word-offset x-word-offset)
         (word-length x-word-length)
         (start x-start)
         (length x-length)
         (mode x-mode)
         (.splice encode (.unsplice x-encode))
         (.splice decode (.unsplice x-decode))
         )
     )

The .splice is necessary because attrs, encode, and decode take a list as an argument.

One would then write f-op1 as:

     (dwf f-op1 "f-op1" () 0 16 15 4 UINT #f #f)

Writing define-normal-insn-enum
-------------------------------

Writing instruction enum entries involves analyzing the instruction set and attaching names to the opcode fields.  For example, if a field named op1 is used to select which of add, addc, sub, subc, and, or, xor, and inv instructions, one could write something like the following:

     (define-normal-insn-enum
       insn-op1 "insn format enums" () f-op1 OP1_
       (ADD ADDC SUB SUBC
        AND OR   XOR INV)
     )

These entries simplify instruction definitions by giving a name to a particular value for a particular instruction field.  By convention, enum names are uppercase.  This convention must be followed.

See Enumerated constants, for details.

Writing define-operand
----------------------

Operands are what instruction semantics use to refer to hardware elements.  The typical use of an operand is to map instruction fields to hardware.  For example, if field f-r2 is used to specify one of the registers defined by the h-gr hardware entry, one could write something like the following:

(dnop sr "source register" () h-gr f-r2)

dnop is short for ``define normal operand''  (A profound aversion to typing causes me to often provide brief names of things that get typed a lot.).

See Instruction operands, for more information.

Writing define-insn
-------------------

A large part of writing a .cpu file is going through the CPU manual and writing an entry for each instruction. Instructions specific to a particular machine variant are indicated so with the `MACH' attribute.  Example:

     (define-normal-insn
       add "add instruction"
       ((MACH mach1)) ; or (MACH mach1,mach2,...) for multiple variants
       ...
     )

The `base' machine is a predefined machine variant that includes instructions available to all variants, and is the default if no `MACH' attribute is specified.

See Instructions, for details.

When the .cpu file is processed, CGEN will analyze the semantics to determine:

  * input operands

     The list of hardware elements read by the instruction.

  * output operands

     The list of hardware elements written by the instruction.

  * attributes

     Instruction attributes that can be computed from the semantics.

     CTI: control transfer instruction, generally a branch.

       * UNCOND-CTI

          The instruction unconditionally sets pc.

       * COND-CTI

          The instruction conditionally sets pc.

       * SKIP-CTI

          NB. This is an experimental attribute.  Its usage needs to evolve.

       * DELAY-SLOT

          NB. This is an experimental attribute.  Its usage needs to evolve.

CGEN will also try to simplify the semantics as much as possible:

  * Constant folding

     Expressions involving constants are simplified and any resulting non-taken paths of conditional expressions are discarded.

Writing define-macro-insn
-------------------------

Some instructions are really aliases for other instructions, maybe even a sequence of them.  For example, an architecture that has a general decrement-then-store instruction might have a specialized version of this instruction called push supported by the assembler.  These are handled with ``macro instructions''.

See Macro-instructions, for details.

Macro instructions are used by the assembler/disassembler only. They are not used by the simulator.

For example, if this was the real instruction:

     (dni st-minus "st-" ()
          "st $src1,$src2"
          (+ OP1_2 OP2_7 src1 src2)
          (sequence ((WI new-src2))
     	       (set new-src2 (sub src2 (const 4)))
     	       (set (mem WI new-src2) src1)
     	       (set src2 new-src2))
          ()
     )

One could write a push variant with:

     (dnmi push "push" ()
       "push $src1"
       (emit st-minus src1 (src2 15)) ; "st %0,sp"
     )

Using define-pmacro
-------------------

When a group of entries, say instructions, share similar information, a macro (in the C preprocessor sense) can be used to simplify the description.  This can be used to save a lot of typing, which can also improve readability since often one page of code is easier to understand than four.

See Preprocessor macros, for details.

Here is an example from the M32R port.

     (define-pmacro (bin-op mnemonic op2-op sem-op imm-prefix imm)
       (begin
          (dni mnemonic
     	  (.str mnemonic " reg/reg")
     	  ()
     	  (.str mnemonic " $dr,$sr")
     	  (+ OP1_0 op2-op dr sr)
     	  (set dr (sem-op dr sr))
     	  ()
          )
          (dni (.sym mnemonic "3")
     	  (.str mnemonic " reg/" imm)
     	  ()
     	  (.str mnemonic "3 $dr,$sr," imm-prefix "$" imm)
     	  (+ OP1_8 op2-op dr sr imm)
     	  (set dr (sem-op sr imm))
     	  ()
          )
        )
     )
     (bin-op add OP2_10 add "$hash" slo16)
     (bin-op and OP2_12 and ""      uimm16)
     (bin-op or  OP2_14 or  "$hash" ulo16)
     (bin-op xor OP2_13 xor ""      uimm16)

.sym/.str are short for Scheme's symbol-append and string-append operations and are conceptually the same as the C preprocessor's ## concatenation operator.  See Symbol concatenation, and see String concatenation, for details.

Splicing arguments
------------------

Several cpu description elements take a list as an argument (as opposed to a scalar). When constructing a call to define-* in a pmacro, these elements must have their arguments spliced in to achieve the proper syntax.

This is best explained with an example. Here's a simplifying macro for writing ifield definitions with every element specified.

See List splicing, for details.

     ; dwf: define-word-field

     (define-pmacro (dwf x-name x-comment x-attrs
                         x-word-offset x-word-length x-start x-length
                         x-mode x-encode x-decode)
       "Define a field including its containing word."
       (define-ifield
         (name x-name)
         (comment x-comment)
         (.splice attrs (.unsplice x-attrs))
         (word-offset x-word-offset)
         (word-length x-word-length)
         (start x-start)
         (length x-length)
         (mode x-mode)
         (.splice encode (.unsplice x-encode))
         (.splice decode (.unsplice x-decode))
         )
     )

The .splice is necessary because attrs, encode, and decode take a list as an argument.

One would then write f-op1 as:

     (dwf f-op1 "f-op1" () 0 16 15 4 UINT #f #f)

Interactive development
-----------------------

The normal way (Normal for some anyway, certainly each person will have their own preference.) of writing a CPU description file involves starting Guile and developing the .CPU file interactively.  The basic steps are:

 1. Run guile.

 2. (load "dev.scm")

 3. Load application, e.g. (load-opc) or (load-sim)

 4. Load CPU description file, e.g. (cload #:arch "cpu/m32r.cpu")

 5. Run generators until output looks reasonable, e.g. (cgen-opc.c)

To assist in the development process and to cut down on some typing, dev.scm looks for $HOME/.cgenrc and, if present, loads it. Typical things that .cgenrc contains are definitions of procedures that combine steps 3 and 4 above.

Example:

     (define (m32r-opc)
       (load-opc)
       (cload #:arch "cpu/m32r.cpu")
     )
     (define (m32r-sim)
       (load-sim)
       (cload #:arch "cpu/m32r.cpu" #:options "with-scache with-profile=fn")
     )
     (define (m32rbf-sim)
       (load-sim)
       (cload #:arch "cpu/m32r.cpu" #:machs "m32r" #:options "with-scache with-profile=fn")
     )
     (define (m32rxf-sim)
       (load-sim)
       (cload #:arch "cpu/m32r.cpu" #:machs "m32rx" #:options "with-scache with-profile=fn")
     )

CPU description files are loaded into an interactive guile session with cload.  The syntax is:

     (cload #:arch "cpu-file-path"
            [#:machs "mach-list"]
            [#:isas "isa-list"]
            [#:options "option-list"])

Only the #:arch argument is mandatory.

cpu-file is the path to the .cpu file.

mach-list is a comma separated string of machines to keep.

isa-list is a comma separated string of isas to keep.

options is a space separated string of options for the application.

Doing an opcodes port
=====================

The best way to begin a port is to take an existing one (preferably one that is similar to the new port) and use it as a template.

 1. Run guile.

 2. (load "dev.scm"). This loads in a set of interactive development routines.

 3. (load-opc). Load the opcodes support.

 4. Edit your cpu/<arch>.cpu and cpu/<arch>.opc files.

       * The .cpu file is the main description file.

       * The .opc file provides additional C support code.

 5. (cload #:arch "cpu/<arch>.cpu")

 6. Run each of:

       * (cgen-desc.h)

       * (cgen-desc.c)

       * (cgen-opc.h)

       * (cgen-opc.c)

       * (cgen-ibld.in)

       * (cgen-asm.in)

       * (cgen-dis.in)

       * (cgen-opinst.c) -- [optional]

 7. Repeat steps 4, 5 and 6 until the output looks reasonable.

 8. Add dependencies to opcodes/Makefile.am to generate the eight opcodes files (use the M32R port as an example).

 9. Run make dep from the opcodes build directory.

 10. Run make all-opcodes from the top level build directory.

Doing a GAS port
================

A GAS CGEN port is essentially no different than a normal port except that the CGEN opcode table is used, and there are extra supporting routines available in gas/cgen.[ch].  As always, a good way to get started is to take the M32R port as a template and go from there.

The important CGEN-specific things to keep in mind are:

  * Several support routines are provided by gas/cgen.c.  Some must be used, others are available to use if you want to (in general they should be used unless it's not possible).

       * gas_cgen_init_parse

            - Call from md_assemble before doing anything else.

            - Must be used.

       * gas_cgen_record_fixup

            - Cover function to fix_new.

       * gas_cgen_record_fixup_exp

            - Cover function to fix_new_exp.

       * gas_cgen_parse_operand

            - Callback for opcode table based parser, set in md_begin.

       * gas_cgen_finish_insn

            - After parsing an instruction, call this to add the instruction to the frag and queue any fixups.

       * gas_cgen_md_apply_fix

            - Provides basic md_apply_fix support.

            - #define md_apply_fix gas_cgen_md_apply_fix if you're able to use it.

       * gas_cgen_tc_gen_reloc

            - Provides basic tc_gen_reloc support in function.

            - #define tc_gen_reloc gas_cgen_tc_gen_reloc if you're able to use it.

  * md_begin should contain the following (plus anything else you want of course):

            /* Set the machine number and endianness.  */
            gas_cgen_opcode_desc =
              <arch>_cgen_cpu_open (CGEN_CPU_OPEN_MACHS,
                                    0 /* mach number */,
                                    CGEN_CPU_OPEN_ENDIAN,
                                    (target_big_endian
                                      ? CGEN_ENDIAN_BIG
                                      : CGEN_ENDIAN_LITTLE),
                                    CGEN_CPU_OPEN_END);

            <arch>_cgen_init_asm (gas_cgen_opcode_desc);

            /* This is a callback from cgen to gas to parse operands.  */
            cgen_set_parse_operand_fn (gas_cgen_opcode_desc, gas_cgen_parse_operand);

  * md_assemble should contain the following basic framework:

          {
            const CGEN_INSN *insn;
            char *errmsg;
            CGEN_FIELDS fields;
          #if CGEN_INT_INSN_P
            cgen_insn_t buffer[CGEN_MAX_INSN_SIZE / sizeof (CGEN_INSN_INT)];
          #else
            char buffer[CGEN_MAX_INSN_SIZE];
          #endif

            gas_cgen_init_parse ();

            insn = m32r_cgen_assemble_insn (gas_cgen_opcode_desc, str,
                                            &fields, buffer, &errmsg);

            if (! insn)
              {
                as_bad (errmsg);
                return;
              }

            gas_cgen_finish_insn (insn, buffer, CGEN_FIELDS_BITSIZE (&fields),
               relax_p, /* non-zero to allow relaxable insns */
               result); /* non-null if results needed for later */
          }

Building a GAS test suite
=========================

CGEN can also build the template for test cases for all instructions.  In some cases it can also generate the actual instructions.  The result is then assembled, disassembled, verified, and checked into CVS.  Further changes are usually done by hand as it's easier.  The goal here is to save the enormous amount of initial typing that is required.

 1. cd to the CGEN build directory

 2. make gas-test

     At this point two files have been created in the CGEN build directory: gas-allinsn.exp and gas-build.sh.  The gas-build.sh script normally requires one command line argument: the location of your gas build directory.  If this argument is omitted, the script searches in ../gas automatically.

 3. Copy gas-allinsn.exp to toplevel/gas/testsuite/gas/<arch>/allinsn.exp.

 4. sh gas-build.sh

     At this point directory tmpdir contains two files: allinsn.s and allinsn.d.  File allinsn.d usually needs a bit of massaging.

 5. Copy tmpdir/allinsn.[sd] to toplevel/gas/testsuite/gas/<arch>

 6. Run make check in the gas build directory and massage things until you're satisfied the files are correct.

 7. Check files into CVS.

At this point further additions/modifications are usually done by hand.

Doing a simulator port
======================

The same basic procedure for opcodes porting applies here.

 1. Run guile.

 2. (load "dev.scm")

 3. (load-sim)

 4. Edit your cpu/<arch>.cpu file.

 5. (cload #:arch "cpu/<arch>.cpu")

 6. Run each of:

       * (cgen-arch.h)

       * (cgen-arch.c)

       * (cgen-cpuall.h)

 7. Repeat steps 4,5,6 until the output looks reasonable.

 8. Edit your cpu/<arch>.cpu file.

 9. (cload #:arch "cpu/<arch>.cpu" #:machs "mach1[,mach2[,...]]")

 10. Run each of:

       * (cgen-cpu.h)

       * (cgen-cpu.c)

       * (cgen-decode.h)

       * (cgen-decode.c)

       * (cgen-semantics.c)

       * (cgen-sem-switch.c) -- only if using a switch() version of semantics.

       * (cgen-model.c)

 11. Repeat steps 8, 9 and 10 until the output looks reasonable.

The following additional files are also needed. These live in the sim/<arch> directory. Administrivia files like configure.in and Makefile.in are omitted.

  * sim-main.h

     Main include file required by the ``common'' (sim/common) support, and by each target's .c file. This file includes the relevant other headers. The order is fairly important. m32r/sim-main.h is a good starting point.

     sim-main.h also defines several types:

       - _sim_cpu -- a struct containing all state for a particular CPU.

       - sim_state -- contains all state of the simulator. A SIM_DESC (which is the result of sim_open and is akin to a file descriptor) points to one of these.

       - sim_cia -- type of an instruction address.  For CGEN this is generally ``word mode'', in GCC parlance.

     sim-main.h also defines several macros:

       - CIA_GET(cpu) -- return ``cia'' of the CPU

       - CIA_SET(cpu,cia) -- set the ``cia'' of the CPU

     ``cia'' is short for "current instruction address".

     The definition of sim_state is fairly simple.  Just copy the M32R case.  The definition of _sim_cpu is not simple, so pay attention.  The complexity comes from trying to create a ``derived class'' of sim_cpu for each CPU family.  What is done is define a different version of sim_cpu in each CPU family's set of files, with a common ``base class'' structure ``leading part'' for each sim_cpu definition used by non-CPU-family specific files.  The way this is done is by defining WANT_CPU_<CPU-FAMILY-NAME> at the top of CPU family specific files. The definition of _sim_cpu is then:

          	struct _sim_cpu {
          	  /* sim/common CPU base */
          	  sim_cpu_base base;
          	  /* Static parts of CGEN.  */
          	  CGEN_CPU cgen_CPU;
          	#if defined (WANT_CPU_CPUFAM1)
          	  CPUFAM1_CPU_DATA CPU_data;
          	#elif defined (WANT_CPU_CPUFAM2)
          	  CPUFAM2_CPU_DATA CPU_data;
          	#endif
          	};

  * tconfig.in

     This file predates sim-main.h and was/is intended to contain macros that configure the simulator sources.

       * SIM_HAVE_MODEL -- enable common/sim-model.[ch] support.

       * SIM_HANDLES_LMA -- makes sim-hload.c do the right thing.

       * WITH_SCACHE_PBB -- define this to 1 if using pbb scaching.

  * <arch>-sim.h

     This file predates sim-main.h and contains miscellaneous macros and definitions used by the simulator.

  * mloop.in

     This file contains code to implement the fetch/execute process.  There are various ways to do this, and several are supported.  Which one to choose depends on the environment in which the CPU will be used.  For example when executing a program in a single-CPU environment without devices, most or all available cycles can be devoted to simulation of the target CPU.  However, in an environment with devices or multiple cpus, one may wish the CPU to execute one instruction then relinquish control so a device operation may be done or an instruction can be simulated on a second cpu.  Efficient techniques for the former aren't necessarily the best for the latter.

     Three versions are currently supported:

      1. simple -- fetch/decode/execute one insn

      2. scache -- same as simple but results of decoding are cached

      3. pbb -- same as scache but several insns are handled each iteration pbb stands for pseudo basic block.

     This file is processed by common/genmloop.sh at build time. The result is two files: mloop.c and eng.h.

  * sim-if.c

     By convention this file contains sim_open, sim_close, sim_create_inferior, sim_do_command.  These functions can live in any file of course.  They're here because they're the parts of the remote-sim.h interface that aren't provided by the common directory.

  * <cpufam>.c

     By convention this file contains register access and model support functions for a CPU family (the name of this file is misnamed in the M32R case).  The register access functions implement the sim_fetch_register and sim_store_register interface functions (named <cpufam>_{fetch,store}_register), and support code for register get/set rtl.  The model support functions implement the before/after handlers (functions that handle tracing/profiling) and timing for each function unit.

  * Other files

     The M32R port has two other handwritten files: devices.c and traps.c.  How you wish to organize this is up to you.

Building a simulator test suite
===============================

CGEN can also build the template for test cases for all instructions.  In some cases it can also generate the actual instructions (Although this hasn't been implemented yet.).  The result is then verified and checked into CVS.  Further changes are usually done by hand as it's easier.  The goal here is to save the enormous amount of initial typing that is required.

 1. cd to the CGEN build directory

 2. make sim-test ISA=<arch>

     At this point two files have been created in the CGEN build directory: sim-allinsn.exp and sim-build.sh.

 3. Copy sim-allinsn.exp to toplevel/sim/testsuite/sim/<arch>/allinsn.exp.

 4. sh sim-build.sh

     At this point a new subdirectory called tmpdir will be created and will contain one test case for each instruction.  The framework has been filled in but not the actual test case.  It's handy to write an ``include file'' containing assembler macros that simplify writing test cases.  See toplevel/sim/testsuite/sim/m32r/testutils.inc for an example.

 5. write testutils.inc

 6. finish each test case

 7. copy tmpdir/*.cgs to toplevel/sim/testsuite/sim/<arch>

 8. run make check in the sim build directory and massage things until you're satisfied the files are correct

 9. Check files into CVS.

At this point further additions/modifications are usually done by hand.