Get some basic Teensy code working

It prints some stuff over the USB serial port and turns the on-board LED
on. Also tweak some of the existing code so it works with better
compiler options for what we're doing.

Change-Id: Ifcbd36f9eaca47a86f7a97e8c458c64f9b3df3ab
diff --git a/NO_BUILD_AMD64 b/NO_BUILD_AMD64
index 69ace36..6189481 100644
--- a/NO_BUILD_AMD64
+++ b/NO_BUILD_AMD64
@@ -27,3 +27,4 @@
 -//y2017:wpilib_interface
 -//y2017:download_stripped
 -//y2017:download
+-//motors/...
diff --git a/NO_BUILD_ROBORIO b/NO_BUILD_ROBORIO
index e7d0de1..780d909 100644
--- a/NO_BUILD_ROBORIO
+++ b/NO_BUILD_ROBORIO
@@ -15,3 +15,4 @@
 -//third_party/protobuf/...
 -//y2016_bot3/...
 -//y2017/control_loops/python/...
+-//motors/...
diff --git a/WORKSPACE b/WORKSPACE
index 4db4ba8..dc5e2da 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -117,3 +117,9 @@
   url = 'http://frc971.org/Build-Dependencies/empty.tar.gz',
   sha256 = '71939a7d75585a57d2e99a33d39f391764d8f930f9a16acf32e00c5d3f432aa0',
 )
+
+new_local_repository(
+  name = 'libusb',
+  path = '/usr',
+  build_file = 'debian/libusb.BUILD',
+)
diff --git a/debian/libusb.BUILD b/debian/libusb.BUILD
new file mode 100644
index 0000000..3ccffe1
--- /dev/null
+++ b/debian/libusb.BUILD
@@ -0,0 +1,13 @@
+cc_library(
+  name = 'libusb',
+  visibility = ['//visibility:public'],
+  srcs = [
+    'lib/x86_64-linux-gnu/libusb.so',
+  ],
+  hdrs = [
+    'include/usb.h',
+  ],
+  includes = [
+    'include',
+  ],
+)
diff --git a/motors/BUILD b/motors/BUILD
new file mode 100644
index 0000000..defd1f9
--- /dev/null
+++ b/motors/BUILD
@@ -0,0 +1,31 @@
+cc_binary(
+  name = 'medium_salsa.elf',
+  srcs = [
+    'medium_salsa.cc',
+  ],
+  deps = [
+    ':util',
+    '//motors/core',
+    '//motors/usb',
+  ],
+)
+
+genrule(
+  name = 'medium_salsa',
+  srcs = [
+    'medium_salsa.elf',
+  ],
+  outs = [
+    'medium_salsa.hex',
+  ],
+  cmd = '$(OBJCOPY) -O ihex $<  $@',
+  executable = True,
+  output_to_bindir = True,
+)
+
+cc_library(
+  name = 'util',
+  hdrs = [
+    'util.h',
+  ],
+)
diff --git a/motors/core/mk64fx512.ld b/motors/core/mk64fx512.ld
index e16d7ad..43a63ad 100644
--- a/motors/core/mk64fx512.ld
+++ b/motors/core/mk64fx512.ld
@@ -30,83 +30,91 @@
 
 MEMORY
 {
-	FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
-	RAM  (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K
+  FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K
+  RAM  (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 192K
 }
 
 
 SECTIONS
 {
-	.text : {
-		. = 0;
-		KEEP(*(.vectors))
-		*(.startup*)
-		. = 0x400;
-		KEEP(*(.flashconfig*))
-		*(.text*)
-		*(.rodata*)
-		. = ALIGN(4);
-		KEEP(*(.init))
-		. = ALIGN(4);
-		__preinit_array_start = .;
-		KEEP (*(.preinit_array))
-		__preinit_array_end = .;
-		__init_array_start = .;
-		KEEP (*(SORT(.init_array.*)))
-		KEEP (*(.init_array))
-		__init_array_end = .;
-	} > FLASH = 0xFF
+  .text : {
+    . = 0;
+    KEEP(*(.vectors))
+    *(.startup*)
+    . = 0x400;
+    KEEP(*(.flashconfig*))
+    *(SORT_BY_ALIGNMENT(.text*))
+    *(SORT_BY_ALIGNMENT(.rodata*))
+    . = ALIGN(4);
+    KEEP(*(.init))
+    . = ALIGN(4);
+    __preinit_array_start = .;
+    KEEP (*(.preinit_array))
+    __preinit_array_end = .;
+    __init_array_start = .;
+    KEEP (*(SORT(.init_array.*)))
+    KEEP (*(.init_array))
+    __init_array_end = .;
+  } > FLASH = 0xFF
 
-	.ARM.exidx : {
-		__exidx_start = .;
-		*(.ARM.exidx* .gnu.linkonce.armexidx.*)
-		__exidx_end = .;
-	} > FLASH
-	_etext = .;
+  .ARM.exidx : {
+    __exidx_start = .;
+    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+    __exidx_end = .;
+  } > FLASH
+  _etext = .;
 
-	.usbdescriptortable (NOLOAD) : {
-		/* . = ORIGIN(RAM); */
-		_sram = .;
-		. = ALIGN(512);
-		*(.usbdescriptortable*)
-	} > RAM
+  .usbdescriptortable (NOLOAD) : {
+    /* . = ORIGIN(RAM); */
+    _sram = .;
+    . = ALIGN(512);
+    *(.usbdescriptortable*)
+  } > RAM
 
-	.dmabuffers (NOLOAD) : {
-		. = ALIGN(4);
-		*(.dmabuffers*)
-	} > RAM
+  .dmabuffers (NOLOAD) : {
+    . = ALIGN(4);
+    *(.dmabuffers*)
+  } > RAM
 
-	.usbbuffers (NOLOAD) : {
-		. = ALIGN(4);
-		*(.usbbuffers*)
-	} > RAM
+  .usbbuffers (NOLOAD) : {
+    . = ALIGN(4);
+    *(.usbbuffers*)
+  } > RAM
 
-	.data : AT (_etext) {
-		. = ALIGN(4);
-		_sdata = .; 
-		*(.fastrun*)
-		*(.data*)
-		. = ALIGN(4);
-		_edata = .; 
-	} > RAM
+  .data : AT (_etext) {
+    . = ALIGN(4);
+    _sdata = .; 
+    *(SORT_BY_ALIGNMENT(.data*))
+    . = ALIGN(4);
+    _edata = .; 
+  } > RAM
 
-	.noinit (NOLOAD) : {
-		*(.noinit*)
-	} > RAM
+  .noinit (NOLOAD) : {
+    *(.noinit*)
+  } > RAM
 
-	.bss : {
-		. = ALIGN(4);
-		_sbss = .;
-		__bss_start__ = .;
-		*(.bss*)
-		*(COMMON)
-		. = ALIGN(4);
-		_ebss = .;
-		__bss_end = .;
-		__bss_end__ = .;
-	} > RAM
+  .bss : {
+    . = ALIGN(4);
+    _sbss = .;
+    __bss_start__ = .;
+    *(SORT_BY_ALIGNMENT(.bss*))
+    /* Stupid precompiled libc has common symbols, so stick them in. */
+    */libc_nano.a:*(COMMON)
+    . = ALIGN(4);
+    _ebss = .;
+    __bss_end = .;
+    __bss_end__ = .;
+  } > RAM
 
-	_estack = ORIGIN(RAM) + LENGTH(RAM);
+  /* We don't want any common symbols, so just don't include them which results
+   * in linker errors if any do show up somehow.
+   * Contrary to sanity, even with --orphan-handling=error the linker will still
+   * do normal orphan section handling with COMMON... */
+  /DISCARD/ : {
+    *(COMMON);
+  }
+
+  _estack = ORIGIN(RAM) + LENGTH(RAM);
 }
 
 
diff --git a/motors/core/nonstd.c b/motors/core/nonstd.c
index 436cee4..88f35b3 100644
--- a/motors/core/nonstd.c
+++ b/motors/core/nonstd.c
@@ -163,7 +163,7 @@
 
 			// shift decimal point
 			while (newPrecision > 0) {
-				val *= 10.0;
+				val *= 10.0f;
 				newPrecision--;
 			}
 
diff --git a/motors/medium_salsa.cc b/motors/medium_salsa.cc
new file mode 100644
index 0000000..1a899b1
--- /dev/null
+++ b/motors/medium_salsa.cc
@@ -0,0 +1,76 @@
+#include "motors/core/kinetis.h"
+
+#include <stdio.h>
+
+#include "motors/core/time.h"
+#include "motors/usb/usb_serial.h"
+#include "motors/util.h"
+
+namespace frc971 {
+namespace salsa {
+
+extern "C" {
+void *__stack_chk_guard = (void *)0x67111971;
+extern void usb_init();
+int _write(int file, char *ptr, int len) {
+  (void)file;
+  return usb_serial_write(0, ptr, len);
+}
+
+void __stack_chk_fail(void);
+
+extern char *__brkval;
+extern unsigned long _ebss;
+extern unsigned long _sram;
+extern unsigned long _estack;
+
+}  // extern "C"
+
+extern "C" int main(void) {
+  // for background about this startup delay, please see these conversations
+  // https://forum.pjrc.com/threads/36606-startup-time-(400ms)?p=113980&viewfull=1#post113980
+  // https://forum.pjrc.com/threads/31290-Teensey-3-2-Teensey-Loader-1-24-Issues?p=87273&viewfull=1#post87273
+  delay(400);
+
+  // Set all interrupts to the second-lowest priority to start with.
+  for (int i = 0; i < NVIC_NUM_INTERRUPTS; i++) NVIC_SET_SANE_PRIORITY(i, 0xD);
+
+  // Now set priorities for all the ones we care about. They only have meaning
+  // relative to each other, which means centralizing them here makes it a lot
+  // more manageable.
+  NVIC_SET_SANE_PRIORITY(IRQ_USBOTG, 0x7);
+
+  // Set the LED's pin to output mode.
+  GPIO_BITBAND(GPIOC_PDDR, 5) = 1;
+  PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(1);
+
+  usb_serial_init();
+  usb_descriptor_set_product_id(0x0490);
+  usb_init();
+
+  // Give everything a chance to get going.
+  delay(100);
+
+  printf("Ram start:   %p\n", &_sram);
+  printf("Heap start:  %p\n", &_ebss);
+  printf("Heap end:    %p\n", __brkval);
+  printf("Stack start: %p\n", &_estack);
+
+  GPIOC_PSOR = 1 << 5;
+
+  while (true) {}
+  return 0;
+}
+
+void __stack_chk_fail(void) {
+  while (true) {
+    GPIOC_PSOR = (1 << 5);
+    printf("Stack corruption detected\n");
+    delay(1000);
+    GPIOC_PCOR = (1 << 5);
+    delay(1000);
+  }
+}
+
+}  // namespace salsa
+}  // namespace frc971
diff --git a/motors/util.h b/motors/util.h
new file mode 100644
index 0000000..05edd9d
--- /dev/null
+++ b/motors/util.h
@@ -0,0 +1,154 @@
+#ifndef MOTORS_UTIL_H_
+#define MOTORS_UTIL_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// The GPIO bitband register for a specific bit of a given GPIO register.
+//
+// reg really must be one of the GPIO module's addresses
+// (0x400FF000 - 0x400FFFFF).
+#define GPIO_BITBAND(reg, bit)                                             \
+  (*(volatile uint32_t *)(((uint32_t) & (reg)-0x40000000) * 32 + (bit)*4 + \
+                          0x42000000))
+
+#define NVIC_SET_SANE_PRIORITY(irqnum, priority) \
+  NVIC_SET_PRIORITY(irqnum, ((priority)&0xF) << 4)
+#define NVIC_GET_SANE_PRIORITY(irqnum) (NVIC_GET_PRIORITY(irqnum) >> 4)
+
+// Definitions for the bits in some registers that are missing.
+#define CAN_MCR_MDIS ((uint32_t)(1 << 31))
+#define CAN_MCR_FRZ ((uint32_t)(1 << 30))
+#define CAN_MCR_RFEN ((uint32_t)(1 << 29))
+#define CAN_MCR_HALT ((uint32_t)(1 << 28))
+#define CAN_MCR_NOTRDY ((uint32_t)(1 << 27))
+#define CAN_MCR_WAKMSK ((uint32_t)(1 << 26))
+#define CAN_MCR_SOFTRST ((uint32_t)(1 << 25))
+#define CAN_MCR_FRZACK ((uint32_t)(1 << 24))
+#define CAN_MCR_SUPV ((uint32_t)(1 << 23))
+#define CAN_MCR_SLFWAK ((uint32_t)(1 << 22))
+#define CAN_MCR_WRNEN ((uint32_t)(1 << 21))
+#define CAN_MCR_LPMACK ((uint32_t)(1 << 20))
+#define CAN_MCR_WAKSRC ((uint32_t)(1 << 19))
+#define CAN_MCR_SRXDIS ((uint32_t)(1 << 17))
+#define CAN_MCR_IRMQ ((uint32_t)(1 << 16))
+#define CAN_MCR_LPRIOEN ((uint32_t)(1 << 13))
+#define CAN_MCR_AEN ((uint32_t)(1 << 12))
+#define CAN_MCR_IDAM(n) ((uint32_t)(((n) & 3) << 8))
+#define CAN_MCR_MAXMB(n) ((uint32_t)((n) & 0x7F))
+#define CAN_CTRL1_PRESDIV(n) ((uint32_t)(((n) & 0xFF) << 24))
+#define CAN_CTRL1_RJW(n) ((uint32_t)(((n) & 3) << 22))
+#define CAN_CTRL1_PSEG1(n) ((uint32_t)(((n) & 7) << 19))
+#define CAN_CTRL1_PSEG2(n) ((uint32_t)(((n) & 7) << 16))
+#define CAN_CTRL1_BOFFMSK ((uint32_t)(1 << 15))
+#define CAN_CTRL1_ERRMSK ((uint32_t)(1 << 14))
+#define CAN_CTRL1_CLKSRC ((uint32_t)(1 << 13))
+#define CAN_CTRL1_LPB ((uint32_t)(1 << 12))
+#define CAN_CTRL1_TWRNMSK ((uint32_t)((1 << 11))
+#define CAN_CTRL1_RWRNMSK ((uint32_t)((1 << 10))
+#define CAN_CTRL1_SMP ((uint32_t)(1 << 7))
+#define CAN_CTRL1_BOFFREC ((uint32_t)(1 << 6)
+#define CAN_CTRL1_TSYN ((uint32_t)(1 << 5))
+#define CAN_CTRL1_LBUF ((uint32_t)(1 << 4))
+#define CAN_CTRL1_LOM ((uint32_t)(1 << 3))
+#define CAN_CTRL1_PROPSEG(n) ((uint32_t)((n) & 7))
+#define CAN_ESR1_SYNCH ((uint32_t)(1 << 18))
+#define CAN_ESR1_TWRNINT ((uint32_t)(1 << 17))
+#define CAN_ESR1_RWRNINT ((uint32_t)(1 << 16))
+#define CAN_ESR1_BIT1ERR ((uint32_t)(1 << 15))
+#define CAN_ESR1_BIT0ERR ((uint32_t)(1 << 14))
+#define CAN_ESR1_ACKERR ((uint32_t)(1 << 13))
+#define CAN_ESR1_CRCERR ((uint32_t)(1 << 12))
+#define CAN_ESR1_FRMERR ((uint32_t)(1 << 11))
+#define CAN_ESR1_STFERR ((uint32_t)(1 << 10))
+#define CAN_ESR1_TXWRN ((uint32_t)(1 << 9))
+#define CAN_ESR1_RXWRN ((uint32_t)(1 << 8))
+#define CAN_ESR1_IDLE ((uint32_t)(1 << 7))
+#define CAN_ESR1_TX ((uint32_t)(1 << 6))
+#define CAN_ESR1_RX ((uint32_t)(1 << 3))
+#define CAN_ESR1_BOFFINT ((uint32_t)(1 << 2))
+#define CAN_ESR1_ERRINT ((uint32_t)(1 << 1))
+#define CAN_ESR1_WAKINT ((uint32_t)1)
+#define CAN_CTRL2_WRMFRZ ((uint32_t)(1 << 28))
+#define CAN_CTRL2_RFFN(n) ((uint32_t)(((n) & 0xF) << 24))
+#define CAN_CTRL2_TASD(n) ((uint32_t)(((n) & 0x1F) << 19))
+#define CAN_CTRL2_MRP ((uint32_t)(1 << 18))
+#define CAN_CTRL2_RRS ((uint32_t)(1 << 17))
+#define CAN_CTRL2_EACEN ((uint32_t)(1 << 16))
+#define CAN_ESR2_VPS ((uint32_t)(1 << 14))
+#define CAN_ESR2_IMB ((uint32_t)(1 << 13))
+
+typedef struct {
+  // Timestamp is the lower 16 bits.
+  uint32_t control_timestamp;
+  uint32_t prio_id;
+  uint32_t data[2];
+} CanMessageBuffer;
+#define CAN0_MESSAGES ((volatile CanMessageBuffer *)0x40024080)
+#define CAN0_RXIMRS ((volatile uint32_t *)0x40024880)
+#define CAN1_MESSAGES ((volatile CanMessageBuffer *)0x400A4080)
+#define CAN1_RXIMRS ((volatile uint32_t *)0x400A4880)
+#define CAN_MB_CONTROL_INSERT_DLC(dlc) ((uint32_t)(((dlc) & 0xF) << 16))
+#define CAN_MB_CONTROL_EXTRACT_DLC(control_timestamp) \
+  ((control_timestamp >> 16) & 0xF)
+#define CAN_MB_CONTROL_RTR ((uint32_t)(1 << 20))
+#define CAN_MB_CONTROL_IDE ((uint32_t)(1 << 21))
+#define CAN_MB_CONTROL_SRR ((uint32_t)(1 << 22))
+#define CAN_MB_CONTROL_INSERT_CODE(n) ((uint32_t)(((n) & 0xF) << 24))
+#define CAN_MB_CONTROL_CODE_BUSY_MASK CAN_MB_CONTROL_INSERT_CODE(1)
+#define CAN_MB_PRIO_ID_PRIORITY_MASK ((uint32_t)((1 << 29) - 1))
+#define CAN_MB_CODE_RX_INACTIVE 0
+#define CAN_MB_CODE_RX_EMPTY 4
+#define CAN_MB_CODE_RX_FULL 2
+#define CAN_MB_CODE_RX_OVERRUN 6
+#define CAN_MB_CODE_RX_RANSWER 0xA
+#define CAN_MB_CODE_TX_INACTIVE 8
+#define CAN_MB_CODE_TX_ABORT 9
+#define CAN_MB_CODE_TX_DATA 0xC
+#define CAN_MB_CODE_TX_REMOTE 0xC
+#define CAN_MB_CODE_TX_TANSWER 0xE
+#define CAN_MB_CODE_IS_BUSY(code) ((code) & 1)
+
+// We have to define these, and leave them defined, because the C preprocessor
+// is annoying...
+#define REALLY_DO_CONCATENATE(x, y, z) x ## y ## z
+#define DO_CONCATENATE(x, y, z) REALLY_DO_CONCATENATE(x, y, z)
+
+// Index-parameterized access to various registers from various peripherals.
+// This only includes ones somebody thought might be useful; add more if you
+// want them.
+#define DMA_TCDn_SADDR(n) DO_CONCATENATE(DMA_TCD, n, _SADDR)
+#define DMA_TCDn_SOFF(n) DO_CONCATENATE(DMA_TCD, n, _SOFF)
+#define DMA_TCDn_ATTR(n) DO_CONCATENATE(DMA_TCD, n, _ATTR)
+#define DMA_TCDn_NBYTES_MLNO(n) DO_CONCATENATE(DMA_TCD, n, _NBYTES_MLNO)
+#define DMA_TCDn_NBYTES_MLOFFNO(n) DO_CONCATENATE(DMA_TCD, n, _NBYTES_MLOFFNO)
+#define DMA_TCDn_NBYTES_MLOFFYES(n) DO_CONCATENATE(DMA_TCD, n, _NBYTES_MLOFFYES)
+#define DMA_TCDn_SLAST(n) DO_CONCATENATE(DMA_TCD, n, _SLAST)
+#define DMA_TCDn_DADDR(n) DO_CONCATENATE(DMA_TCD, n, _DADDR)
+#define DMA_TCDn_DOFF(n) DO_CONCATENATE(DMA_TCD, n, _DOFF)
+#define DMA_TCDn_CITER_ELINKYES(n) DO_CONCATENATE(DMA_TCD, n, _CITER_ELINKYES)
+#define DMA_TCDn_CITER_ELINKNO(n) DO_CONCATENATE(DMA_TCD, n, _CITER_ELINKNO)
+#define DMA_TCDn_DLASTSGA(n) DO_CONCATENATE(DMA_TCD, n, _DLASTSGA)
+#define DMA_TCDn_CSR(n) DO_CONCATENATE(DMA_TCD, n, _CSR)
+#define DMA_TCDn_BITER_ELINKYES(n) DO_CONCATENATE(DMA_TCD, n, _BITER_ELINKYES)
+#define DMA_TCDn_BITER_ELINKNO(n) DO_CONCATENATE(DMA_TCD, n, _BITER_ELINKNO)
+#define SPIn_MCR(n) DO_CONCATENATE(SPI, n, _MCR)
+#define SPIn_TCR(n) DO_CONCATENATE(SPI, n, _TCR)
+#define SPIn_CTAR0(n) DO_CONCATENATE(SPI, n, _CTAR0)
+#define SPIn_SR(n) DO_CONCATENATE(SPI, n, _SR)
+#define SPIn_RSER(n) DO_CONCATENATE(SPI, n, _RSER)
+#define SPIn_PUSHR(n) DO_CONCATENATE(SPI, n, _PUSHR)
+#define SPIn_POPR(n) DO_CONCATENATE(SPI, n, _POPR)
+#define DMAMUX0_CHCFGn(n) DO_CONCATENATE(DMAMUX0, _CHCFG, n)
+#define DMAMUX_SOURCE_SPIn_RX(n) DO_CONCATENATE(DMAMUX_SOURCE_SPI, n, _RX)
+#define DMAMUX_SOURCE_SPIn_TX(n) DO_CONCATENATE(DMAMUX_SOURCE_SPI, n, _TX)
+#define dma_chN_isr(n) DO_CONCATENATE(dma_ch, n, _isr)
+#define IRQ_DMA_CHn(n) DO_CONCATENATE(IRQ_DMA, _CH, n)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // MOTORS_UTIL_H_
diff --git a/tools/BUILD b/tools/BUILD
index 8926d08..b8a4f1e 100644
--- a/tools/BUILD
+++ b/tools/BUILD
@@ -20,6 +20,10 @@
   values = {'cpu': 'roborio'},
 )
 config_setting(
+  name = 'cpu_cortex_m4f',
+  values = {'cpu': 'cortex-m4f'},
+)
+config_setting(
   name = 'cpu_armhf',
   values = {'cpu': 'armhf-debian'},
 )
diff --git a/tools/cpp/BUILD b/tools/cpp/BUILD
index a7495d9..f5dfe10 100644
--- a/tools/cpp/BUILD
+++ b/tools/cpp/BUILD
@@ -10,6 +10,7 @@
   deps = select({
     '//tools:has_asan': [],
     '//tools:has_tsan': [],
+    '//tools:cpu_cortex_m4f': [],
     '//conditions:default': ['//third_party/gperftools:tcmalloc'],
   }),
 )
@@ -30,6 +31,7 @@
     'k8|clang': ':cc-compiler-k8',
     'roborio|gcc': ':cc-compiler-roborio',
     'armhf-debian|clang': 'cc-compiler-armhf-debian',
+    'cortex-m4f|gcc': 'cc-compiler-cortex-m4f',
   },
 )
 
@@ -150,3 +152,17 @@
   strip_files = '//tools/cpp/linaro_linux_gcc:strip',
   supports_param_files = 1,
 )
+
+cc_toolchain(
+  name = 'cc-compiler-cortex-m4f',
+  all_files = ':empty',
+  compiler_files = ':empty',
+  cpu = 'cortex-m4',
+  dwp_files = ':empty',
+  dynamic_runtime_libs = [':empty'],
+  linker_files = '//motors/core:linkerscript',
+  objcopy_files = ':empty',
+  static_runtime_libs = [':empty'],
+  strip_files = ':empty',
+  supports_param_files = 0,
+)
diff --git a/tools/cpp/CROSSTOOL b/tools/cpp/CROSSTOOL
index 5a374af..7e6efdb 100644
--- a/tools/cpp/CROSSTOOL
+++ b/tools/cpp/CROSSTOOL
@@ -22,6 +22,11 @@
   toolchain_identifier: "clang_linux_armhf"
 }
 
+default_toolchain {
+  cpu: "cortex-m4f"
+  toolchain_identifier: "cortex-m4f"
+}
+
 toolchain {
   abi_version: "armeabi-v7a"
   abi_libc_version: "armeabi-v7a"
@@ -781,3 +786,223 @@
     linker_flag: "-Wl,--gc-sections"
   }
 }
+
+toolchain {
+  abi_version: "cortex-m4f"
+  abi_libc_version: "cortex-m4f"
+  builtin_sysroot: ""
+  compiler: "gcc"
+  host_system_name: "local"
+  needsPic: false
+  supports_gold_linker: false
+  supports_incremental_linker: false
+  supports_fission: false
+  supports_interface_shared_objects: false
+  supports_normalizing_ar: false
+  supports_start_end_lib: false
+  supports_thin_archives: false
+  target_libc: "cortex-m4f"
+  target_cpu: "cortex-m4f"
+  target_system_name: "cortex-m4f"
+  toolchain_identifier: "cortex-m4f"
+
+  tool_path { name: "ar" path: "/usr/bin/arm-none-eabi-ar" }
+  tool_path { name: "compat-ld" path: "/usr/bin/arm-none-eabi-ld" }
+  tool_path { name: "cpp" path: "/usr/bin/arm-none-eabi-cpp" }
+  tool_path { name: "dwp" path: "/usr/bin/arm-none-eabi-dwp" }
+  tool_path { name: "gcc" path: "/usr/bin/arm-none-eabi-gcc" }
+  tool_path { name: "gcov" path: "/usr/bin/arm-none-eabi-gcov" }
+  # C(++) compiles invoke the compiler (as that is the one knowing where
+  # to find libraries), but we provide LD so other rules can invoke the linker.
+  tool_path { name: "ld" path: "/usr/bin/arm-none-eabi-ld" }
+  tool_path { name: "nm" path: "/usr/bin/arm-none-eabi-nm" }
+  tool_path { name: "objcopy" path: "/usr/bin/arm-none-eabi-objcopy" }
+  objcopy_embed_flag: "-I"
+  objcopy_embed_flag: "binary"
+  tool_path { name: "objdump" path: "/usr/bin/arm-none-eabi-objdump" }
+  tool_path { name: "strip" path: "/usr/bin/arm-none-eabi-strip" }
+  linking_mode_flags { mode: FULLY_STATIC }
+
+  # TODO(bazel-team): In theory, the path here ought to exactly match the path
+  # used by gcc. That works because bazel currently doesn't track files at
+  # absolute locations and has no remote execution, yet. However, this will need
+  # to be fixed, maybe with auto-detection?
+  cxx_builtin_include_directory: '/usr/lib/gcc/arm-none-eabi/4.8/include'
+  cxx_builtin_include_directory: '/usr/lib/gcc/arm-none-eabi/4.8/include-fixed'
+  cxx_builtin_include_directory: '/usr/lib/arm-none-eabi/include'
+  cxx_builtin_include_directory: '/usr/include/newlib',
+
+  feature {
+    name: "dbg"
+    implies: "all_modes"
+    flag_set {
+      action: "preprocess-assemble"
+      action: "c-compile"
+      action: "c++-compile"
+      action: "c++-header-parsing"
+      action: "c++-header-preprocessing"
+      action: "c++-module-compile"
+      flag_group {
+        flag: "-fno-omit-frame-pointer"
+      }
+    }
+  }
+
+  feature {
+    name: "opt"
+    implies: "all_modes"
+  }
+  feature {
+    name: "fastbuild"
+    implies: "all_modes"
+  }
+
+  feature {
+    name: "all_modes"
+    flag_set {
+      action: "preprocess-assemble"
+      action: "assemble"
+      action: "c-compile"
+      flag_group {
+        flag: "--std=gnu99"
+      }
+    }
+    flag_set {
+      action: "c++-compile"
+      action: "c++-header-parsing"
+      action: "c++-header-preprocessing"
+      action: "c++-module-compile"
+      flag_group {
+        flag: "--std=gnu++11"
+        flag: "-fno-exceptions"
+        flag: "-fno-rtti"
+      }
+    }
+  }
+
+  # Anticipated future default.
+  # This makes GCC and Clang do what we want when called through symlinks.
+  unfiltered_cxx_flag: "-no-canonical-prefixes"
+  linker_flag: "-no-canonical-prefixes"
+
+  # Things that the code wants defined.
+  compiler_flag: "-D__STDC_FORMAT_MACROS"
+  compiler_flag: "-D__STDC_CONSTANT_MACROS"
+  compiler_flag: "-D__STDC_LIMIT_MACROS"
+  compiler_flag: "-D__MK64FX512__"
+  compiler_flag: "-DF_CPU=120000000"
+  compiler_flag: "-Wl,--gc-sections"
+
+  # Make C++ compilation deterministic. Use linkstamping instead of these
+  # compiler symbols.
+  unfiltered_cxx_flag: "-Wno-builtin-macro-redefined"
+  unfiltered_cxx_flag: "-D__DATE__=\"redacted\""
+  unfiltered_cxx_flag: "-D__TIMESTAMP__=\"redacted\""
+  unfiltered_cxx_flag: "-D__TIME__=\"redacted\""
+
+  # Security hardening on by default.
+  # Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases.
+  # We need to undef it before redefining it as some distributions now have
+  # it enabled by default.
+  compiler_flag: "-fstack-protector"
+  compiler_flag: "-mcpu=cortex-m4"
+  compiler_flag: "-mfpu=fpv4-sp-d16"
+  compiler_flag: "-mthumb"
+  compiler_flag: "-mfloat-abi=hard"
+  compiler_flag: "-fno-strict-aliasing"
+  linker_flag: "-mcpu=cortex-m4"
+  linker_flag: "-mfpu=fpv4-sp-d16"
+  linker_flag: "-mthumb"
+  linker_flag: "-mfloat-abi=hard"
+  linker_flag: "-fno-strict-aliasing"
+  linker_flag: "--specs=nano.specs"
+
+  # Pretty much everything needs this, including parts of the glibc STL...
+  linker_flag: "-lgcc"
+  linker_flag: "-lstdc++"
+  linker_flag: "-lm"
+  linker_flag: "-lc"
+  linker_flag: "-Tmotors/core/mk64fx512.ld"
+
+  compiler_flag: "-fmessage-length=80"
+
+  compiler_flag: "-Wall"
+  compiler_flag: "-Wextra"
+  compiler_flag: "-Wswitch-enum"
+  compiler_flag: "-Wpointer-arith"
+  compiler_flag: "-Wcast-qual"
+  compiler_flag: "-Wwrite-strings"
+  compiler_flag: "-Wtype-limits"
+  compiler_flag: "-Wsign-compare"
+  compiler_flag: "-Wformat=2"
+  compiler_flag: "-Werror"
+  compiler_flag: "-Wstrict-aliasing=2"
+
+  # Be annoying about using doubles places we probably didn't mean to, because
+  # the FPU only does single-precision.
+  compiler_flag: "-Wdouble-promotion"
+
+  # Don't use temp files while compiling.
+  compiler_flag: "-pipe"
+
+  # Stamp the binary with a unique identifier.
+  # TODO(austin): Put these back in.
+  #linker_flag: "-Wl,--build-id=md5"
+  #linker_flag: "-Wl,--hash-style=gnu"
+
+  # Enable debug symbols.
+  compiler_flag: "-g"
+
+  # Commons symbols are weird and not what we want, so just give multiple
+  # declaration errors instead.
+  compiler_flag: "-fno-common"
+
+  compilation_mode_flags {
+    mode: OPT
+
+    # Freescale recommends this combination for reducing cycle count.
+    # http://www.nxp.com/assets/documents/data/en/application-notes/AN4808.pdf
+    compiler_flag: "-O2"
+    compiler_flag: "-finline-functions"
+
+    # This is definitely worth it for us. It makes the FPU a lot more useful,
+    # especially with complex arithmetic, which matters a lot.
+    compiler_flag: "-ffast-math"
+
+    # It seems like this is a good idea, at least for the number crunching code.
+    # Might want to look into moving it to copts on specific rules if the code
+    # size increase becomes a problem.
+    compiler_flag: "-funroll-loops"
+
+    # Disable assertions
+    compiler_flag: "-DNDEBUG"
+
+    # Removal of unused code and data at link time (can this increase binary size in some cases?).
+    compiler_flag: "-ffunction-sections"
+    #compiler_flag: "-fdata-sections"
+    linker_flag: "-Wl,--gc-sections"
+  }
+
+  feature {
+    name: 'include_paths'
+    flag_set {
+      action: 'preprocess-assemble'
+      action: 'c-compile'
+      action: 'c++-compile'
+      action: 'c++-header-parsing'
+      action: 'c++-header-preprocessing'
+      action: 'c++-module-compile'
+      flag_group {
+        flag: '-iquote'
+        flag: '%{quote_include_paths}'
+      }
+      flag_group {
+        flag: '-I%{include_paths}'
+      }
+      flag_group {
+        flag: '-iquote'
+        flag: '%{system_include_paths}'
+      }
+    }
+  }
+}