MSP430: Add new methods of finding external MCU data file
authorJozef Lawrynowicz <jozef.l@mittosystems.com>
Mon, 4 Nov 2019 11:01:03 +0000 (11:01 +0000)
committerJozef Lawrynowicz <jozefl@gcc.gnu.org>
Mon, 4 Nov 2019 11:01:03 +0000 (11:01 +0000)
MCU data file can now be specified with an environment variable or installed
into a toolchain subdirectory.

2019-11-04  Jozef Lawrynowicz  <jozef.l@mittosystems.com>

gcc/
* config/msp430/driver-msp430.c
(msp430_get_linker_devices_include_path): New spec function.
* config/msp430/msp430-devices.c (msp430_dirname): New function.
(extract_devices_dir_from_exec_prefix): New function.
(extract_devices_dir_from_collect_gcc): New function.
(msp430_check_env_var_for_devices): New function.
(msp430_check_path_for_devices): Use xstrdup instead of ASTRDUP.
(parse_devices_csv): Call msp430_check_env_var_for_devices if
devices.csv was not found using other methods.
* config/msp430/msp430-devices.h (msp430_check_env_var_for_devices):
New prototype.
(msp430_dirname): Likewise.
* config/msp430/msp430.c (msp430_register_pre_includes): New function.
* config/msp430/msp430.h (EXTRA_SPEC_FUNCTIONS): Add
msp430_get_linker_devices_include_path.
(TARGET_EXTRA_PRE_INCLUDES): Define.
* doc/invoke.texi: Document new ways of searching for support files.

gcc/testsuite/
* gcc.target/msp430/devices/csv-using-env-var.c: New test.
* gcc.target/msp430/devices/csv-using-installed.c: New test.
* gcc.target/msp430/devices/csv-using-option.c: New test.
* gcc.target/msp430/devices/devices-main.c: New test source file.
* gcc.target/msp430/devices/msp430-devices.h: New test.
* gcc.target/msp430/msp430.exp (msp430_device_permutations_runtest):
Add special cases for csv-using* tests.
Define TESTING_HARD_DATA when running tests that use hard-coded device
data.
(get_installed_device_data_path): New.
(msp430_hide_installed_devices_data): New.
(msp430_restore_installed_devices_data): New.
(msp430_test_installed_device_data): New.
(msp430_install_device_data): New.

From-SVN: r277772

14 files changed:
gcc/ChangeLog
gcc/config/msp430/driver-msp430.c
gcc/config/msp430/msp430-devices.c
gcc/config/msp430/msp430-devices.h
gcc/config/msp430/msp430.c
gcc/config/msp430/msp430.h
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/msp430/devices/csv-using-env-var.c [new file with mode: 0644]
gcc/testsuite/gcc.target/msp430/devices/csv-using-installed.c [new file with mode: 0644]
gcc/testsuite/gcc.target/msp430/devices/csv-using-option.c [new file with mode: 0644]
gcc/testsuite/gcc.target/msp430/devices/devices-main.c
gcc/testsuite/gcc.target/msp430/devices/msp430-devices.h [new file with mode: 0644]
gcc/testsuite/gcc.target/msp430/msp430.exp

index 5807a69b9adc42f356226636d192dbd6f3789ea4..c1c6d335d04c88d187f0adb6dbfc784a08fa405a 100644 (file)
@@ -1,3 +1,23 @@
+2019-11-04  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * config/msp430/driver-msp430.c
+       (msp430_get_linker_devices_include_path): New spec function.
+       * config/msp430/msp430-devices.c (msp430_dirname): New function.
+       (extract_devices_dir_from_exec_prefix): New function.
+       (extract_devices_dir_from_collect_gcc): New function.
+       (msp430_check_env_var_for_devices): New function.
+       (msp430_check_path_for_devices): Use xstrdup instead of ASTRDUP.
+       (parse_devices_csv): Call msp430_check_env_var_for_devices if
+       devices.csv was not found using other methods.
+       * config/msp430/msp430-devices.h (msp430_check_env_var_for_devices):
+       New prototype.
+       (msp430_dirname): Likewise.
+       * config/msp430/msp430.c (msp430_register_pre_includes): New function.
+       * config/msp430/msp430.h (EXTRA_SPEC_FUNCTIONS): Add
+       msp430_get_linker_devices_include_path.
+       (TARGET_EXTRA_PRE_INCLUDES): Define.
+       * doc/invoke.texi: Document new ways of searching for support files.
+
 2019-11-04  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/92301
index c37b169ff8b27510a17003d19370ff22a5e61f38..fbe7c44ea3740892e5679fc4ab99fd9a7448fa0e 100644 (file)
@@ -150,6 +150,19 @@ msp430_select_hwmult_lib (int argc ATTRIBUTE_UNUSED,
   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.  */
index 537d438ea3b60b33eb982e5ff9c93c82f0bb774a..600a111b51726b2b8d0ae9478e6341eda7aee409 100644 (file)
@@ -37,7 +37,7 @@ extern struct t_msp430_mcu_data hard_msp430_mcu_data[605];
 
 /* Set to the full path to devices.csv if it is found by searching the -I and
    -L paths.  */
-char * derived_devices_csv_loc = NULL;
+char *derived_devices_csv_loc = NULL;
 
 /* This is to canonicalize the directory separators in the path.
    On Windows we could have a mix of '/' and '\' in the path.  */
@@ -52,6 +52,128 @@ canonicalize_path_dirsep (char **path)
       t_path[i] = DIR_SEPARATOR;
 }
 
+/* This function returns the enclosing directory of PATH.
+   It is inconsequential whether PATH ends in a dirsep or not.
+   It modifies the string pointed to by PATH.  */
+char *
+msp430_dirname (char *path)
+{
+  int last_elem = strlen (path) - 1;
+  int i = last_elem - (IS_DIR_SEPARATOR (path[last_elem]) ? 1 : 0);
+  for (; i >= 0; i--)
+    {
+      if (IS_DIR_SEPARATOR (path[i]))
+       {
+         path[i] = '\0';
+         return path;
+       }
+    }
+  return path;
+}
+
+/* devices.csv path from the toolchain root.  */
+static const char rest_of_devices_path[] = "/msp430-elf/include/devices/";
+
+/* "The default value of GCC_EXEC_PREFIX is prefix/lib/gcc". Strip lib/gcc
+   from GCC_EXEC_PREFIX to get the path to the installed toolchain.  */
+static void
+extract_devices_dir_from_exec_prefix (char **devices_loc)
+{
+  const char *temp;
+  char *gcc_exec_prefix = *devices_loc;
+  int len = strlen (gcc_exec_prefix);
+
+  /* Copied from gcc.c.  */
+  if (len > (int) sizeof ("/lib/gcc/") - 1
+      && (IS_DIR_SEPARATOR (gcc_exec_prefix[len-1])))
+    {
+      temp = gcc_exec_prefix + len - sizeof ("/lib/gcc/") + 1;
+      if (IS_DIR_SEPARATOR (*temp)
+         && filename_ncmp (temp + 1, "lib", 3) == 0
+         && IS_DIR_SEPARATOR (temp[4])
+         && filename_ncmp (temp + 5, "gcc", 3) == 0)
+       {
+         len -= sizeof ("/lib/gcc/") - 1;
+         /* Keep the '/' from the beginning of /lib/gcc.  */
+         gcc_exec_prefix[len + 1] = (char) 0;
+         *devices_loc = concat (gcc_exec_prefix, rest_of_devices_path, NULL);
+         return;
+       }
+    }
+}
+
+/* Given the path to the GCC executable, return the path to the installed
+   device data in "$TOOLCHAIN_ROOT/msp430-elf/include/devices".
+   Assumes the GCC executable is in "$TOOLCHAIN_ROOT/<somedir>/".  */
+static void
+extract_devices_dir_from_collect_gcc (char **devices_loc)
+{
+  char *t_devices_loc = *devices_loc;
+  /* Go up a directory to the toolchain root.  */
+  t_devices_loc = msp430_dirname (msp430_dirname (t_devices_loc));
+  t_devices_loc = concat (t_devices_loc, rest_of_devices_path, NULL);
+  *devices_loc = t_devices_loc;
+}
+
+/* The path to the MSP430-GCC support files can be specified with the
+   environment variable "MSP430_GCC_INCLUDE_DIR", or installed into the
+   toolchain in the msp430-elf/include/devices subdirectory.
+   We use the GCC_EXEC_PREFIX or COLLECT_GCC environment variables as a starting
+   point for the location of the toolchain, and work out the path to the
+   installed device data from there.
+   Return 0 and set LOCAL_DEVICES_CSV_LOC if we find devices.csv.  Return 1
+   if devices.csv wasn't found.  */
+int
+msp430_check_env_var_for_devices (char **local_devices_csv_loc)
+{
+  const int num_vars = 3;
+  const char dirsep[2] = { DIR_SEPARATOR, 0 };
+  /* Both GCC_EXEC_PREFIX and COLLECT_GCC should always be set to the format we
+     expect, as they are required for correct operation of the toolchain.
+     So if they are wrong the user will probably have bigger problems.
+     GCC_EXEC_PREFIX is only defined in the driver, whilst COLLECT_GCC is only
+     defined in the compiler proper, so we need both.  */
+  const char *env_vars[num_vars] = {
+      "MSP430_GCC_INCLUDE_DIR", "GCC_EXEC_PREFIX", "COLLECT_GCC" };
+  enum msp430_include_vars {
+      MSP430_GCC_INCLUDE_DIR,
+      GCC_EXEC_PREFIX,
+      COLLECT_GCC
+  };
+  FILE *devices_csv_file = NULL;
+  int i;
+
+  for (i = MSP430_GCC_INCLUDE_DIR; i <= COLLECT_GCC; i++)
+    {
+      char *t_devices_loc;
+      char *val = getenv (env_vars[i]);
+      if (val == NULL)
+       continue;
+      t_devices_loc = xstrdup (val);
+
+      if (i == MSP430_GCC_INCLUDE_DIR)
+       {
+         if (!IS_DIR_SEPARATOR (t_devices_loc[strlen (t_devices_loc) - 1]))
+           t_devices_loc = concat (t_devices_loc, dirsep, NULL);
+       }
+      else if (i == GCC_EXEC_PREFIX)
+       extract_devices_dir_from_exec_prefix (&t_devices_loc);
+      else if (i == COLLECT_GCC)
+       extract_devices_dir_from_collect_gcc (&t_devices_loc);
+
+      t_devices_loc = concat (t_devices_loc, "devices.csv", NULL);
+      devices_csv_file = fopen (t_devices_loc,  "r");
+      if (devices_csv_file != NULL)
+       {
+         fclose (devices_csv_file);
+         *local_devices_csv_loc = t_devices_loc;
+         canonicalize_path_dirsep (local_devices_csv_loc);
+         return 0;
+       }
+    }
+  return 1;
+}
+
 /* Spec function which searches the paths passed to the -I and -L options for
    the "devices.csv" file.  If it is found then the -mdevices-csv-loc option is
    placed on the command line so the compiler knows the location of the
@@ -69,7 +191,7 @@ msp430_check_path_for_devices (int argc, const char **argv)
     return NULL;
   for (i = 0; i < argc; i++)
     {
-      char *inc_path = ASTRDUP (argv[i]);
+      char *inc_path = xstrdup (argv[i]);
       canonicalize_path_dirsep (&inc_path);
       if (!IS_DIR_SEPARATOR (inc_path[strlen (inc_path) - 1]))
        inc_path = concat (inc_path, dirsep, NULL);
@@ -274,8 +396,11 @@ parse_devices_csv (const char * mcu_name)
   /* Otherwise check if the path to devices.csv was found another way.  */
   else if (derived_devices_csv_loc != NULL)
     return parse_devices_csv_1 (derived_devices_csv_loc, mcu_name);
-  /* devices.csv was not found.  */
-  return 2;
+  /* Otherwise we need to use environment variables to try and find it.  */
+  if (msp430_check_env_var_for_devices (&derived_devices_csv_loc))
+    /* devices.csv was not found.  */
+    return 2;
+  return parse_devices_csv_1 (derived_devices_csv_loc, mcu_name);
 }
 
 /* Main entry point to load the MCU data for the given -mmcu into
index 08ae1adf4edaf96ca2b871fa31fd9c4be8177a1b..9e8029a32cad5f64af14bcc645f791cd20be8b37 100644 (file)
@@ -29,3 +29,5 @@ struct t_msp430_mcu_data
 extern struct t_msp430_mcu_data extracted_mcu_data;
 
 void msp430_extract_mcu_data (const char * mcu_name);
+int msp430_check_env_var_for_devices (char **local_devices_csv_loc);
+char *msp430_dirname (char *path);
index c058690e82703bf7c3ad51814e339590bd1a5f4e..b5d3edb42d0bc24e814711a497d0f52104857ec2 100644 (file)
@@ -47,6 +47,8 @@
 #include "builtins.h"
 #include "intl.h"
 #include "msp430-devices.h"
+#include "incpath.h"
+#include "prefix.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -3634,6 +3636,27 @@ msp430_incoming_return_addr_rtx (void)
 {
   return gen_rtx_MEM (Pmode, stack_pointer_rtx);
 }
+
+/* If the path to the MSP430-GCC support files has been found by examining
+   an environment variable (see msp430_check_env_var_for_devices in
+   msp430-devices.c), or -mdevices-csv-loc=, register this path as an include
+   directory so the user can #include msp430.h without needing to specify the
+   path to the support files with -I.  */
+void
+msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED,
+                             const char *iprefix ATTRIBUTE_UNUSED,
+                             int stdinc ATTRIBUTE_UNUSED)
+{
+  char *include_dir;
+  if (msp430_devices_csv_loc)
+    include_dir = xstrdup (msp430_devices_csv_loc);
+  else if (msp430_check_env_var_for_devices (&include_dir))
+    return;
+  include_dir = msp430_dirname (include_dir);
+
+  include_dir = update_path (include_dir, "");
+  add_path (include_dir, INC_SYSTEM, false, false);
+}
 \f
 /* Instruction generation stuff.  */
 
index 73afe2e2d169cc89d4f4ce7ebbe7daeb1fea6814..2e70e0d6ab6cf7880dc8d3faa6f6c2d6b17d1a52 100644 (file)
@@ -75,6 +75,7 @@ extern bool msp430x;
     "msp430_propagate_region_opt(%* %{muse-lower-region-prefix})} " \
   "%{mdata-region=*:--data-region=%:" \
     "msp430_propagate_region_opt(%* %{muse-lower-region-prefix})} " \
+  "%:msp430_get_linker_devices_include_path()"
 
 #define DRIVER_SELF_SPECS \
   " %{!mlarge:%{mcode-region=*:%{mdata-region=*:%e-mcode-region and "  \
@@ -94,6 +95,7 @@ extern const char * msp430_select_cpu (int, const char **);
 extern const char * msp430_set_driver_var (int, const char **);
 extern const char * msp430_check_path_for_devices (int, const char **);
 extern const char *msp430_propagate_region_opt (int, const char **);
+extern const char *msp430_get_linker_devices_include_path (int, const char **);
 
 /* There must be a trailing comma after the last item, see gcc.c
    "static_spec_functions".  */
@@ -102,7 +104,9 @@ extern const char *msp430_propagate_region_opt (int, const char **);
   { "msp430_select_cpu", msp430_select_cpu },          \
   { "msp430_set_driver_var", msp430_set_driver_var },          \
   { "msp430_check_path_for_devices", msp430_check_path_for_devices }, \
-  { "msp430_propagate_region_opt", msp430_propagate_region_opt },
+  { "msp430_propagate_region_opt", msp430_propagate_region_opt }, \
+  { "msp430_get_linker_devices_include_path", \
+    msp430_get_linker_devices_include_path },
 
 /* Specify the libraries to include on the linker command line.
 
@@ -496,6 +500,12 @@ typedef struct
 
 #define TARGET_HAS_NO_HW_DIVIDE (! TARGET_HWMULT)
 
+void msp430_register_pre_includes (const char *sysroot ATTRIBUTE_UNUSED,
+                                  const char *iprefix ATTRIBUTE_UNUSED,
+                                  int stdinc ATTRIBUTE_UNUSED);
+#undef TARGET_EXTRA_PRE_INCLUDES
+#define TARGET_EXTRA_PRE_INCLUDES msp430_register_pre_includes
+
 #undef  USE_SELECT_SECTION_FOR_FUNCTIONS
 #define USE_SELECT_SECTION_FOR_FUNCTIONS 1
 
index faa7fa95a0eb02d897423a0d4d43be66e2dc8969..122a23eef115b79380ddae9161b50a48ad760b68 100644 (file)
@@ -23231,8 +23231,33 @@ The ISA and hardware multiply supported for the different MCUs is hard-coded
 into GCC.  However, an external @samp{devices.csv} file can be used to
 extend device support beyond those that have been hard-coded.
 
-GCC searches for the @samp{devices.csv} file on the paths specified
-with the @code{-I} and @code{-L} options.
+GCC searches for the @samp{devices.csv} file using the following methods in the
+given precedence order, where the first method takes precendence over the
+second which takes precedence over the third.
+
+@table @asis
+@item Include path specified with @code{-I} and @code{-L}
+@samp{devices.csv} will be searched for in each of the directories specified by
+include paths and linker library search paths.
+@item Path specified by the environment variable @samp{MSP430_GCC_INCLUDE_DIR}
+Define the value of the global environment variable
+@samp{MSP430_GCC_INCLUDE_DIR}
+to the full path to the directory containing devices.csv, and GCC will search
+this directory for devices.csv.  If devices.csv is found, this directory will
+also be registered as an include path, and linker library path.  Header files
+and linker scripts in this directory can therefore be used without manually
+specifying @code{-I} and @code{-L} on the command line.
+@item The @samp{msp430-elf/include/devices} directory
+Finally, GCC will examine @samp{msp430-elf/include/devices} from the
+toolchain root directory.  This directory does not exist in a default
+installation, but if the user has created it and copied @samp{devices.csv}
+there, then the MCU data will be read.  As above, this directory will
+also be registered as an include path, and linker library path.
+
+@end table
+If none of the above search methods find @samp{devices.csv}, then the
+hard-coded MCU data is used.
+
 
 @item -mwarn-mcu
 @itemx -mno-warn-mcu
index 7140f1d7e80e8a740c11945cfc9110bde1ee5435..45ec73ab7d2cf0547637590bccfe3ee26f8b7901 100644 (file)
@@ -1,3 +1,20 @@
+2019-11-04  Jozef Lawrynowicz  <jozef.l@mittosystems.com>
+
+       * gcc.target/msp430/devices/csv-using-env-var.c: New test.
+       * gcc.target/msp430/devices/csv-using-installed.c: New test.
+       * gcc.target/msp430/devices/csv-using-option.c: New test.
+       * gcc.target/msp430/devices/devices-main.c: New test source file.
+       * gcc.target/msp430/devices/msp430-devices.h: New test.
+       * gcc.target/msp430/msp430.exp (msp430_device_permutations_runtest):
+       Add special cases for csv-using* tests.
+       Define TESTING_HARD_DATA when running tests that use hard-coded device
+       data.
+       (get_installed_device_data_path): New.
+       (msp430_hide_installed_devices_data): New.
+       (msp430_restore_installed_devices_data): New.
+       (msp430_test_installed_device_data): New.
+       (msp430_install_device_data): New.
+
 2019-11-04  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/92301
diff --git a/gcc/testsuite/gcc.target/msp430/devices/csv-using-env-var.c b/gcc/testsuite/gcc.target/msp430/devices/csv-using-env-var.c
new file mode 100644 (file)
index 0000000..f2c30ee
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-mmcu=msp430_28" } */
+/* { dg-warning "supports 430X ISA but '-mcpu' option is set to 430" "" { target msp430_430_selected } 0 } */
+/* { dg-warning "supports f5series hardware multiply" "" { target msp430_hwmul_not_f5 } 0 } */
+
+/* This tests that the environment variable MSP430_GCC_INCLUDE_DIR can be used
+   to specify the path to the directory containing devices.csv.
+   The variable is set in msp430.exp.  */
+
+#include "devices-main.c"
diff --git a/gcc/testsuite/gcc.target/msp430/devices/csv-using-installed.c b/gcc/testsuite/gcc.target/msp430/devices/csv-using-installed.c
new file mode 100644 (file)
index 0000000..11cbbab
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-mmcu=msp430_28" } */
+/* { dg-warning "supports 430X ISA but '-mcpu' option is set to 430" "" { target msp430_430_selected } 0 } */
+/* { dg-warning "supports f5series hardware multiply" "" { target msp430_hwmul_not_f5 } 0 } */
+
+/* This tests that devices.csv can be installed into the
+   "$TOOLCHAIN_ROOT/msp430-elf/include/devices/" and used to read device data.  */
+
+#include "devices-main.c"
diff --git a/gcc/testsuite/gcc.target/msp430/devices/csv-using-option.c b/gcc/testsuite/gcc.target/msp430/devices/csv-using-option.c
new file mode 100644 (file)
index 0000000..bb47d53
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-mmcu=msp430_28" } */
+/* { dg-warning "supports 430X ISA but '-mcpu' option is set to 430" "" { target msp430_430_selected } 0 } */
+/* { dg-warning "supports f5series hardware multiply" "" { target msp430_hwmul_not_f5 } 0 } */
+
+/* This tests that the -mdevices-csv-loc option can be used to specify the path
+   to devices.csv.  */
+
+#include "devices-main.c"
index 20448f4f03dd6377e329236a445f0ff8537df1a5..8af6ec124bda5961ac321c771c029287f5253171 100644 (file)
@@ -1,3 +1,7 @@
+#ifndef TESTING_HARD_DATA
+#include <msp430-devices.h>
+#endif
+
 int
 main (void)
 {
diff --git a/gcc/testsuite/gcc.target/msp430/devices/msp430-devices.h b/gcc/testsuite/gcc.target/msp430/devices/msp430-devices.h
new file mode 100644 (file)
index 0000000..105bd2b
--- /dev/null
@@ -0,0 +1,3 @@
+#ifndef __MSP430__
+#error
+#endif
index bcc56861abc4f0bfb580af22a3f37b2a972c9591..37586612b9abb32a229d47708b96d6aa6ce9f1f5 100644 (file)
@@ -101,6 +101,25 @@ proc msp430_device_permutations_runtest { tests } {
        if { ![runtest_file_p $runtests $test_file] } {
            continue
        }
+       # The device name passed to -mmcu in the csv-using-* tests do not exist
+       # in the hard-coded data, to ensure the test fails if the method can't
+       # find the device data.
+       if { [file tail $test_file] eq "csv-using-installed.c" } {
+           msp430_test_installed_device_data $test_file $MSP430_DEFAULT_CFLAGS
+           continue
+       } elseif { [file tail $test_file] eq "csv-using-option.c" } {
+           dg-runtest $test_file \
+               "-mdevices-csv-loc=[file dirname $test_file]/devices.csv" \
+               "$MSP430_DEFAULT_CFLAGS"
+           continue
+       } elseif { [file tail $test_file] eq "csv-using-env-var.c" } {
+           setenv MSP430_GCC_INCLUDE_DIR [file dirname $test_file]
+           verbose -log "MSP430_GCC_INCLUDE_DIR=[file dirname $test_file]"
+           dg-runtest $test_file "" "$MSP430_DEFAULT_CFLAGS"
+           setenv MSP430_GCC_INCLUDE_DIR ""
+           verbose -log "MSP430_GCC_INCLUDE_DIR=\"\""
+           continue
+       }
        foreach { mcu_flags } [msp430_get_opts $test_file] {
            if { [string match "csv-*" [file tail $test_file]] } {
                # Specify the path to devices.csv for devices/csv-* tests with -I.
@@ -115,12 +134,76 @@ proc msp430_device_permutations_runtest { tests } {
            } elseif { [string match "bad-devices*" [file tail $test_file]] } {
                dg-runtest $test_file "$mcu_flags" "-mdevices-csv-loc=[file dirname $test_file]/[file tail $test_file]sv $MSP430_DEFAULT_CFLAGS"
            } else {
-               dg-runtest $test_file "$mcu_flags" "$MSP430_DEFAULT_CFLAGS"
+               dg-runtest $test_file "$mcu_flags -DTESTING_HARD_DATA" "$MSP430_DEFAULT_CFLAGS"
            }
-       }
+        }
+    }
+}
+
+
+# Return $TOOLCHAIN_ROOT/msp430-elf/include/devices/
+proc get_installed_device_data_path { } {
+    set compiler [lindex [regexp -all -inline {\S+} \
+       [board_info [target_info name] compiler]] 0]
+    # $compiler is actually a file, but normalize will still get us the desired
+    # result.
+    return [file normalize \
+       "$compiler/../../msp430-elf/include/devices/devices.csv"]
+}
+
+# If the devices.csv is installed in
+# $TOOLCHAIN_ROOT/msp430-elf/include/devices/, rename it so it doesn't
+# interfere with the hard-coded device data tests.
+proc msp430_hide_installed_devices_data { } {
+    set devices_path [get_installed_device_data_path]
+    if { [file exists $devices_path] } {
+       file rename $devices_path "$devices_path.bak"
     }
 }
 
+# Restore devices.csv if renamed by msp430_hide_installed_devices_data.
+proc msp430_restore_installed_devices_data { } {
+    set devices_path [get_installed_device_data_path]
+    if { [file exists "$devices_path.bak"] } {
+       file rename "$devices_path.bak" $devices_path 
+    }
+}
+
+proc msp430_test_installed_device_data { name default_cflags } {
+    global subdir
+    global env
+
+    # The initial value for GCC_EXEC_PREFIX set by target-libpath.exp is not
+    # correct for cross-compilers so fix it here. GCC fixes the value itself,
+    # but not after spec functions are executed, which can cause a warning
+    # about missing devices.csv to be emitted.
+    set compiler [lindex [regexp -all -inline {\S+} \
+       [board_info [target_info name] compiler]] 0]
+    set real_exec_prefix "[file normalize "$compiler/../../lib/gcc"]/"
+    setenv GCC_EXEC_PREFIX $real_exec_prefix
+
+    msp430_restore_installed_devices_data 
+    set devices_path [get_installed_device_data_path]
+    if { [file exists $devices_path] } {
+       dg-runtest $name "" "$default_cflags"
+    } else {
+       set shorter_name "$subdir/[file tail $name]"
+       verbose -log "$shorter_name not supported, $devices_path doesn't exist."
+       unsupported $shorter_name
+    }
+    msp430_hide_installed_devices_data 
+}
+
+proc msp430_install_device_data { testsuite_dir } {
+    set devices_path [get_installed_device_data_path]
+    if { [file exists $devices_path] } {
+        return
+    }
+    set installed_path [file dirname $devices_path]
+    file mkdir $installed_path
+    file copy $testsuite_dir/msp430-devices.h $testsuite_dir/devices.csv $installed_path
+}
+
 # Load support procs.
 load_lib gcc-dg.exp
 
@@ -138,11 +221,18 @@ if [info exists DEFAULT_CFLAGS] then {
 # Initialize `dg'.
 dg-init
 
+# Install then hide the devices data now, in case it is already installed. We
+# don't want it to interfere with tests until we need it to.
+msp430_install_device_data $srcdir/$subdir/devices
+msp430_hide_installed_devices_data
+
 # Main loop.
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \
        "" $MSP430_DEFAULT_CFLAGS
 
 msp430_device_permutations_runtest [lsort [glob -nocomplain $srcdir/$subdir/devices/*.\[cCS\]]]
 
+msp430_restore_installed_devices_data 
+
 # All done.
 dg-finish