Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/* Subroutines for the gcc driver.
   Copyright (C) 2015-2020 Free Software Foundation, Inc.
   Contributed by Georg-Johann Lay <avr@gjlay.de>

   This file is part of GCC.

   GCC is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3, or (at your option)
   any later version.

   GCC is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with GCC; see the file COPYING3.  If not see
   <http://www.gnu.org/licenses/>.  */

#define IN_TARGET_CODE 1

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
#include "tm.h"
#include "msp430-devices.h"

/* This spec function is called if the user has provided an -mmcu option without
   an -mcpu option.  It will place the correct -mcpu option for the given -mmcu
   onto the command line, to ensure the correct ISA multilib is selected.  */
const char *
msp430_select_cpu (int argc, const char ** argv)
{
  if (argc == 0)
    {
      error ("expected an argument to %<msp430_select_cpu%>");
      return NULL;
    }
  msp430_extract_mcu_data (argv[0]);
  if (extracted_mcu_data.name != NULL)
    {
      switch (extracted_mcu_data.revision)
	{
	case 0: return "-mcpu=msp430";
	case 1: return "-mcpu=msp430x";
	case 2: return "-mcpu=msp430xv2";
	default:
	  gcc_unreachable ();
	}
    }
  /* MCU wasn't found, the compiler proper will warn about this.  */
  return NULL;
}

/* Spec function to set a global variable to a specific value in the driver.
   The first argument is the variable name, and the second is the value to set
   it to.
   Currently only "msp430_warn_devices_csv" and "msp430_devices_csv_loc" are
   supported.
   The intention is that we can take a "Target" option and set the variable
   associated with it in the driver as well.  Whilst the driver sees "Target"
   options, it does not set the variables associated with that option.  */
const char *
msp430_set_driver_var (int argc, const char ** argv)
{
  if (argc != 2)
    error ("%<msp430_set_driver_var%> expects 2 arguments");
  else if (strcmp (argv[0], "msp430_warn_devices_csv") == 0)
    msp430_warn_devices_csv = atoi (argv[1]);
  else if (strcmp (argv[0], "msp430_devices_csv_loc") == 0)
    msp430_devices_csv_loc = argv[1];
  else
    error ("unhandled arguments %qs and %qs to %<msp430_set_driver_var%>",
	   argv[0], argv[1]);
  return NULL;
}

/* Implement spec function `msp430_hwmult_libĀ“.  */

const char *
msp430_select_hwmult_lib (int argc ATTRIBUTE_UNUSED,
			  const char ** argv ATTRIBUTE_UNUSED)
{
  int i;

  switch (argc)
    {
    case 1:
      if (strcasecmp (argv[0], "default"))
	error ("unexpected argument to msp430_select_hwmult_lib: %s", argv[0]);
      break;

    default:
      /* We can get three or more arguments passed to this function.
	 This happens when the same option is repeated on the command line.
	 For example:
	 msp430-elf-gcc -mhwmult=none -mhwmult=16bit foo.c
	 We have to use the last argument as our selector.  */
      if (strcasecmp (argv[0], "hwmult") == 0)
	{
	  static struct hwmult_options
	    {
	      const char * name;
	      const char * lib;
	    } hwmult_options[] =
	    {
	      { "none", "-lmul_none" },
	      { "auto", "-lmul_AUTO" }, /* Should not see this one... */
	      { "16bit", "-lmul_16" },
	      { "32bit", "-lmul_32" },
	      { "f5series", "-lmul_f5" }
	    };

	for (i = ARRAY_SIZE (hwmult_options); i--;)
	  if (strcasecmp (argv[argc - 1], hwmult_options[i].name) == 0)
	    return hwmult_options[i].lib;
	}
      else if (strcasecmp (argv[0], "mcu") == 0)
	{
	  msp430_extract_mcu_data (argv[argc - 1]);
	  if (extracted_mcu_data.name != NULL)
	    {
	      switch (extracted_mcu_data.hwmpy)
		{
		case 0: return "-lmul_none";
		case 2:
		case 1: return "-lmul_16";
		case 4: return "-lmul_32";
		case 8: return "-lmul_f5";
		default:
		  /* We have already checked the hwmpy values for
		     validity in msp430_extract_mcu_data.  */
		  gcc_unreachable ();
		  break;
		}
	    }
	}
      else
	error ("unexpected first argument to msp430_select_hwmult_lib: %s",
	       argv[0]);
      break;

    case 0:
      error ("msp430_select_hwmult_lib needs one or more arguments");
      break;
    }

  return "-lmul_none";
}

/* Spec function.  Used to place the path to the MSP430-GCC support files
   on the command line, prefixed with "-L", so the linker finds the linker
   scripts in that directory.  */
const char *
msp430_get_linker_devices_include_path (int argc ATTRIBUTE_UNUSED,
					const char **argv ATTRIBUTE_UNUSED)
{
  char *devices_csv_path;
  if (msp430_check_env_var_for_devices (&devices_csv_path))
    return NULL;
  return concat ("-L", msp430_dirname (devices_csv_path), NULL);
}

/* Spec function.  Propagate -m{code,data}-region= to the linker, unless the
   lower region has been specified without -muse-lower-region-prefix also being
   used.  */
const char *
msp430_propagate_region_opt (int argc, const char **argv)
{
  if (strcmp (argv[0], "lower") != 0)
    return argv[0];
  else if ((argc == 2) && (strcmp (argv[1], "-muse-lower-region-prefix") == 0))
    return argv[0]; /* argv[0] == "lower".  */
  return "none";
}