diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 0acf2e5f77..d4f34e76fd 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -1352,6 +1352,10 @@
*/
//#define SDCARD_CONNECTION LCD
+ // Emulate RepRapFirmware with macro files stored in /sys and /macros
+ // Provide the M98 command to run a macro file as a sub-program
+ //#define MACHINE_COMMAND_MACROS
+
#endif // SDSUPPORT
/**
diff --git a/Marlin/src/gcode/sdcard/M98.cpp b/Marlin/src/gcode/sdcard/M98.cpp
new file mode 100644
index 0000000000..2959d7fc19
--- /dev/null
+++ b/Marlin/src/gcode/sdcard/M98.cpp
@@ -0,0 +1,49 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * This program 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 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see .
+ *
+ */
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(MACHINE_COMMAND_MACROS)
+
+#include "../gcode.h"
+#include "../../sd/cardreader.h"
+
+/**
+ * M98: Select file and run as sub-procedure
+ *
+ * P - The plain (DOS 8.3) filepath
+ *
+ * Example:
+ * M98 P/macros/home.g ; Run home.g (as a procedure)
+ *
+ */
+void GcodeSuite::M98() {
+ if (card.isMounted() && parser.seen('P')) {
+ char *path = parser.value_string();
+ char *lb = strchr(p, ' ');
+ if (!lb) lb = strchr(p, ';');
+ if (lb) *lb = '\0';
+ card.runMacro(path);
+ }
+}
+
+#endif // MACHINE_COMMAND_MACROS
diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp
index 1be5f4f2f6..87138512e9 100644
--- a/Marlin/src/sd/cardreader.cpp
+++ b/Marlin/src/sd/cardreader.cpp
@@ -650,6 +650,15 @@ bool CardReader::fileExists(const char * const path) {
return !!fname;
}
+#if ENABLED(MACHINE_COMMAND_MACROS)
+
+ void CardReader::runMacro(const char * const path) {
+ openFileRead(path, 2);
+ startFileprint();
+ }
+
+#endif
+
//
// Delete a file by name in the working directory
//
diff --git a/Marlin/src/sd/cardreader.h b/Marlin/src/sd/cardreader.h
index c6fe37400c..6cbd74efb6 100644
--- a/Marlin/src/sd/cardreader.h
+++ b/Marlin/src/sd/cardreader.h
@@ -102,6 +102,10 @@ public:
static bool fileExists(const char * const name);
static void removeFile(const char * const name);
+ #if ENABLED(MACHINE_COMMAND_MACROS)
+ static void runMacro(const char * const path);
+ #endif
+
static inline char* longest_filename() { return longFilename[0] ? longFilename : filename; }
#if ENABLED(LONG_FILENAME_HOST_SUPPORT)
static void printLongPath(char * const path); // Used by M33