pw_toolchain: ARM clang toolchain
Initial work to get clang building ARM firmware.
Current state:
- Does not work on Windows; no clang toolchain yet.
- Almost all tests pass.
- FreeListHeap tests that don't zero-initilize the buffer fail in qemu
and crash on STM32F429I-DISC1. (pwbug/315)
Change-Id: I39559511f19571c26930a868406d6ee1b514c412
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/13144
Commit-Queue: Armando Montanez <amontanez@google.com>
Reviewed-by: Keir Mierle <keir@google.com>
Reviewed-by: Ewout van Bekkum <ewout@google.com>
Reviewed-by: Alexei Frolov <frolv@google.com>
Pigweed-Auto-Submit: Armando Montanez <amontanez@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 0c6414f..06e411d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -111,8 +111,14 @@
}
}
-_build_pigweed_default_at_all_optimization_levels("qemu") {
- toolchain_prefix = "$dir_pigweed/targets/lm3s6965evb-qemu:lm3s6965evb_qemu_"
+_build_pigweed_default_at_all_optimization_levels("qemu_gcc") {
+ toolchain_prefix =
+ "$dir_pigweed/targets/lm3s6965evb-qemu:lm3s6965evb_qemu_gcc_"
+}
+
+_build_pigweed_default_at_all_optimization_levels("qemu_clang") {
+ toolchain_prefix =
+ "$dir_pigweed/targets/lm3s6965evb-qemu:lm3s6965evb_qemu_clang_"
}
group("docs") {
@@ -148,6 +154,7 @@
"$dir_pw_rpc/py",
"$dir_pw_status/py",
"$dir_pw_tokenizer/py",
+ "$dir_pw_toolchain/py",
"$dir_pw_trace/py",
"$dir_pw_trace_tokenized/py",
"$dir_pw_unit_test/py",
@@ -264,7 +271,6 @@
# Targets for all module unit test groups.
pw_test_group("pw_module_tests") {
group_deps = [
- "$dir_pw_allocator:tests",
"$dir_pw_assert:tests",
"$dir_pw_base64:tests",
"$dir_pw_blob_store:tests",
@@ -306,6 +312,19 @@
"$dir_pw_varint:tests",
]
+ # TODO(pwbug/315): Fix pw_allocator tests on ARM Clang build.
+ _qemu_toolchains = [
+ "lm3s6965evb_qemu_clang_debug",
+ "lm3s6965evb_qemu_clang_size_optimized",
+ "lm3s6965evb_qemu_clang_speed_optimized",
+ ]
+ _toolchain_is_qemu_clang =
+ _qemu_toolchains + [ get_label_info(current_toolchain, "name") ] -
+ [ get_label_info(current_toolchain, "name") ] != _qemu_toolchains
+ if (!_toolchain_is_qemu_clang) {
+ group_deps += [ "$dir_pw_allocator:tests" ]
+ }
+
if (defined(pw_toolchain_SCOPE.is_host_toolchain) &&
pw_toolchain_SCOPE.is_host_toolchain) {
# TODO(pwbug/196): KVS tests are not compatible with device builds as they
diff --git a/pw_allocator/block_test.cc b/pw_allocator/block_test.cc
index fb918ba..f70c826 100644
--- a/pw_allocator/block_test.cc
+++ b/pw_allocator/block_test.cc
@@ -68,7 +68,7 @@
alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(kSplitN, &next_block);
@@ -101,7 +101,7 @@
uintptr_t split_len = split_addr - (uintptr_t)&bytes;
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(kSplitN, &next_block);
@@ -130,10 +130,10 @@
constexpr size_t kN = 1024;
constexpr size_t kSplit1 = 512;
constexpr size_t kSplit2 = 256;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* block2 = nullptr;
block->Split(kSplit1, &block2);
@@ -151,10 +151,10 @@
constexpr size_t kN = 1024;
constexpr size_t kSplitN =
kN - sizeof(Block) - 2 * PW_ALLOCATOR_POISON_OFFSET - 1;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(kSplitN, &next_block);
@@ -166,10 +166,10 @@
TEST(Block, MustProvideNextBlockPointer) {
constexpr size_t kN = 1024;
constexpr size_t kSplitN = kN - sizeof(Block) - 1;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
auto status = block->Split(kSplitN, nullptr);
EXPECT_EQ(status, Status::InvalidArgument());
@@ -178,10 +178,10 @@
TEST(Block, CannotMakeBlockLargerInSplit) {
// Ensure that we can't ask for more space than the block actually has...
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(block->InnerSize() + 1, &next_block);
@@ -192,10 +192,10 @@
TEST(Block, CannotMakeSecondBlockLargerInSplit) {
// Ensure that the second block in split is at least of the size of header.
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(
@@ -209,10 +209,10 @@
TEST(Block, CanMakeZeroSizeFirstBlock) {
// This block does support splitting with zero payload size.
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(0, &next_block);
@@ -224,10 +224,10 @@
TEST(Block, CanMakeZeroSizeSecondBlock) {
// Likewise, the split block can be zero-width.
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
auto status = block->Split(
@@ -243,7 +243,7 @@
alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
block->MarkUsed();
EXPECT_EQ(block->Used(), true);
@@ -261,7 +261,7 @@
alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
block->MarkUsed();
@@ -276,10 +276,10 @@
constexpr size_t kN = 1024;
constexpr size_t kSplit1 = 512;
constexpr size_t kSplit2 = 256;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* block2 = nullptr;
block->Split(kSplit1, &block2);
@@ -302,12 +302,12 @@
TEST(Block, CannotMergeWithFirstOrLastBlock) {
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
// Do a split, just to sanity check that the checks on Next/Prev are
// different...
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
block->Split(512, &next_block);
@@ -318,12 +318,12 @@
TEST(Block, CannotMergeUsedBlock) {
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
// Do a split, just to sanity check that the checks on Next/Prev are
// different...
Block* block = nullptr;
- Block::Init(std::span(bytes, kN), &block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &block), OkStatus());
Block* next_block = nullptr;
block->Split(512, &next_block);
@@ -335,10 +335,10 @@
TEST(Block, CanCheckValidBlock) {
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* first_block = nullptr;
- Block::Init(std::span(bytes, kN), &first_block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &first_block), OkStatus());
Block* second_block = nullptr;
first_block->Split(512, &second_block);
@@ -353,10 +353,10 @@
TEST(Block, CanCheckInalidBlock) {
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* first_block = nullptr;
- Block::Init(std::span(bytes, kN), &first_block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &first_block), OkStatus());
Block* second_block = nullptr;
first_block->Split(512, &second_block);
@@ -391,10 +391,10 @@
TEST(Block, CanPoisonBlock) {
#if defined(PW_ALLOCATOR_POISON_ENABLE) && PW_ALLOCATOR_POISON_ENABLE
constexpr size_t kN = 1024;
- byte bytes[kN];
+ alignas(Block*) byte bytes[kN];
Block* first_block = nullptr;
- Block::Init(std::span(bytes, kN), &first_block);
+ EXPECT_EQ(Block::Init(std::span(bytes, kN), &first_block), OkStatus());
Block* second_block = nullptr;
first_block->Split(512, &second_block);
diff --git a/pw_boot_armv7m/basic_armv7m.ld b/pw_boot_armv7m/basic_armv7m.ld
index 7ca09de..e758aa2 100644
--- a/pw_boot_armv7m/basic_armv7m.ld
+++ b/pw_boot_armv7m/basic_armv7m.ld
@@ -179,6 +179,12 @@
. = _stack_high;
pw_boot_stack_high_addr = .;
} >RAM
+
+ /* Discard unwind info. */
+ .ARM.extab 0x0 (INFO) :
+ {
+ KEEP(*(.ARM.extab*))
+ }
}
/* Symbols used by core_init.c: */
diff --git a/pw_boot_armv7m/public/pw_boot_armv7m/boot.h b/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
index 9b683d5..88e11dc 100644
--- a/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
+++ b/pw_boot_armv7m/public/pw_boot_armv7m/boot.h
@@ -85,7 +85,7 @@
// (which usually points to Reset_Handler) must be set to point to this
// function. This function is implemented by pw_boot_armv7m, and does early
// memory initialization.
-PW_NO_PROLOGUE void pw_boot_Entry();
+PW_NO_RETURN void pw_boot_Entry();
// pw_boot hook: Before static memory is initialized (user supplied)
//
diff --git a/pw_cpu_exception_cortex_m/exception_entry_test.cc b/pw_cpu_exception_cortex_m/exception_entry_test.cc
index 842bcd4..f6c47c3 100644
--- a/pw_cpu_exception_cortex_m/exception_entry_test.cc
+++ b/pw_cpu_exception_cortex_m/exception_entry_test.cc
@@ -275,7 +275,7 @@
// clang-format off
: /*output=*/[local_msp]"=r"(local_msp), [local_psp]"=r"(local_psp)
: /*input=*/[magic]"r"(magic)
- : /*clobbers=*/"r4", "r5", "r11", "memory"
+ : /*clobbers=*/"r0", "r4", "r5", "r11", "memory"
// clang-format on
);
@@ -314,7 +314,7 @@
// clang-format off
: /*output=*/[local_msp]"=r"(local_msp), [local_psp]"=r"(local_psp)
: /*input=*/[magic]"r"(magic)
- : /*clobbers=*/"r4", "r5", "r11", "memory"
+ : /*clobbers=*/"r0", "r4", "r5", "r11", "memory"
// clang-format on
);
@@ -567,6 +567,14 @@
trigger_nested_fault = false;
BeginNestedFaultTest();
}
+ // Logging may require FPU (fpu instructions in vsnprintf()), so re-enable
+ // asap.
+ EnableFpu();
+
+ // Disable traps. Must be disabled before EXPECT, as memcpy() can do unaligned
+ // operations.
+ cortex_m_ccr &= ~kUnalignedTrapEnableMask;
+ cortex_m_ccr &= ~kDivByZeroTrapEnableMask;
// Clear HFSR forced (nested) hard fault mask if set. This will only be
// set by the nested fault test.
@@ -582,7 +590,6 @@
sizeof(pw_cpu_exception_State));
// Disable unaligned read/write trapping to "handle" exception.
- cortex_m_ccr &= ~kUnalignedTrapEnableMask;
cortex_m_cfsr = kUnalignedFaultMask;
exceptions_handled++;
return;
@@ -602,7 +609,6 @@
}
// Disable divide-by-zero trapping to "handle" exception.
- cortex_m_ccr &= ~kDivByZeroTrapEnableMask;
cortex_m_cfsr = kDivByZeroFaultMask;
exceptions_handled++;
return;
diff --git a/pw_kvs/size_report/base.cc b/pw_kvs/size_report/base.cc
index 9a675ba..be6d89c 100644
--- a/pw_kvs/size_report/base.cc
+++ b/pw_kvs/size_report/base.cc
@@ -31,7 +31,7 @@
PW_LOG_INFO("We care about optimizing: %d", *unoptimizable);
void* result =
- std::memset((void*)working_buffer, sizeof(working_buffer), 0x55);
+ std::memset((void*)working_buffer, 0x55, sizeof(working_buffer));
is_set = (result != nullptr);
return 0;
}
diff --git a/pw_kvs/size_report/base_with_only_flash.cc b/pw_kvs/size_report/base_with_only_flash.cc
index fe290ad..bb7c182 100644
--- a/pw_kvs/size_report/base_with_only_flash.cc
+++ b/pw_kvs/size_report/base_with_only_flash.cc
@@ -36,12 +36,12 @@
PW_LOG_INFO("We care about optimizing: %d", *unoptimizable);
void* result =
- std::memset((void*)working_buffer, sizeof(working_buffer), 0x55);
+ std::memset((void*)working_buffer, 0x55, sizeof(working_buffer));
is_set = (result != nullptr);
test_partition.Erase();
- std::memset((void*)working_buffer, sizeof(working_buffer), 0x55);
+ std::memset((void*)working_buffer, 0x55, sizeof(working_buffer));
test_partition.Write(0, std::as_bytes(std::span(working_buffer)));
diff --git a/pw_kvs/size_report/with_kvs.cc b/pw_kvs/size_report/with_kvs.cc
index 209cfd3..fc99e55 100644
--- a/pw_kvs/size_report/with_kvs.cc
+++ b/pw_kvs/size_report/with_kvs.cc
@@ -46,7 +46,7 @@
PW_LOG_INFO("We care about optimizing: %d", *unoptimizable);
void* result =
- std::memset((void*)working_buffer, sizeof(working_buffer), 0x55);
+ std::memset((void*)working_buffer, 0x55, sizeof(working_buffer));
is_set = (result != nullptr);
kvs.Init();
diff --git a/pw_malloc_freelist/freelist_malloc.cc b/pw_malloc_freelist/freelist_malloc.cc
index 8797295..6b5ecfe 100644
--- a/pw_malloc_freelist/freelist_malloc.cc
+++ b/pw_malloc_freelist/freelist_malloc.cc
@@ -17,13 +17,13 @@
#include "pw_allocator/freelist_heap.h"
#include "pw_boot_armv7m/boot.h"
#include "pw_malloc/malloc.h"
+#include "pw_preprocessor/compiler.h"
#include "pw_preprocessor/util.h"
namespace {
std::aligned_storage_t<sizeof(pw::allocator::FreeListHeapBuffer<>),
alignof(pw::allocator::FreeListHeapBuffer<>)>
buf;
-std::span<std::byte> pw_allocator_freelist_raw_heap;
} // namespace
pw::allocator::FreeListHeapBuffer<>* pw_freelist_heap;
diff --git a/pw_polyfill/standard_library_public/pw_polyfill/standard_library/namespace.h b/pw_polyfill/standard_library_public/pw_polyfill/standard_library/namespace.h
index abaab09..6c6bec5 100644
--- a/pw_polyfill/standard_library_public/pw_polyfill/standard_library/namespace.h
+++ b/pw_polyfill/standard_library_public/pw_polyfill/standard_library/namespace.h
@@ -13,9 +13,9 @@
// the License.
#pragma once
-// Clang uses a special namespace for standard library headers. Use this
+// libc++ uses a special namespace for standard library headers. Use this
// namespace via the defines in <__config>.
-#if defined(__clang__) && __has_include(<__config>)
+#if defined(_LIBCPP_VERSION) && __has_include(<__config>)
#include <__config>
@@ -27,11 +27,11 @@
#define _PW_POLYFILL_BEGIN_NAMESPACE_STD namespace std {
#define _PW_POLYFILL_END_NAMESPACE_STD } // namespace std
-// Cannot compile with Clang / libc++ without the <__config> header.
-#ifdef __clang__
+// Cannot compile when using libc++ without the <__config> header.
+#ifdef _LIBCPP_VERSION
static_assert(
false,
- "Compiling with Clang, but the <__config> header is not available. "
+ "Compiling against libc++, but the <__config> header is not available. "
"The <__config> header provides various _LIBCPP defines used internally "
"by libc++. pw_polyfill needs this header for the "
"_LIBCPP_BEGIN_NAMESPACE_STD and _LIBCPP_END_NAMESPACE_STD macros, which "
@@ -43,6 +43,6 @@
"<__config>, in which this file should be updated to properly "
"set _PW_POLYFILL_BEGIN_NAMESPACE_STD and _PW_POLYFILL_END_NAMESPACE_STD.");
-#endif // __clang__
+#endif // _LIBCPP_VERSION
-#endif // defined(__clang__) && __has_include(<__config>)
+#endif // defined(_LIBCPP_VERSION) && __has_include(<__config>)
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index d1df037..f77d262 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -137,7 +137,13 @@
@filter_paths(endswith=_BUILD_EXTENSIONS)
def gn_qemu_build(ctx: PresubmitContext):
build.gn_gen(ctx.root, ctx.output_dir)
- build.ninja(ctx.output_dir, *_at_all_optimization_levels('qemu'))
+ build.ninja(ctx.output_dir, *_at_all_optimization_levels('qemu_gcc'))
+
+
+@filter_paths(endswith=_BUILD_EXTENSIONS)
+def gn_qemu_clang_build(ctx: PresubmitContext):
+ build.gn_gen(ctx.root, ctx.output_dir)
+ build.ninja(ctx.output_dir, *_at_all_optimization_levels('qemu_clang'))
def gn_docs_build(ctx: PresubmitContext):
@@ -501,8 +507,6 @@
BROKEN = (
# TODO(pwbug/45): Remove clang-tidy from BROKEN when it passes.
clang_tidy,
- # QEMU build. Currently doesn't have test runners.
- gn_qemu_build,
# Build that attempts to duplicate the build OSS-Fuzz does. Currently
# failing.
oss_fuzz_build,
@@ -538,6 +542,9 @@
# On Mac OS, system 'gcc' is a symlink to 'clang' by default, so skip GCC
# host builds on Mac for now.
gn_gcc_build if sys.platform != 'darwin' else (),
+ # Windows doesn't support QEMU yet.
+ gn_qemu_build if sys.platform != 'win32' else (),
+ gn_qemu_clang_build if sys.platform != 'win32' else (),
source_is_in_build_files,
python_checks,
build_env_setup,
diff --git a/pw_sys_io_baremetal_lm3s6965evb/sys_io_baremetal.cc b/pw_sys_io_baremetal_lm3s6965evb/sys_io_baremetal.cc
index 1c1ccbc..ca70d97 100644
--- a/pw_sys_io_baremetal_lm3s6965evb/sys_io_baremetal.cc
+++ b/pw_sys_io_baremetal_lm3s6965evb/sys_io_baremetal.cc
@@ -25,10 +25,7 @@
// UART status flags.
constexpr uint32_t kTxFifoEmptyMask = 0b10000000;
-constexpr uint32_t kTxFifoFullMask = 0b1000000;
constexpr uint32_t kRxFifoFullMask = 0b100000;
-constexpr uint32_t kRxFifoEmptyMask = 0b10000;
-constexpr uint32_t kTxBusyMask = 0b1000;
// UART line control flags.
// Default: 8n1
diff --git a/pw_sys_io_baremetal_stm32f429/sys_io_baremetal.cc b/pw_sys_io_baremetal_stm32f429/sys_io_baremetal.cc
index 915fd67..b5b1792 100644
--- a/pw_sys_io_baremetal_stm32f429/sys_io_baremetal.cc
+++ b/pw_sys_io_baremetal_stm32f429/sys_io_baremetal.cc
@@ -61,25 +61,21 @@
};
// Constants related to GPIO mode register masks.
-constexpr uint32_t kGpioPortModeMask = 0x3u;
constexpr uint32_t kGpio9PortModePos = 18;
constexpr uint32_t kGpio10PortModePos = 20;
constexpr uint32_t kGpioPortModeAlternate = 2;
// Constants related to GPIO port speed register masks.
-constexpr uint32_t kGpioPortSpeedMask = 0x3u;
constexpr uint32_t kGpio9PortSpeedPos = 18;
constexpr uint32_t kGpio10PortSpeedPos = 20;
constexpr uint32_t kGpioSpeedVeryHigh = 3;
// Constants related to GPIO pull up/down resistor type masks.
-constexpr uint32_t kGpioPullTypeMask = 0x3u;
constexpr uint32_t kGpio9PullTypePos = 18;
constexpr uint32_t kGpio10PullTypePos = 20;
constexpr uint32_t kPullTypePullUp = 1;
// Constants related to GPIO port speed register masks.
-constexpr uint32_t kGpioAltModeMask = 0x3u;
constexpr uint32_t kGpio9AltModeHighPos = 4;
constexpr uint32_t kGpio10AltModeHighPos = 8;
diff --git a/pw_toolchain/arm_clang/BUILD.gn b/pw_toolchain/arm_clang/BUILD.gn
new file mode 100644
index 0000000..d4b73a9
--- /dev/null
+++ b/pw_toolchain/arm_clang/BUILD.gn
@@ -0,0 +1,53 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+import("clang_config.gni")
+
+cortex_m_common_flags = [
+ "-mabi=aapcs",
+ "-mthumb",
+]
+
+cortex_m_software_fpu_flags = [ "-mfloat-abi=soft" ]
+
+cortex_m_hardware_fpu_flags = [
+ "-mfloat-abi=hard",
+ "-mfpu=fpv4-sp-d16",
+
+ # Used by some pigweed tests/targets to correctly handle hardware FPU
+ # behavior.
+ "-DPW_ARMV7M_ENABLE_FPU=1",
+]
+
+config("enable_float_printf") {
+ ldflags = [ "-Wl,-u_printf_float" ]
+}
+
+pw_clang_arm_config("cortex_m3") {
+ cflags = [ "-mcpu=cortex-m3" ]
+ cflags += cortex_m_common_flags
+ cflags += cortex_m_software_fpu_flags
+ asmflags = cflags
+ ldflags = cflags
+}
+
+pw_clang_arm_config("cortex_m4f") {
+ cflags = [ "-mcpu=cortex-m4" ]
+ cflags += cortex_m_common_flags
+ cflags += cortex_m_hardware_fpu_flags
+ asmflags = cflags
+ ldflags = cflags
+}
diff --git a/pw_toolchain/arm_clang/clang_config.gni b/pw_toolchain/arm_clang/clang_config.gni
new file mode 100644
index 0000000..2c71a2f
--- /dev/null
+++ b/pw_toolchain/arm_clang/clang_config.gni
@@ -0,0 +1,82 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+_script_path = rebase_path("../py/pw_toolchain/clang_arm_toolchain.py")
+
+# This template generates a config that can be used to target ARM cores using
+# a clang compiler.
+#
+# Clang isn't a plug-and-play experience for Cortex-M baremetal targets; it's
+# missing C runtime libraries, C/C++ standard libraries, and a few other
+# things. This template uses the provided cflags, asmflags, ldflags, etc. to
+# generate a config that pulls the missing components from an arm-none-eabi-gcc
+# compiler on the system PATH. The end result is a clang-based compiler that
+# pulls in gcc-provided headers and libraries to complete the toolchain.
+#
+# Args:
+# - asmflags, cflags, cflags_c, cflags_cc, ldflags: These flags are used to
+# locate the correct architecture-specific libraries/headers. To
+# properly drive the script, provide all architecture flags (e.g. -mcpu,
+# -mabi, -mthumb, -mfloat-abi, -mfpu) in at least one of these
+# variables.
+#
+# Generated targets:
+# - $target_name: The final config to use with your clang toolchain.
+template("pw_clang_arm_config") {
+ config(target_name) {
+ # Pull all the compiler flags into a single list.
+ _compiler_flags = []
+ forward_variables_from(invoker, "*")
+ if (defined(asmflags)) {
+ _compiler_flags += asmflags
+ } else {
+ asmflags = []
+ }
+ if (defined(cflags)) {
+ _compiler_flags += cflags
+ } else {
+ cflags = []
+ }
+ if (defined(cflags_c)) {
+ _compiler_flags += cflags_c
+ } else {
+ cflags_c = []
+ }
+ if (defined(cflags_cc)) {
+ _compiler_flags += cflags_cc
+ } else {
+ cflags_cc = []
+ }
+ if (defined(ldflags)) {
+ _compiler_flags += ldflags
+ } else {
+ ldflags = []
+ }
+
+ # Invoke the script that will generate clang flags based on the current
+ # compiler version and desired arch.
+ _script_flags = [
+ "--gn-scope",
+ "--cflags",
+ "--ldflags",
+ "--",
+ ]
+ _script_flags += _compiler_flags
+ _arm_flags = exec_script(_script_path, _script_flags, "scope")
+
+ cflags += _arm_flags.cflags
+ ldflags += _arm_flags.cflags
+ ldflags += _arm_flags.ldflags
+ }
+}
diff --git a/pw_toolchain/arm_clang/toolchains.gni b/pw_toolchain/arm_clang/toolchains.gni
new file mode 100644
index 0000000..91aea25
--- /dev/null
+++ b/pw_toolchain/arm_clang/toolchains.gni
@@ -0,0 +1,115 @@
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+import("//build_overrides/pigweed.gni")
+
+# Specifies the tools used by host Clang toolchains.
+_arm_clang_toolchain = {
+ # Note: On macOS, there is no "llvm-ar", only "ar", which happens to be LLVM
+ # ar. This should get updated for linux systems.
+ ar = "ar"
+ cc = "clang"
+ cxx = "clang++"
+
+ link_whole_archive = true
+}
+
+# Configs specific to different architectures.
+_cortex_m3 = [ "$dir_pw_toolchain/arm_clang:cortex_m3" ]
+
+_cortex_m4 = [ "$dir_pw_toolchain/arm_clang:cortex_m4" ]
+
+_cortex_m4f = [ "$dir_pw_toolchain/arm_clang:cortex_m4f" ]
+
+# Describes ARM clang toolchains for specific targets.
+pw_toolchain_arm_clang = {
+ cortex_m3_debug = {
+ name = "arm_clang_cortex_m3_debug"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m3 + [ "$dir_pw_build:optimize_debugging" ]
+ }
+ }
+ cortex_m3_speed_optimized = {
+ name = "arm_clang_cortex_m3_speed_optimized"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m3 + [ "$dir_pw_build:optimize_speed" ]
+ }
+ }
+ cortex_m3_size_optimized = {
+ name = "arm_clang_cortex_m3_size_optimized"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m3 + [ "$dir_pw_build:optimize_size" ]
+ }
+ }
+ cortex_m4_debug = {
+ name = "arm_clang_cortex_m4_debug"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m4 + [ "$dir_pw_build:optimize_debugging" ]
+ }
+ }
+ cortex_m4_speed_optimized = {
+ name = "arm_clang_cortex_m4_speed_optimized"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m4 + [ "$dir_pw_build:optimize_speed" ]
+ }
+ }
+ cortex_m4_size_optimized = {
+ name = "arm_clang_cortex_m4_size_optimized"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m4 + [ "$dir_pw_build:optimize_size" ]
+ }
+ }
+ cortex_m4f_debug = {
+ name = "arm_clang_cortex_m4f_debug"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m4f + [ "$dir_pw_build:optimize_debugging" ]
+ }
+ }
+ cortex_m4f_speed_optimized = {
+ name = "arm_clang_cortex_m4f_speed_optimized"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m4f + [ "$dir_pw_build:optimize_speed" ]
+ }
+ }
+ cortex_m4f_size_optimized = {
+ name = "arm_clang_cortex_m4f_size_optimized"
+ forward_variables_from(_arm_clang_toolchain, "*")
+ defaults = {
+ default_configs = _cortex_m4f + [ "$dir_pw_build:optimize_size" ]
+ }
+ }
+}
+
+# This list just contains the members of the above scope for convenience to make
+# it trivial to generate all the toolchains in this file via a
+# `generate_toolchains` target.
+pw_toolchain_arm_clang_list = [
+ pw_toolchain_arm_clang.cortex_m3_debug,
+ pw_toolchain_arm_clang.cortex_m3_speed_optimized,
+ pw_toolchain_arm_clang.cortex_m3_size_optimized,
+ pw_toolchain_arm_clang.cortex_m4_debug,
+ pw_toolchain_arm_clang.cortex_m4_speed_optimized,
+ pw_toolchain_arm_clang.cortex_m4_size_optimized,
+ pw_toolchain_arm_clang.cortex_m4f_debug,
+ pw_toolchain_arm_clang.cortex_m4f_speed_optimized,
+ pw_toolchain_arm_clang.cortex_m4f_size_optimized,
+]
diff --git a/pw_toolchain/py/BUILD.gn b/pw_toolchain/py/BUILD.gn
index 2bf0cd4..ee7df0a 100644
--- a/pw_toolchain/py/BUILD.gn
+++ b/pw_toolchain/py/BUILD.gn
@@ -21,6 +21,7 @@
sources = [
"pw_toolchain/__init__.py",
"pw_toolchain/bad_toolchain.py",
+ "pw_toolchain/clang_arm_toolchain.py",
"pw_toolchain/copy_with_metadata.py",
]
pylintrc = "$dir_pigweed/.pylintrc"
diff --git a/pw_toolchain/py/pw_toolchain/clang_arm_toolchain.py b/pw_toolchain/py/pw_toolchain/clang_arm_toolchain.py
new file mode 100644
index 0000000..7494727
--- /dev/null
+++ b/pw_toolchain/py/pw_toolchain/clang_arm_toolchain.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python3
+# Copyright 2021 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+"""Generates flags needed for an ARM build using clang.
+
+Using clang on Cortex-M cores isn't intuitive as the end-to-end experience isn't
+quite completely in LLVM. LLVM doesn't yet provide compatible C runtime
+libraries or C/C++ standard libraries. To work around this, this script pulls
+the missing bits from an arm-none-eabi-gcc compiler on the system path. This
+lets clang do the heavy lifting while only relying on some headers provided by
+newlib/arm-none-eabi-gcc in addition to a small assortment of needed libraries.
+
+To use this script, specify what flags you want from the script, and run with
+the required architecture flags like you would with gcc:
+
+ python -m pw_toolchain.clang_arm_toolchain --cflags -- -mthumb -mcpu=cortex-m3
+
+The script will then print out the additional flags you need to pass to clang to
+get a working build.
+"""
+
+import argparse
+import sys
+import subprocess
+
+from pathlib import Path
+from typing import List, Dict, Tuple
+
+_ARM_COMPILER_PREFIX = 'arm-none-eabi'
+_ARM_COMPILER_NAME = _ARM_COMPILER_PREFIX + '-gcc'
+
+
+def _parse_args() -> argparse.Namespace:
+ """Parses arguments for this script, splitting out the command to run."""
+
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ '--gn-scope',
+ action='store_true',
+ help=("Formats the output like a GN scope so it can be ingested by "
+ "exec_script()"))
+ parser.add_argument('--cflags',
+ action='store_true',
+ help=('Include necessary C flags in the output'))
+ parser.add_argument('--ldflags',
+ action='store_true',
+ help=('Include necessary linker flags in the output'))
+ parser.add_argument(
+ 'clang_flags',
+ nargs=argparse.REMAINDER,
+ help='Flags to pass to clang, which can affect library/include paths',
+ )
+ parsed_args = parser.parse_args()
+
+ assert parsed_args.clang_flags[0] == '--', 'arguments not correctly split'
+ parsed_args.clang_flags = parsed_args.clang_flags[1:]
+ return parsed_args
+
+
+def _compiler_info_command(print_command: str, cflags: List[str]) -> str:
+ command = [_ARM_COMPILER_NAME]
+ command.extend(cflags)
+ command.append(print_command)
+ result = subprocess.run(
+ command,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ )
+ result.check_returncode()
+ return result.stdout.decode().rstrip()
+
+
+def get_gcc_lib_dir(cflags: List[str]) -> Path:
+ return Path(_compiler_info_command('-print-libgcc-file-name',
+ cflags)).parent
+
+
+def get_compiler_info(cflags: List[str]) -> Dict[str, str]:
+ compiler_info: Dict[str, str] = {}
+ compiler_info['gcc_libs_dir'] = str(get_gcc_lib_dir(cflags))
+ compiler_info['sysroot'] = _compiler_info_command('-print-sysroot', cflags)
+ compiler_info['version'] = _compiler_info_command('-dumpversion', cflags)
+ compiler_info['multi_dir'] = _compiler_info_command(
+ '-print-multi-directory', cflags)
+ return compiler_info
+
+
+def get_cflags(compiler_info: Dict[str, str]):
+ # TODO(amontanez): Make newlib-nano optional.
+ cflags = [
+ # TODO(amontanez): For some reason, -stdlib++-isystem and
+ # -isystem-after work, but emit unused argument errors. This is the only
+ # way to let the build succeed.
+ '-Qunused-arguments',
+ # Disable all default libraries.
+ "-nodefaultlibs",
+ '--target=arm-none-eabi'
+ ]
+
+ # Add sysroot info.
+ cflags.extend((
+ '--sysroot=' + compiler_info['sysroot'],
+ '-isystem' +
+ str(Path(compiler_info['sysroot']) / 'include' / 'newlib-nano'),
+ # This must be included after Clang's builtin headers.
+ '-isystem-after' + str(Path(compiler_info['sysroot']) / 'include'),
+ '-stdlib++-isystem' + str(
+ Path(compiler_info['sysroot']) / 'include' / 'c++' /
+ compiler_info['version']),
+ '-isystem' + str(
+ Path(compiler_info['sysroot']) / 'include' / 'c++' /
+ compiler_info['version'] / _ARM_COMPILER_PREFIX /
+ compiler_info['multi_dir']),
+ ))
+
+ return cflags
+
+
+def get_crt_objs(compiler_info: Dict[str, str]) -> Tuple[str, ...]:
+ return (
+ str(Path(compiler_info['gcc_libs_dir']) / 'crtfastmath.o'),
+ str(Path(compiler_info['gcc_libs_dir']) / 'crti.o'),
+ str(Path(compiler_info['gcc_libs_dir']) / 'crtn.o'),
+ str(
+ Path(compiler_info['sysroot']) / 'lib' /
+ compiler_info['multi_dir'] / 'crt0.o'),
+ )
+
+
+def get_ldflags(compiler_info: Dict[str, str]) -> List[str]:
+ ldflags: List[str] = [
+ '-lnosys',
+ # Add library search paths.
+ '-L' + compiler_info['gcc_libs_dir'],
+ '-L' + str(
+ Path(compiler_info['sysroot']) / 'lib' /
+ compiler_info['multi_dir']),
+ # Add libraries to link.
+ '-lc_nano',
+ '-lm',
+ '-lgcc',
+ '-lstdc++_nano',
+ ]
+
+ # Add C runtime object files.
+ objs = get_crt_objs(compiler_info)
+ ldflags.extend(objs)
+
+ return ldflags
+
+
+def main(
+ cflags: bool,
+ ldflags: bool,
+ gn_scope: bool,
+ clang_flags: List[str],
+) -> int:
+ """Script entry point."""
+ compiler_info = get_compiler_info(clang_flags)
+ if ldflags:
+ ldflag_list = get_ldflags(compiler_info)
+
+ if cflags:
+ cflag_list = get_cflags(compiler_info)
+
+ if not gn_scope:
+ flags = []
+ if cflags:
+ flags.extend(cflag_list)
+ if ldflags:
+ flags.extend(ldflag_list)
+ print(' '.join(flags))
+ return 0
+
+ if cflags:
+ print('cflags = [')
+ for flag in cflag_list:
+ print(f' "{flag}",')
+ print(']')
+
+ if ldflags:
+ print('ldflags = [')
+ for flag in ldflag_list:
+ print(f' "{flag}",')
+ print(']')
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(**vars(_parse_args())))
diff --git a/targets/lm3s6965evb-qemu/BUILD b/targets/lm3s6965evb-qemu/BUILD
index 307d555..bb15e06 100644
--- a/targets/lm3s6965evb-qemu/BUILD
+++ b/targets/lm3s6965evb-qemu/BUILD
@@ -25,7 +25,7 @@
name = "pre_init",
srcs = [
"boot.cc",
- "vector_table.cc"
+ "vector_table.c"
],
deps = [
"//pw_boot_armv7m",
diff --git a/targets/lm3s6965evb-qemu/BUILD.gn b/targets/lm3s6965evb-qemu/BUILD.gn
index beb52f3..ebfa30f 100644
--- a/targets/lm3s6965evb-qemu/BUILD.gn
+++ b/targets/lm3s6965evb-qemu/BUILD.gn
@@ -32,7 +32,7 @@
deps = [ "$dir_pw_preprocessor" ]
sources = [
"boot.cc",
- "vector_table.cc",
+ "vector_table.c",
]
}
}
diff --git a/targets/lm3s6965evb-qemu/target_docs.rst b/targets/lm3s6965evb-qemu/target_docs.rst
index 6e8c12f..b5f5b84 100644
--- a/targets/lm3s6965evb-qemu/target_docs.rst
+++ b/targets/lm3s6965evb-qemu/target_docs.rst
@@ -12,12 +12,12 @@
Building
========
-To build for this Pigweed target, simply build the top-level "qemu" Ninja
+To build for this Pigweed target, simply build the top-level "qemu_gcc" Ninja
target.
.. code:: sh
- $ ninja -C out qemu
+ $ ninja -C out qemu_gcc
Testing
=======
diff --git a/targets/lm3s6965evb-qemu/target_toolchains.gni b/targets/lm3s6965evb-qemu/target_toolchains.gni
index b66ccd0..ce3c496 100644
--- a/targets/lm3s6965evb-qemu/target_toolchains.gni
+++ b/targets/lm3s6965evb-qemu/target_toolchains.gni
@@ -15,6 +15,7 @@
import("//build_overrides/pigweed.gni")
import("$dir_pw_sys_io/backend.gni")
+import("$dir_pw_toolchain/arm_clang/toolchains.gni")
import("$dir_pw_toolchain/arm_gcc/toolchains.gni")
_test_runner_script = "py/lm3s6965evb_qemu_utils/unit_test_runner.py"
@@ -63,11 +64,16 @@
current_os = ""
}
-_target_default_configs = [
+_gcc_target_default_configs = [
"$dir_pw_build:extra_strict_warnings",
"$dir_pw_toolchain/arm_gcc:enable_float_printf",
]
+_clang_target_default_configs = [
+ "$dir_pw_build:extra_strict_warnings",
+ "$dir_pw_toolchain/arm_clang:enable_float_printf",
+]
+
pw_target_toolchain_lm3s6965evb_qemu = {
_excluded_members = [
"defaults",
@@ -75,35 +81,68 @@
]
debug = {
- name = "lm3s6965evb_qemu_debug"
+ name = "lm3s6965evb_qemu_gcc_debug"
_toolchain_base = pw_toolchain_arm_gcc.cortex_m3_debug
forward_variables_from(_toolchain_base, "*", _excluded_members)
defaults = {
forward_variables_from(_toolchain_base.defaults, "*")
forward_variables_from(_target_config, "*")
- default_configs += _target_default_configs
+ default_configs += _gcc_target_default_configs
}
}
speed_optimized = {
- name = "lm3s6965evb_qemu_speed_optimized"
+ name = "lm3s6965evb_qemu_gcc_speed_optimized"
_toolchain_base = pw_toolchain_arm_gcc.cortex_m3_speed_optimized
forward_variables_from(_toolchain_base, "*", _excluded_members)
defaults = {
forward_variables_from(_toolchain_base.defaults, "*")
forward_variables_from(_target_config, "*")
- default_configs += _target_default_configs
+ default_configs += _gcc_target_default_configs
}
}
size_optimized = {
- name = "lm3s6965evb_qemu_size_optimized"
+ name = "lm3s6965evb_qemu_gcc_size_optimized"
_toolchain_base = pw_toolchain_arm_gcc.cortex_m3_size_optimized
forward_variables_from(_toolchain_base, "*", _excluded_members)
defaults = {
forward_variables_from(_toolchain_base.defaults, "*")
forward_variables_from(_target_config, "*")
- default_configs += _target_default_configs
+ default_configs += _gcc_target_default_configs
+ }
+ }
+
+ debug_clang = {
+ name = "lm3s6965evb_qemu_clang_debug"
+ _toolchain_base = pw_toolchain_arm_clang.cortex_m3_debug
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _clang_target_default_configs
+ }
+ }
+
+ speed_optimized_clang = {
+ name = "lm3s6965evb_qemu_clang_speed_optimized"
+ _toolchain_base = pw_toolchain_arm_clang.cortex_m3_speed_optimized
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _clang_target_default_configs
+ }
+ }
+
+ size_optimized_clang = {
+ name = "lm3s6965evb_qemu_clang_size_optimized"
+ _toolchain_base = pw_toolchain_arm_clang.cortex_m3_size_optimized
+ forward_variables_from(_toolchain_base, "*", _excluded_members)
+ defaults = {
+ forward_variables_from(_toolchain_base.defaults, "*")
+ forward_variables_from(_target_config, "*")
+ default_configs += _clang_target_default_configs
}
}
}
@@ -115,4 +154,7 @@
pw_target_toolchain_lm3s6965evb_qemu.debug,
pw_target_toolchain_lm3s6965evb_qemu.speed_optimized,
pw_target_toolchain_lm3s6965evb_qemu.size_optimized,
+ pw_target_toolchain_lm3s6965evb_qemu.debug_clang,
+ pw_target_toolchain_lm3s6965evb_qemu.speed_optimized_clang,
+ pw_target_toolchain_lm3s6965evb_qemu.size_optimized_clang,
]
diff --git a/targets/lm3s6965evb-qemu/vector_table.cc b/targets/lm3s6965evb-qemu/vector_table.c
similarity index 93%
rename from targets/lm3s6965evb-qemu/vector_table.cc
rename to targets/lm3s6965evb-qemu/vector_table.c
index 575a673..cbb5898 100644
--- a/targets/lm3s6965evb-qemu/vector_table.cc
+++ b/targets/lm3s6965evb-qemu/vector_table.c
@@ -12,14 +12,14 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_boot_armv7m/boot.h"
+#include <stdbool.h>
-namespace {
+#include "pw_boot_armv7m/boot.h"
// Default handler to insert into the ARMv7-M vector table (below).
// This function exists for convenience. If a device isn't doing what you
// expect, it might have hit a fault and ended up here.
-void DefaultFaultHandler(void) {
+static void DefaultFaultHandler(void) {
while (true) {
// Wait for debugger to attach.
}
@@ -44,7 +44,7 @@
// This address is NOT an interrupt handler/function pointer, it is simply
// the address that the main stack pointer should be initialized to. The
// value is reinterpret casted because it needs to be in the vector table.
- [0] = reinterpret_cast<InterruptHandler>(&pw_boot_stack_high_addr),
+ [0] = (InterruptHandler)(&pw_boot_stack_high_addr),
// Reset handler, dictates how to handle reset interrupt. This is the
// address that the Program Counter (PC) is initialized to at boot.
@@ -55,5 +55,3 @@
// HardFault handler.
[3] = DefaultFaultHandler,
};
-
-} // namespace
diff --git a/targets/stm32f429i-disc1/BUILD b/targets/stm32f429i-disc1/BUILD
index d88113b..b9cffcc 100644
--- a/targets/stm32f429i-disc1/BUILD
+++ b/targets/stm32f429i-disc1/BUILD
@@ -25,7 +25,7 @@
name = "pre_init",
srcs = [
"boot.cc",
- "vector_table.cc"
+ "vector_table.c"
],
deps = [
"//pw_boot_armv7m",
diff --git a/targets/stm32f429i-disc1/BUILD.gn b/targets/stm32f429i-disc1/BUILD.gn
index b148981..5527e65 100644
--- a/targets/stm32f429i-disc1/BUILD.gn
+++ b/targets/stm32f429i-disc1/BUILD.gn
@@ -43,7 +43,7 @@
]
sources = [
"boot.cc",
- "vector_table.cc",
+ "vector_table.c",
]
}
diff --git a/targets/lm3s6965evb-qemu/vector_table.cc b/targets/stm32f429i-disc1/vector_table.c
similarity index 93%
copy from targets/lm3s6965evb-qemu/vector_table.cc
copy to targets/stm32f429i-disc1/vector_table.c
index 575a673..cbb5898 100644
--- a/targets/lm3s6965evb-qemu/vector_table.cc
+++ b/targets/stm32f429i-disc1/vector_table.c
@@ -12,14 +12,14 @@
// License for the specific language governing permissions and limitations under
// the License.
-#include "pw_boot_armv7m/boot.h"
+#include <stdbool.h>
-namespace {
+#include "pw_boot_armv7m/boot.h"
// Default handler to insert into the ARMv7-M vector table (below).
// This function exists for convenience. If a device isn't doing what you
// expect, it might have hit a fault and ended up here.
-void DefaultFaultHandler(void) {
+static void DefaultFaultHandler(void) {
while (true) {
// Wait for debugger to attach.
}
@@ -44,7 +44,7 @@
// This address is NOT an interrupt handler/function pointer, it is simply
// the address that the main stack pointer should be initialized to. The
// value is reinterpret casted because it needs to be in the vector table.
- [0] = reinterpret_cast<InterruptHandler>(&pw_boot_stack_high_addr),
+ [0] = (InterruptHandler)(&pw_boot_stack_high_addr),
// Reset handler, dictates how to handle reset interrupt. This is the
// address that the Program Counter (PC) is initialized to at boot.
@@ -55,5 +55,3 @@
// HardFault handler.
[3] = DefaultFaultHandler,
};
-
-} // namespace
diff --git a/targets/stm32f429i-disc1/vector_table.cc b/targets/stm32f429i-disc1/vector_table.cc
deleted file mode 100644
index 575a673..0000000
--- a/targets/stm32f429i-disc1/vector_table.cc
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2020 The Pigweed Authors
-//
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-#include "pw_boot_armv7m/boot.h"
-
-namespace {
-
-// Default handler to insert into the ARMv7-M vector table (below).
-// This function exists for convenience. If a device isn't doing what you
-// expect, it might have hit a fault and ended up here.
-void DefaultFaultHandler(void) {
- while (true) {
- // Wait for debugger to attach.
- }
-}
-
-// This is the device's interrupt vector table. It's not referenced in any
-// code because the platform (STM32F4xx) expects this table to be present at the
-// beginning of flash. The exact address is specified in the pw_boot_armv7m
-// configuration as part of the target config.
-//
-// For more information, see ARMv7-M Architecture Reference Manual DDI 0403E.b
-// section B1.5.3.
-
-// This typedef is for convenience when building the vector table. With the
-// exception of SP_main (0th entry in the vector table), all the entries of the
-// vector table are function pointers.
-typedef void (*InterruptHandler)();
-
-PW_KEEP_IN_SECTION(".vector_table")
-const InterruptHandler vector_table[] = {
- // The starting location of the stack pointer.
- // This address is NOT an interrupt handler/function pointer, it is simply
- // the address that the main stack pointer should be initialized to. The
- // value is reinterpret casted because it needs to be in the vector table.
- [0] = reinterpret_cast<InterruptHandler>(&pw_boot_stack_high_addr),
-
- // Reset handler, dictates how to handle reset interrupt. This is the
- // address that the Program Counter (PC) is initialized to at boot.
- [1] = pw_boot_Entry,
-
- // NMI handler.
- [2] = DefaultFaultHandler,
- // HardFault handler.
- [3] = DefaultFaultHandler,
-};
-
-} // namespace