207 lines
5.8 KiB
Python
207 lines
5.8 KiB
Python
"""
|
|
ARM GCC compiler implementation for embedded targets.
|
|
|
|
This module implements the Compiler interface for ARM GCC toolchain,
|
|
used for cross-compiling to ARM Cortex-M processors (e.g., RP2040).
|
|
"""
|
|
|
|
from pathlib import Path
|
|
from typing import List, Optional
|
|
|
|
from .gcc import GCCCompiler
|
|
|
|
|
|
class ARMGCCCompiler(GCCCompiler):
|
|
"""
|
|
ARM GCC compiler implementation for embedded targets.
|
|
|
|
Uses the arm-none-eabi-gcc toolchain for bare-metal ARM development.
|
|
Extends GCCCompiler with ARM Cortex-M specific flags.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
executable: str = "arm-none-eabi-gcc",
|
|
cpu: str = "cortex-m0plus"
|
|
):
|
|
"""
|
|
Initialize ARM GCC compiler.
|
|
|
|
Args:
|
|
executable: ARM GCC executable (default: "arm-none-eabi-gcc")
|
|
cpu: Target CPU architecture (default: "cortex-m0plus" for RP2040)
|
|
"""
|
|
super().__init__(executable=executable, is_clang=False)
|
|
self.cpu = cpu
|
|
self.fpu = None
|
|
self.float_abi = None
|
|
self.additional_arch_flags = []
|
|
|
|
def set_cpu(self, cpu: str):
|
|
"""
|
|
Set target CPU architecture.
|
|
|
|
Args:
|
|
cpu: CPU name (e.g., "cortex-m0plus", "cortex-m4", "cortex-m7")
|
|
|
|
Returns:
|
|
Self for method chaining
|
|
"""
|
|
self.cpu = cpu
|
|
return self
|
|
|
|
def set_fpu(self, fpu: str, float_abi: str = "hard"):
|
|
"""
|
|
Set FPU configuration (for Cortex-M4F, M7, etc.).
|
|
|
|
Args:
|
|
fpu: FPU type (e.g., "fpv4-sp-d16", "fpv5-d16")
|
|
float_abi: Float ABI ("soft", "softfp", or "hard")
|
|
|
|
Returns:
|
|
Self for method chaining
|
|
"""
|
|
self.fpu = fpu
|
|
self.float_abi = float_abi
|
|
return self
|
|
|
|
def add_arch_flags(self, flags: List[str]):
|
|
"""
|
|
Add additional architecture-specific flags.
|
|
|
|
Args:
|
|
flags: List of flags to add
|
|
|
|
Returns:
|
|
Self for method chaining
|
|
"""
|
|
self.additional_arch_flags.extend(flags)
|
|
return self
|
|
|
|
def compile(
|
|
self,
|
|
source: Path,
|
|
output: Path,
|
|
*,
|
|
includes: Optional[List[Path]] = None,
|
|
defines: Optional[dict] = None,
|
|
flags: Optional[List[str]] = None,
|
|
generate_deps: bool = True,
|
|
is_test: bool = False
|
|
) -> Path:
|
|
"""
|
|
Compile using ARM GCC with embedded-specific flags.
|
|
|
|
Adds ARM Cortex-M architecture flags before calling parent compile.
|
|
"""
|
|
flags = flags or []
|
|
|
|
# ARM architecture flags (must come early)
|
|
arch_flags = [
|
|
f"-mcpu={self.cpu}",
|
|
"-mthumb", # Use Thumb instruction set
|
|
]
|
|
|
|
# FPU flags if configured
|
|
if self.fpu:
|
|
arch_flags.append(f"-mfpu={self.fpu}")
|
|
arch_flags.append(f"-mfloat-abi={self.float_abi}")
|
|
|
|
# Additional architecture flags
|
|
arch_flags.extend(self.additional_arch_flags)
|
|
|
|
# Prepend architecture flags (they need to come before other flags)
|
|
flags = arch_flags + flags
|
|
|
|
return super().compile(
|
|
source,
|
|
output,
|
|
includes=includes,
|
|
defines=defines,
|
|
flags=flags,
|
|
generate_deps=generate_deps,
|
|
is_test=is_test
|
|
)
|
|
|
|
def link(
|
|
self,
|
|
objects: List[Path],
|
|
output: Path,
|
|
*,
|
|
libraries: Optional[List[str]] = None,
|
|
library_paths: Optional[List[Path]] = None,
|
|
flags: Optional[List[str]] = None,
|
|
linker_script: Optional[Path] = None,
|
|
specs: Optional[str] = None
|
|
) -> Path:
|
|
"""
|
|
Link using ARM GCC with embedded-specific flags.
|
|
|
|
Args:
|
|
objects: Object files to link
|
|
output: Output executable path
|
|
libraries: Libraries to link
|
|
library_paths: Library search paths
|
|
flags: Additional linker flags
|
|
linker_script: Path to linker script (.ld file)
|
|
specs: Specs file (e.g., "nosys.specs", "nano.specs")
|
|
|
|
Returns:
|
|
Path to linked executable
|
|
"""
|
|
flags = flags or []
|
|
|
|
# ARM architecture flags (need to be passed to linker too)
|
|
arch_flags = [
|
|
f"-mcpu={self.cpu}",
|
|
"-mthumb",
|
|
]
|
|
|
|
# FPU flags
|
|
if self.fpu:
|
|
arch_flags.append(f"-mfpu={self.fpu}")
|
|
arch_flags.append(f"-mfloat-abi={self.float_abi}")
|
|
|
|
# Additional architecture flags
|
|
arch_flags.extend(self.additional_arch_flags)
|
|
|
|
# Linker script
|
|
if linker_script:
|
|
arch_flags.append(f"-T{linker_script}")
|
|
|
|
# Specs file (for selecting C library variant)
|
|
if specs:
|
|
arch_flags.append(f"--specs={specs}")
|
|
|
|
# Prepend architecture flags
|
|
flags = arch_flags + flags
|
|
|
|
return super().link(
|
|
objects,
|
|
output,
|
|
libraries=libraries,
|
|
library_paths=library_paths,
|
|
flags=flags
|
|
)
|
|
|
|
def get_executable_extension(self) -> str:
|
|
"""
|
|
Get executable extension for ARM embedded.
|
|
|
|
Returns .elf for embedded binaries (can be converted to .bin, .hex, .uf2)
|
|
"""
|
|
return ".elf"
|
|
|
|
|
|
class RP2040Compiler(ARMGCCCompiler):
|
|
"""
|
|
Specialized ARM GCC compiler for RP2040 (Raspberry Pi Pico).
|
|
|
|
Pre-configured for Cortex-M0+ with RP2040-specific settings.
|
|
"""
|
|
|
|
def __init__(self, executable: str = "arm-none-eabi-gcc"):
|
|
"""Initialize compiler for RP2040."""
|
|
super().__init__(executable=executable, cpu="cortex-m0plus")
|
|
|