第14章:嵌入式系统模拟器原理与实战应用

14.1 模拟器技术基础概念解析

模拟器技术在嵌入式系统开发中扮演着至关重要的角色,它允许开发者在没有实际硬件的情况下进行软件开发和调试。本节将深入探讨模拟器的基本概念、工作原理及其在嵌入式开发中的应用价值。

理论部分:模拟器是通过软件模拟硬件系统行为的程序,它能够复制目标系统的功能,包括处理器指令集、内存映射、外设接口等。模拟器可以分为全系统模拟器和应用程序模拟器两大类。全系统模拟器如QEMU能够模拟整个计算机系统,包括CPU、内存、存储设备和各种外设;而应用程序模拟器通常只模拟特定的运行环境。

实例部分:基于QEMU的ARM嵌入式系统模拟环境搭建:

  1. 在Ubuntu 20.04.6 LTS上安装QEMU系统模拟器:
# 更新软件包列表并安装QEMU
sudo apt update
sudo apt install qemu-system-arm qemu-utils -y

# 安装交叉编译工具链
sudo apt install gcc-arm-linux-gnueabihf gdb-multiarch -y

# 验证安装
qemu-system-arm --version
arm-linux-gnueabihf-gcc --version
  1. 创建简单的ARM裸机程序并测试:
// bare_metal_arm.c - 简单的ARM裸机程序
#define UART0_BASE 0x101f1000

// 简单的UART输出函数
void uart_putc(char c) {
    volatile unsigned int *uart_dr = (unsigned int *)(UART0_BASE + 0x00);
    *uart_dr = c;
}

void uart_puts(const char *str) {
    while (*str) {
        uart_putc(*str++);
    }
}

// 简单的内存操作函数
void memset(void *dest, int val, unsigned int size) {
    char *d = (char *)dest;
    while (size--) {
        *d++ = val;
    }
}

// 入口函数
void _start() {
    // 初始化栈指针(由链接脚本定义)
    extern unsigned int _stack_top;
    asm volatile("mov sp, %0" : : "r" (&_stack_top));
    
    uart_puts("Hello from ARM Bare Metal Simulation!\r\n");
    uart_puts("System initialized successfully.\r\n");
    
    // 简单内存测试
    char test_buffer[64];
    memset(test_buffer, 'A', sizeof(test_buffer));
    uart_puts("Memory test completed.\r\n");
    
    // 主循环
    while (1) {
        // 简单的闪烁模式表示系统运行
        uart_putc('.');
        // 延时循环
        for (volatile int i = 0; i < 1000000; i++);
    }
}
  1. 对应的链接脚本和编译命令:
/* simple_arm.ld - 简单的ARM链接脚本 */
ENTRY(_start)

MEMORY {
    RAM (rwx) : ORIGIN = 0x10000, LENGTH = 64K
}

SECTIONS {
    .text : {
        *(.text)
    } > RAM
    
    .data : {
        *(.data)
    } > RAM
    
    .bss : {
        *(.bss)
    } > RAM
    
    /* 栈设置在RAM末尾 */
    _stack_top = ORIGIN(RAM) + LENGTH(RAM);
}

编译和运行命令:

# 编译ARM裸机程序
arm-linux-gnueabihf-gcc -nostdlib -ffreestanding -T simple_arm.ld \
    -o bare_metal_arm.elf bare_metal_arm.c

# 转换为原始二进制文件
arm-linux-gnueabihf-objcopy -O binary bare_metal_arm.elf bare_metal_arm.bin

# 使用QEMU运行模拟
qemu-system-arm -M versatilepb -cpu cortex-a8 -kernel bare_metal_arm.bin \
    -serial stdio -nographic

14.2 模拟器与仿真器的技术差异

虽然模拟器(Simulator)和仿真器(Emulator)经常被混用,但它们在技术实现和应用场景上存在重要区别。理解这些差异对于选择合适的开发工具至关重要。

理论部分:模拟器通常是在主机系统上通过软件模拟目标系统的功能,侧重于行为模拟;而仿真器则更接近硬件层面,可能涉及专门的硬件设备来精确复制目标系统的时序和行为。模拟器更适合软件开发和算法验证,仿真器则更适合硬件接口测试和实时系统验证。

实例部分:不同层次模拟的实现对比:

  1. 指令集模拟器(ISS)实现示例:
// simple_iss.c - 简单的ARM指令集模拟器
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define MEMORY_SIZE 65536
#define REGISTER_COUNT 16

typedef struct {
    uint32_t registers[REGISTER_COUNT];
    uint32_t pc;
    uint32_t cpsr;
    uint8_t memory[MEMORY_SIZE];
    int running;
} arm_cpu_t;

// 条件码检查
int check_condition(uint32_t instruction, uint32_t cpsr) {
    uint8_t cond = (instruction >> 28) & 0xF;
    
    switch (cond) {
        case 0x0: // EQ - Equal
            return (cpsr & (1 << 30)) != 0;
        case 0x1: // NE - Not Equal
            return (cpsr & (1 << 30)) == 0;
        case 0xE: // AL - Always
        default:
            return 1;
    }
}

// 数据处理指令模拟
void execute_data_processing(arm_cpu_t *cpu, uint32_t instruction) {
    if (!check_condition(instruction, cpu->cpsr)) return;
    
    uint8_t opcode = (instruction >> 21) & 0xF;
    uint8_t s = (instruction >> 20) & 1;
    uint8_t rn = (instruction >> 16) & 0xF;
    uint8_t rd = (instruction >> 12) & 0xF;
    
    uint32_t operand1 = cpu->registers[rn];
    uint32_t operand2;
    
    // 处理第二操作数(立即数或寄存器移位)
    if (instruction & (1 << 25)) {
        // 立即数
        uint32_t imm = instruction & 0xFF;
        uint8_t rotate = (instruction >> 8) & 0xF;
        operand2 = (imm >> (rotate * 2)) | (imm << (32 - rotate * 2));
    } else {
        // 寄存器移位
        uint8_t rm = instruction & 0xF;
        operand2 = cpu->registers[rm];
    }
    
    uint32_t result = 0;
    
    switch (opcode) {
        case 0x0: // AND
            result = operand1 & operand2;
            break;
        case 0x1: // EOR
            result = operand1 ^ operand2;
            break;
        case 0x2: // SUB
            result = operand1 - operand2;
            break;
        case 0x4: // ADD
            result = operand1 + operand2;
            break;
        case 0xD: // MOV
            result = operand2;
            break;
        default:
            printf("未实现的操作码: 0x%X\n", opcode);
            cpu->running = 0;
            return;
    }
    
    cpu->registers[rd] = result;
    
    // 更新条件标志位
    if (s && rd != 15) {
        cpu->cpsr &= ~0xF0000000; // 清除条件标志
        if (result == 0) cpu->cpsr |= (1 << 30); // Z标志
        if (result & 0x80000000) cpu->cpsr |= (1 << 31); // N标志
        // 这里应该设置C和V标志,但为了简化省略
    }
    
    cpu->pc += 4;
}

// 加载存储指令模拟
void execute_load_store(arm_cpu_t *cpu, uint32_t instruction) {
    if (!check_condition(instruction, cpu->cpsr)) return;
    
    uint8_t load = (instruction >> 20) & 1;
    uint8_t byte = (instruction >> 22) & 1;
    uint8_t rn = (instruction >> 16) & 0xF;
    uint8_t rd = (instruction >> 12) & 0xF;
    
    uint32_t address = cpu->registers[rn];
    
    // 计算偏移量(简化版本)
    uint32_t offset;
    if (instruction & (1 << 25)) {
        // 寄存器偏移
        uint8_t rm = instruction & 0xF;
        offset = cpu->registers[rm];
    } else {
        // 立即数偏移
        offset = instruction & 0xFFF;
    }
    
    if (!(instruction & (1 << 24))) { // 前变址
        address += (instruction & (1 << 23)) ? offset : -offset;
    }
    
    if (load) {
        // 加载指令
        if (byte) {
            cpu->registers[rd] = cpu->memory[address];
        } else {
            // 字加载(简化,未处理对齐)
            cpu->registers[rd] = *(uint32_t*)&cpu->memory[address];
        }
    } else {
        // 存储指令
        if (byte) {
            cpu->memory[address] = cpu->registers[rd] & 0xFF;
        } else {
            *(uint32_t*)&cpu->memory[address] = cpu->registers[rd];
        }
    }
    
    if (instruction & (1 << 24)) { // 后变址
        address += (instruction & (1 << 23)) ? offset : -offset;
        cpu->registers[rn] = address;
    }
    
    cpu->pc += 4;
}

// 主模拟循环
void cpu_execute(arm_cpu_t *cpu) {
    cpu->running = 1;
    
    while (cpu->running) {
        // 取指
        uint32_t instruction = *(uint32_t*)&cpu->memory[cpu->pc];
        
        // 译码和执行
        uint8_t opcode = (instruction >> 26) & 0x3;
        
        switch (opcode) {
            case 0x0: // 数据处理指令
                execute_data_processing(cpu, instruction);
                break;
            case 0x1: // 加载存储指令
                execute_load_store(cpu, instruction);
                break;
            case 0x2: // 分支指令(简化实现)
                if (check_condition(instruction, cpu->cpsr)) {
                    int32_t offset = (instruction & 0xFFFFFF) << 2;
                    if (offset & 0x2000000) offset |= 0xFC000000; // 符号扩展
                    cpu->pc += offset + 8;
                } else {
                    cpu->pc += 4;
                }
                break;
            default:
                printf("未知指令: 0x%08X at PC=0x%08X\n", instruction, cpu->pc);
                cpu->running = 0;
                break;
        }
        
        // 简单的调试输出
        if ((cpu->pc % 16) == 0) {
            printf("PC: 0x%08X, R0: 0x%08X, R1: 0x%08X\n", 
                   cpu->pc, cpu->registers[0], cpu->registers[1]);
        }
        
        // 安全停止条件
        if (cpu->pc >= MEMORY_SIZE - 4) {
            printf("程序执行完成\n");
            break;
        }
    }
}
  1. 硬件在环(HIL)仿真示例:
// hil_simulation.c - 硬件在环仿真接口
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

// 模拟硬件寄存器
typedef struct {
    volatile uint32_t control;
    volatile uint32_t status;
    volatile uint32_t data;
    volatile uint32_t interrupt;
} hardware_registers_t;

// 硬件仿真上下文
typedef struct {
    hardware_registers_t *regs;
    int simulation_fd;
    uint8_t *shared_memory;
} hil_context_t;

// 初始化HIL仿真
hil_context_t* hil_init(const char *shared_memory_path) {
    hil_context_t *ctx = malloc(sizeof(hil_context_t));
    if (!ctx) return NULL;
    
    // 创建共享内存
    ctx->simulation_fd = shm_open(shared_memory_path, O_CREAT | O_RDWR, 0666);
    if (ctx->simulation_fd < 0) {
        perror("shm_open");
        free(ctx);
        return NULL;
    }
    
    // 设置共享内存大小
    ftruncate(ctx->simulation_fd, sizeof(hardware_registers_t) + 4096);
    
    // 映射共享内存
    ctx->shared_memory = mmap(NULL, sizeof(hardware_registers_t) + 4096,
                             PROT_READ | PROT_WRITE, MAP_SHARED,
                             ctx->simulation_fd, 0);
    
    if (ctx->shared_memory == MAP_FAILED) {
        perror("mmap");
        close(ctx->simulation_fd);
        free(ctx);
        return NULL;
    }
    
    ctx->regs = (hardware_registers_t*)ctx->shared_memory;
    
    // 初始化寄存器
    ctx->regs->control = 0;
    ctx->regs->status = 0;
    ctx->regs->data = 0;
    ctx->regs->interrupt = 0;
    
    return ctx;
}

// 模拟硬件中断处理
void hardware_interrupt_simulation(hil_context_t *ctx) {
    static int interrupt_counter = 0;
    
    // 每100次调用产生一次中断
    if (++interrupt_counter >= 100) {
        ctx->regs->interrupt = 1;
        interrupt_counter = 0;
        
        // 模拟硬件延迟
        usleep(1000); // 1ms延迟
    }
}

// 硬件响应模拟
void hardware_response_simulation(hil_context_t *ctx) {
    // 如果控制寄存器设置了启动位
    if (ctx->regs->control & 0x1) {
        // 模拟硬件处理数据
        uint32_t input_data = ctx->regs->data;
        uint32_t processed_data = input_data * 2 + 1; // 简单的处理
        
        // 更新状态寄存器
        ctx->regs->status |= 0x1; // 设置完成位
        
        // 如果有中断使能,触发中断
        if (ctx->regs->control & 0x2) {
            ctx->regs->interrupt = 1;
        }
    }
}

// 清理HIL资源
void hil_cleanup(hil_context_t *ctx) {
    if (ctx) {
        munmap(ctx->shared_memory, sizeof(hardware_registers_t) + 4096);
        close(ctx->simulation_fd);
        shm_unlink("/hil_simulation");
        free(ctx);
    }
}

14.3 模拟器在项目开发中的核心价值

模拟器在现代嵌入式项目开发中提供了不可替代的价值,从早期开发到持续集成,模拟器都在各个环节发挥着重要作用。

理论部分:模拟器的主要价值体现在以下几个方面:提前开发周期、降低硬件成本、提高测试覆盖率、支持自动化测试、便于调试和性能分析。通过模拟器,团队可以在硬件可用之前就开始软件开发,大幅缩短产品上市时间。

实例部分:模拟器在完整开发流程中的应用:

  1. 基于QEMU的自动化测试框架:
#!/usr/bin/env python3
# qemu_test_runner.py - 基于QEMU的自动化测试框架

import subprocess
import time
import threading
import re
from pathlib import Path

class QEMUTestRunner:
    def __init__(self, qemu_path, kernel_path, memory_size="128M"):
        self.qemu_path = qemu_path
        self.kernel_path = kernel_path
        self.memory_size = memory_size
        self.qemu_process = None
        self.test_output = ""
        self.test_complete = False
        
    def start_qemu(self, extra_args=None):
        """启动QEMU模拟器"""
        cmd = [
            self.qemu_path,
            "-machine", "virt",
            "-cpu", "cortex-a53",
            "-smp", "1",
            "-m", self.memory_size,
            "-kernel", self.kernel_path,
            "-serial", "stdio",
            "-monitor", "none",
            "-display", "none",
        ]
        
        if extra_args:
            cmd.extend(extra_args)
            
        self.qemu_process = subprocess.Popen(
            cmd,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1
        )
        
        # 启动输出监控线程
        output_thread = threading.Thread(target=self._capture_output)
        output_thread.daemon = True
        output_thread.start()
        
    def _capture_output(self):
        """捕获QEMU输出"""
        while self.qemu_process and self.qemu_process.poll() is None:
            line = self.qemu_process.stdout.readline()
            if line:
                self.test_output += line
                print(f"QEMU: {line.strip()}")
                
                # 检查测试完成标志
                if "TEST_COMPLETE" in line:
                    self.test_complete = True
                    
    def wait_for_test_completion(self, timeout=30):
        """等待测试完成"""
        start_time = time.time()
        while not self.test_complete:
            if time.time() - start_time > timeout:
                raise TimeoutError("测试超时")
            time.sleep(0.1)
            
    def run_test_suite(self):
        """运行测试套件"""
        print("启动QEMU测试环境...")
        self.start_qemu()
        
        try:
            print("等待测试完成...")
            self.wait_for_test_completion()
            
            # 分析测试结果
            test_results = self.analyze_test_results()
            
            print(f"测试完成: {test_results}")
            return test_results
            
        except TimeoutError:
            print("测试超时")
            return {"status": "timeout", "passed": 0, "failed": 0}
        finally:
            self.stop_qemu()
            
    def analyze_test_results(self):
        """分析测试结果"""
        passed_pattern = r"PASSED: (\d+)"
        failed_pattern = r"FAILED: (\d+)"
        
        passed_match = re.search(passed_pattern, self.test_output)
        failed_match = re.search(failed_pattern, self.test_output)
        
        passed = int(passed_match.group(1)) if passed_match else 0
        failed = int(failed_match.group(1)) if failed_match else 0
        
        status = "passed" if failed == 0 else "failed"
        
        return {
            "status": status,
            "passed": passed,
            "failed": failed,
            "output": self.test_output
        }
        
    def stop_qemu(self):
        """停止QEMU进程"""
        if self.qemu_process and self.qemu_process.poll() is None:
            self.qemu_process.terminate()
            try:
                self.qemu_process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                self.qemu_process.kill()
                
# 使用示例
if __name__ == "__main__":
    runner = QEMUTestRunner(
        qemu_path="qemu-system-aarch64",
        kernel_path="build/test_kernel.elf"
    )
    
    results = runner.run_test_suite()
    
    if results["status"] == "passed":
        print("所有测试通过!")
    else:
        print(f"测试失败: {results['failed']} 个测试未通过")
        exit(1)
  1. 基于模拟器的性能分析工具:
// performance_profiler.c - 模拟器性能分析工具
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

#define PROFILER_BUFFER_SIZE 10000

typedef struct {
    const char *function_name;
    struct timeval start_time;
    struct timeval end_time;
    unsigned long call_count;
    unsigned long total_time_us;
} function_profile_t;

typedef struct {
    function_profile_t functions[PROFILER_BUFFER_SIZE];
    int function_count;
    int enabled;
} profiler_t;

static profiler_t global_profiler = {0};

// 开始函数性能分析
void profiler_start(const char *func_name) {
    if (!global_profiler.enabled) return;
    
    // 查找或创建函数记录
    int index = -1;
    for (int i = 0; i < global_profiler.function_count; i++) {
        if (global_profiler.functions[i].function_name == func_name) {
            index = i;
            break;
        }
    }
    
    if (index == -1) {
        if (global_profiler.function_count >= PROFILER_BUFFER_SIZE) return;
        index = global_profiler.function_count++;
        global_profiler.functions[index].function_name = func_name;
        global_profiler.functions[index].call_count = 0;
        global_profiler.functions[index].total_time_us = 0;
    }
    
    gettimeofday(&global_profiler.functions[index].start_time, NULL);
}

// 结束函数性能分析
void profiler_end(const char *func_name) {
    if (!global_profiler.enabled) return;
    
    struct timeval end_time;
    gettimeofday(&end_time, NULL);
    
    for (int i = 0; i < global_profiler.function_count; i++) {
        if (global_profiler.functions[i].function_name == func_name) {
            struct timeval *start = &global_profiler.functions[i].start_time;
            
            unsigned long time_us = 
                (end_time.tv_sec - start->tv_sec) * 1000000 +
                (end_time.tv_usec - start->tv_usec);
            
            global_profiler.functions[i].total_time_us += time_us;
            global_profiler.functions[i].call_count++;
            break;
        }
    }
}

// 生成性能报告
void profiler_generate_report(void) {
    printf("\n=== 性能分析报告 ===\n");
    printf("%-30s %10s %12s %12s\n", 
           "函数名", "调用次数", "总时间(us)", "平均时间(us)");
    printf("------------------------------------------------------------\n");
    
    for (int i = 0; i < global_profiler.function_count; i++) {
        function_profile_t *func = &global_profiler.functions[i];
        unsigned long avg_time = func->total_time_us / func->call_count;
        
        printf("%-30s %10lu %12lu %12lu\n",
               func->function_name, func->call_count,
               func->total_time_us, avg_time);
    }
}

// 性能分析宏(方便使用)
#define PROFILE_FUNCTION() \
    profiler_start(__func__); \
    defer_profiler_end(__func__)

// 使用defer模式确保函数退出时调用profiler_end
void defer_profiler_end(const char *func_name) {
    // 这个函数会在栈展开时被调用
    profiler_end(func_name);
}

// 示例使用
void expensive_calculation(void) {
    PROFILE_FUNCTION();
    
    // 模拟耗时操作
    volatile int result = 0;
    for (int i = 0; i < 1000000; i++) {
        result += i * i;
    }
}

void data_processing(void) {
    PROFILE_FUNCTION();
    
    expensive_calculation();
    
    // 更多处理
    for (int i = 0; i < 1000; i++) {
        // 数据处理
    }
}

14.4 模拟器实战应用与高级技巧

在实际项目开发中,模拟器的应用远不止基本的系统模拟。本节将探讨模拟器在复杂场景下的高级应用技巧和最佳实践。

实例部分:综合模拟器应用案例:

  1. 多核嵌入式系统模拟:
// multicore_simulation.c - 多核ARM系统模拟
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define NUM_CORES 4
#define SHARED_MEMORY_SIZE 4096

typedef struct {
    int core_id;
    volatile int *shared_memory;
    pthread_t thread;
    int running;
} cpu_core_t;

// 核间通信寄存器
typedef struct {
    volatile uint32_t mailbox[NUM_CORES][NUM_CORES];
    volatile uint32_t irq_status;
    volatile uint32_t irq_mask;
} ipc_registers_t;

static ipc_registers_t ipc_regs;
static cpu_core_t cores[NUM_CORES];

// 核间中断处理
void send_ipi(int source_core, int target_core) {
    ipc_regs.mailbox[target_core][source_core] = 1;
    
    if (ipc_regs.irq_mask & (1 << target_core)) {
        ipc_regs.irq_status |= (1 << target_core);
        // 在实际模拟器中,这里应该触发目标核的中断
    }
}

// 核心执行函数
void* cpu_core_execute(void *arg) {
    cpu_core_t *core = (cpu_core_t *)arg;
    
    printf("Core %d 启动\n", core->core_id);
    
    // 核心特定的初始化
    switch (core->core_id) {
        case 0:
            // 核心0 - 主控核心
            printf("Core 0: 初始化系统...\n");
            sleep(1);
            
            // 启动其他核心
            for (int i = 1; i < NUM_CORES; i++) {
                printf("Core 0: 启动核心 %d\n", i);
                send_ipi(0, i);
            }
            break;
            
        case 1:
            // 核心1 - 数据处理核心
            printf("Core 1: 等待工作...\n");
            while (!ipc_regs.mailbox[1][0]) {
                usleep(100000);
            }
            printf("Core 1: 开始数据处理...\n");
            break;
            
        case 2:
            // 核心2 - 网络处理核心
            printf("Core 2: 等待网络任务...\n");
            while (!ipc_regs.mailbox[2][0]) {
                usleep(100000);
            }
            printf("Core 2: 处理网络数据包...\n");
            break;
            
        case 3:
            // 核心3 - 存储处理核心
            printf("Core 3: 等待存储操作...\n");
            while (!ipc_regs.mailbox[3][0]) {
                usleep(100000);
            }
            printf("Core 3: 执行存储I/O...\n");
            break;
    }
    
    // 核心主循环
    while (core->running) {
        // 模拟核心工作负载
        switch (core->core_id) {
            case 0:
                // 系统管理任务
                sleep(2);
                printf("Core 0: 系统心跳\n");
                break;
                
            case 1:
                // 数据处理
                usleep(500000);
                printf("Core 1: 处理数据块\n");
                break;
                
            default:
                usleep(1000000);
                break;
        }
        
        // 检查核间通信
        for (int i = 0; i < NUM_CORES; i++) {
            if (i != core->core_id && ipc_regs.mailbox[core->core_id][i]) {
                printf("Core %d: 收到来自Core %d的消息\n", 
                       core->core_id, i);
                ipc_regs.mailbox[core->core_id][i] = 0;
            }
        }
    }
    
    printf("Core %d 退出\n", core->core_id);
    return NULL;
}

// 初始化多核系统
int init_multicore_system(void) {
    // 初始化IPC寄存器
    for (int i = 0; i < NUM_CORES; i++) {
        for (int j = 0; j < NUM_CORES; j++) {
            ipc_regs.mailbox[i][j] = 0;
        }
    }
    ipc_regs.irq_status = 0;
    ipc_regs.irq_mask = 0xF; // 所有核心使能中断
    
    // 创建核心线程
    for (int i = 0; i < NUM_CORES; i++) {
        cores[i].core_id = i;
        cores[i].running = 1;
        cores[i].shared_memory = NULL;
        
        if (pthread_create(&cores[i].thread, NULL, 
                          cpu_core_execute, &cores[i]) != 0) {
            perror("pthread_create");
            return -1;
        }
    }
    
    return 0;
}

// 停止多核系统
void stop_multicore_system(void) {
    for (int i = 0; i < NUM_CORES; i++) {
        cores[i].running = 0;
    }
    
    for (int i = 0; i < NUM_CORES; i++) {
        pthread_join(cores[i].thread, NULL);
    }
    
    printf("多核系统已停止\n");
}
  1. 设备模拟和驱动程序测试:
// device_simulation.c - 虚拟设备模拟和驱动测试
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>

// 虚拟网络设备模拟
typedef struct {
    volatile uint32_t control;
    volatile uint32_t status;
    volatile uint32_t tx_data;
    volatile uint32_t rx_data;
    volatile uint32_t interrupt;
    
    uint8_t tx_buffer[1518];
    uint8_t rx_buffer[1518];
    uint32_t tx_length;
    uint32_t rx_length;
    
    pthread_mutex_t lock;
} virtual_net_device_t;

static virtual_net_device_t net_dev;

// 网络设备初始化
void net_device_init(void) {
    memset(&net_dev, 0, sizeof(net_dev));
    pthread_mutex_init(&net_dev.lock, NULL);
    
    net_dev.status = 0x1; // 设备就绪
    printf("虚拟网络设备初始化完成\n");
}

// 设备中断处理线程
void* interrupt_simulation_thread(void *arg) {
    while (1) {
        usleep(100000); // 每100ms检查一次
        
        pthread_mutex_lock(&net_dev.lock);
        
        // 模拟网络数据到达
        static int packet_counter = 0;
        if (packet_counter++ % 10 == 0) {
            // 每1秒模拟收到一个数据包
            net_dev.rx_length = 64; // 模拟64字节数据包
            net_dev.status |= 0x2; // 设置接收就绪标志
            
            if (net_dev.control & 0x2) { // 接收中断使能
                net_dev.interrupt = 1;
                printf("网络设备: 接收中断触发\n");
            }
        }
        
        // 检查发送完成
        if (net_dev.tx_length > 0) {
            net_dev.status |= 0x4; // 设置发送完成标志
            net_dev.tx_length = 0;
            
            if (net_dev.control & 0x4) { // 发送中断使能
                net_dev.interrupt = 1;
                printf("网络设备: 发送完成中断\n");
            }
        }
        
        pthread_mutex_unlock(&net_dev.lock);
    }
    
    return NULL;
}

// 网络设备驱动
typedef struct {
    uint32_t base_address;
    int irq_number;
    void (*isr_callback)(void);
} net_driver_t;

// 驱动初始化
int net_driver_init(net_driver_t *drv, uint32_t base_addr) {
    drv->base_address = base_addr;
    drv->irq_number = 5; // 虚拟IRQ号
    
    printf("网络驱动初始化: 基地址 0x%08X, IRQ %d\n", 
           base_addr, drv->irq_number);
    return 0;
}

// 发送数据包
int net_driver_send(net_driver_t *drv, const uint8_t *data, uint32_t length) {
    if (length > 1518) {
        printf("错误: 数据包太大\n");
        return -1;
    }
    
    pthread_mutex_lock(&net_dev.lock);
    
    // 复制数据到设备缓冲区
    memcpy(net_dev.tx_buffer, data, length);
    net_dev.tx_length = length;
    
    // 启动发送
    net_dev.control |= 0x1; // 设置发送启动位
    net_dev.status &= ~0x4; // 清除发送完成标志
    
    printf("驱动: 发送 %u 字节数据包\n", length);
    
    pthread_mutex_unlock(&net_dev.lock);
    
    return 0;
}

// 接收数据包
int net_driver_receive(net_driver_t *drv, uint8_t *buffer, uint32_t *length) {
    pthread_mutex_lock(&net_dev.lock);
    
    if (!(net_dev.status & 0x2)) {
        // 没有数据可读
        pthread_mutex_unlock(&net_dev.lock);
        return -1;
    }
    
    // 复制接收数据
    *length = net_dev.rx_length;
    memcpy(buffer, net_dev.rx_buffer, *length);
    
    // 清除接收状态
    net_dev.status &= ~0x2;
    net_dev.interrupt = 0;
    
    printf("驱动: 接收 %u 字节数据包\n", *length);
    
    pthread_mutex_unlock(&net_dev.lock);
    return 0;
}

// 中断服务例程
void net_driver_isr(net_driver_t *drv) {
    printf("驱动ISR: 处理网络中断\n");
    
    pthread_mutex_lock(&net_dev.lock);
    
    // 检查接收中断
    if (net_dev.status & 0x2) {
        uint8_t packet[1518];
        uint32_t length;
        
        if (net_driver_receive(drv, packet, &length) == 0) {
            printf("ISR: 处理接收数据包,长度 %u\n", length);
            // 这里可以调用上层协议处理
        }
    }
    
    // 检查发送中断
    if (net_dev.status & 0x4) {
        printf("ISR: 发送完成确认\n");
        net_dev.status &= ~0x4;
    }
    
    // 清除中断
    net_dev.interrupt = 0;
    
    pthread_mutex_unlock(&net_dev.lock);
}

// 测试用例
void net_driver_test(void) {
    net_driver_t driver;
    pthread_t sim_thread;
    
    // 初始化设备和驱动
    net_device_init();
    net_driver_init(&driver, 0x10000000);
    
    // 启动设备模拟线程
    pthread_create(&sim_thread, NULL, interrupt_simulation_thread, NULL);
    
    // 启用中断
    net_dev.control |= 0x6; // 使能接收和发送中断
    
    // 测试发送
    uint8_t test_packet[] = {0xAA, 0xBB, 0xCC, 0xDD};
    net_driver_send(&driver, test_packet, sizeof(test_packet));
    
    // 等待并处理中断
    for (int i = 0; i < 5; i++) {
        sleep(1);
        
        if (net_dev.interrupt) {
            net_driver_isr(&driver);
        }
    }
    
    printf("网络驱动测试完成\n");
}

通过这些深入的实例和详细的理论分析,我们全面探讨了模拟器技术的各个方面,从基础概念到高级应用,从指令集模拟到多核系统仿真。这些知识和技能将帮助嵌入式软件工程师在没有实际硬件的情况下高效开发和测试复杂的嵌入式系统。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐