Skip to content

Platform Differences

The EmbSec Kit supports multiple target platforms, each with unique characteristics. Understanding these differences is crucial for developing portable labs and ensuring consistent behavior across environments.

Supported Platforms

1. TM4C123GH6PM (Hardware)

  • Architecture: ARM Cortex-M4F
  • Flash: 256 KB
  • RAM: 32 KB
  • Clock: Up to 80 MHz
  • FPU: Hardware floating-point
  • Use Case: Physical hardware labs

2. LM3S6965 (QEMU)

  • Architecture: ARM Cortex-M3
  • Flash: 256 KB
  • RAM: 64 KB
  • Clock: Simulated
  • FPU: None (software emulation)
  • Use Case: Development and testing

3. Host Platform (Testing)

  • Architecture: x86_64 or ARM64
  • Memory: Host system memory
  • Use Case: Unit testing and development

Key Differences

Memory Layout

TM4C123GH6PM

0x00000000 - 0x0003FFFF  Flash (256 KB)
0x20000000 - 0x20007FFF  SRAM (32 KB)
0x40000000 - 0x400FFFFF  Peripherals
0xE0000000 - 0xE0041FFF  System Control

LM3S6965 (QEMU)

0x00000000 - 0x0003FFFF  Flash (256 KB)
0x20000000 - 0x2000FFFF  SRAM (64 KB)  ← More RAM
0x40000000 - 0x400FFFFF  Peripherals
0xE0000000 - 0xE0041FFF  System Control

Peripheral Differences

UART Configuration

#ifdef PART_TM4C123GH6PM
    // Hardware: Multiple UART modules
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
#elif defined(PART_LM3S6965)
    // QEMU: Simplified UART
    SYSCTL_RCGC1_R |= SYSCTL_RCGC1_UART0;
    SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOA;
#endif

GPIO Differences

// TM4C: Advanced GPIO with multiple drive strengths
ROM_GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1,
                     GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD);

// LM3S: Basic GPIO configuration
GPIO_PORTA_DIR_R |= 0x02;  // PA1 output
GPIO_PORTA_DEN_R |= 0x03;  // PA0-1 digital enable

Timing and Clocks

Hardware Timing

void setup_system_clock_hw() {
    // TM4C: Configure PLL for 80 MHz
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL |
                       SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
}

QEMU Timing

void setup_system_clock_qemu() {
    // LM3S: Simpler clock setup, timing not cycle-accurate
    SYSCTL_RCC_R = SYSCTL_RCC_XTAL_8MHZ | SYSCTL_RCC_OSC_MAIN |
                   SYSCTL_RCC_USESYSDIV | (4 << SYSCTL_RCC_SYSDIV_S);
}

Interrupt Handling

Vector Table Differences

// tm4c_vectors.c
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
    (void (*)(void))((uint32_t)&_stack_top),
    ResetISR,
    NmiSR,
    FaultISR,
    // ... TM4C-specific vectors
};

// lm3s_vectors.c
__attribute__ ((section(".isr_vector")))
void (* const g_pfnVectors[])(void) = {
    (void (*)(void))((uint32_t)&_stack_top),
    ResetISR,
    NmiSR,
    HardFaultISR,  // Different fault handling
    // ... LM3S-specific vectors
};

Build Configuration

Compiler Flags

Hardware Build

set(CPU_FLAGS "-mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard")
add_compile_definitions(
    PART_TM4C123GH6PM
    TARGET_IS_TM4C123_RB1
    ARM_MATH_CM4
)

QEMU Build

set(CPU_FLAGS "-mcpu=cortex-m3 -mthumb")
add_compile_definitions(
    PART_LM3S6965
    TARGET_IS_DUSTDEVIL_RA0
    QEMU_BUILD
)

Linker Scripts

Hardware Linker Script

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}

QEMU Linker Script

MEMORY
{
    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 256K
    SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K  /* More RAM */
}

Platform-Specific Code

Conditional Compilation

void platform_init() {
#ifdef QEMU_BUILD
    // QEMU-specific initialization
    qemu_uart_init();
    qemu_timer_init();
#else
    // Hardware initialization
    hw_clock_init();
    hw_uart_init();
    hw_gpio_init();
#endif
}

Feature Detection

typedef struct {
    bool has_fpu;
    bool has_mpu;
    uint32_t sram_size;
    uint32_t flash_size;
} platform_features_t;

platform_features_t get_platform_features() {
    platform_features_t features = {0};

#ifdef PART_TM4C123GH6PM
    features.has_fpu = true;
    features.has_mpu = true;
    features.sram_size = 32 * 1024;
#elif defined(PART_LM3S6965)
    features.has_fpu = false;
    features.has_mpu = true;
    features.sram_size = 64 * 1024;
#endif

    return features;
}

Testing Considerations

QEMU-Specific Testing

class QEMUTestBase(LabTestBase):
    def setUp(self):
        super().setUp()
        # QEMU-specific setup
        self.qemu_monitor = self.setup_qemu_monitor()

    def inject_fault(self):
        # QEMU allows fault injection
        self.qemu_monitor.send("system_reset")

Hardware Testing

class HardwareTestBase(LabTestBase):
    def setUp(self):
        super().setUp()
        # Hardware-specific setup
        self.serial = serial.Serial('/dev/ttyUSB0', 115200)
        self.openocd = self.setup_openocd()

Performance Implications

Execution Speed

  • Hardware: Real-time, cycle-accurate
  • QEMU: ~10-100x slower, not cycle-accurate

Memory Access

  • Hardware: Wait states, cache effects
  • QEMU: Uniform access times

Interrupt Latency

  • Hardware: Deterministic, 12 cycles
  • QEMU: Variable, depends on host

Best Practices

1. Abstract Platform Differences

// Use SDK functions that handle platform differences
embsec_uart_init();  // Handles both TM4C and LM3S

2. Test on All Platforms

# Test on QEMU
cmake --preset qemu && cmake --build build-qemu
./build-qemu/labs/buffer-overflow/test_lab.py

# Test on hardware
cmake --preset embedded && cmake --build build
make flash-buffer-overflow

3. Document Platform-Specific Behavior

/**
 * @note On TM4C hardware, this function uses hardware FPU.
 *       On LM3S/QEMU, software floating-point is used.
 */
float calculate_checksum(const uint8_t *data, size_t len);

4. Provide Platform-Specific Workarounds

#ifdef QEMU_BUILD
    // QEMU workaround for missing peripheral
    #define READ_TIMER() (qemu_timer_read())
#else
    // Hardware timer read
    #define READ_TIMER() (TIMER0->TAR)
#endif

Migration Guide

Porting from LM3S to TM4C

  1. Update peripheral initialization
  2. Adjust memory layout if needed
  3. Enable FPU for floating-point
  4. Update interrupt vectors

Porting from TM4C to LM3S

  1. Remove FPU-dependent code
  2. Simplify peripheral usage
  3. Adjust for larger RAM
  4. Update build configuration

Debugging Platform Issues

Common Issues

  1. Different behavior in QEMU vs hardware
  2. Check timing-dependent code
  3. Verify peripheral initialization
  4. Compare memory layouts

  5. Build failures for specific platform

  6. Verify toolchain configuration
  7. Check conditional compilation
  8. Review linker scripts

  9. Runtime crashes on one platform

  10. Check stack usage (different RAM sizes)
  11. Verify interrupt handlers
  12. Review platform-specific code

Debug Strategies

# GDB commands for platform debugging
(gdb) info registers
(gdb) x/10x $sp
(gdb) disassemble $pc-32,$pc+32
(gdb) info mem

Future Platform Support

Planned platform additions:

  • STM32F4 series
  • nRF52 series
  • RISC-V embedded
  • Additional QEMU machines