Target description

Target module

Each target must be described by a Python module and must be accessible in one of the target directories specified on the command-line.

The target module gap9/evk.py wich can be found in the targets inside Gapy can be looked at as an example:

class Target(gapylib.chips.gap.gap9_v2.target.Target):

    def __init__(self, options: list):
        super().__init__(options)

        self.register_flash(
            gapylib.chips.gap.flash.DefaultFlashRomV2(self, 'flash',
                flash_atributes={
                    "flash_type": "spi",
                    "rtl_stim_format": "slm_16",
                    "rtl_stim_name": "slm_files/flash_stim.slm",
                    "flasher": "gap_flasher-gap9_evk.elf",
                    "flasher_sector_size": 0x2000,
                    "littlefs_block_size": 262144,
                },
                size=8*1024*1024
        ))
        self.register_flash(
            gapylib.chips.gap.flash.DefaultFlashRomV2(self, 'mram',
                flash_atributes={
                    "flash_type": "mram",
                    "rtl_stim_format": "mram",
                    "rtl_stim_name": "slm_files/mram_stim.slm",
                    "flasher": "gap_flasher-gap9_evk-mram.elf",
                    "flasher_sector_size": 0x2000,
                    "littlefs_block_size": 262144,
                },
                size=2*1024*1024
        ))

    def __str__(self) -> str:
        return "GAP9 evaluation kit"

Any target descriptor must inherit from gapylib.target.Target. This example inherits first from a common gap9 descriptor which itself inherits from gapylib.target.Target.

The descriptor should return the target name when it is converted to string, using the method __str__.

The descriptor can then optionnally overload some methods of the base class in order to add some custom behaviors.

The most useful one is to overload the method gapylib.target.Target.append_args() in order to specify additionnal command-line options, like in this example:

def append_args(self, parser: argparse.ArgumentParser):
    super().append_args(parser)

    [args, _] = parser.parse_known_args()

    if args.platform == 'board':
        self.runner = gapylib.chips.gap.gap9_v2.board_runner.Runner(self)

    else:
        raise RuntimeError('Unknown platform: ' + args.platform)

    self.runner.append_args(parser)

This method gets an argparse parser as argument, which can be used to add target-specific arguments. It can also be used to immediately parse arguments in order to check the value of the added arguments.

Another useful method to overload is gapylib.target.Target.handle_command() which allows defining target-specific commands, like in this example:

def handle_command(self, cmd: str):

    args = self.get_args()

    if cmd == 'run':
        self.runner.run()

    elif cmd == 'traces':
        if args.platform == 'rtl':
            self.runner.traces()

    elif cmd == 'flash':
        gapylib.target.Target.handle_command(self, cmd)

        # board platform needs to upload flash content
        if args.platform == 'board':
            self.runner.flash()

    else:
        gapylib.target.Target.handle_command(self, cmd)

As seen on this example, this can be used either to add a command or also to change the behavior of an existing command.

Flash registration

Another goal of the target descriptor is to declare the available flashes and their layout in order to let Gapy manage them.

As we can see on the previous example, this is done by calling the method gapylib.target.Target.register_flash():

class Target(gapylib.chips.gap.gap9_v2.target.Target):

    def __init__(self, options: list):
        super().__init__(options)

        self.register_flash(
            gapylib.chips.gap.flash.DefaultFlashRomV2(self, 'flash',
                flash_info={
                    "flash_type": "spi",
                    "rtl_stim_format": "slm_16",
                    "rtl_stim_name": "slm_files/flash_stim.slm",
                    "flasher": "gap_flasher-gap9_evk.elf",
                    "flasher_sector_size": 0x2000,
                    "littlefs_block_size": 262144,
                },
                size=8*1024*1024
        ))

This method takes as argument the flash instance, whose class must derive from gapylib.flash.Flash.

This class must be instantiated with as arguments, the flash name, the flash size and optionnally some flash attributes.

The flash name is the name which is used everywhere to refer to this flash, like on the command-line to set flash section properties.

The flash size is used to check that the flash is not overflowed and can also be used by some sections like the raw section in gapylib.fs.raw.RawSection which is using it to spread until the end of the flash.

The flash attributes given to the instance can be used to store information about the flash, which can then be used by the target to understand how the flash should be handled. This is used for example on the board to get some information about the way the flasher should update the content of the flash.

The class gapylib.chips.gap.flash.DefaultFlashRomV2 is derived from the base class gapylib.flash.Flash and is adding some information about the allowed sections and default flash layout. More information can be found in the sections about flash management and about gap targets.

Overriding properties

Every properties describes in flash registration can be overriden via --flash-property-override=VALUE@FLASH:PROPERTY_NAME switch. As an example one may override the flasher path as so:

# overide mram's flasher path with a flasher in the user's home directory
export runner_args="--flash-property-override=$HOME/flasher_mram.elf@mram:flasher"
# run with cmake
cmake --build build --target run
# or with make
make all run