C硬核:聊聊预编译指令和宏的应用场景(二)

UEFI Build file Mouble 一个模块,有.inf的文件编译 Package 有0个或许多个Mouble组成,有.dsc和.dec文件 Platform 一个特殊的Package文件一定包含一个.dec文件 EDK II 发展史: 1、创造了Package用于整合Mouble,作为基础的Mouble的合集,也定义了DEC文件和GUID、Protocols 2、由于产生了Package,必须创建INF文件用于规范Mouble的属性和结构。 3、创建DSC文件用于编译 4、调整Mouble, 阅读详情

C语言硬件编程栏目

往期文章:
工作数年还是被指针坑了——谈谈C语言指针运算
C硬核:聊聊预编译指令和宏的应用场景(一)



前言

关于预编译指令,在上周已经对重要的几个做了一次介绍。这一期以UEFI源码为蓝本,介绍下#define宏的经典用法。


一、如何方便维护那些值不变的参数?

经常在编写程序的时候,会发现某个常量用的地方很多,而很多初学者都是在每一个使用该常量的地方用数字表示,比如申请长度为8的数组:

int array[8];

而在声明之后使用的过程中对数组元素进行遍历,也是用这个长度8:

for(i=0; i<8; i++){
...
}

在今后代码维护和升级的过程中,可能会发现,这个数组长度要发生变化,那么又需要在声明、定义和使用的过程都需要修改了,这无疑会增加时间成本,甚至还会漏改导致出错。所以我们常用宏来定义这个常量8:

#define ARRAY_SIZE 8

这样我们下次在修改这个数组长度的时候,只需要修改这个宏的值就ok了,这样就实现了常量的统一管理!
或许有人说枚举enum也可以实现类似的功能,但从灵活性的角度来讲,宏的优势更加明显!来看看在UEFI kernel中,是怎样定义各种EFI_STATUS的:

///
/// Enumeration of EFI_STATUS.
///@{
#define EFI_SUCCESS               RETURN_SUCCESS
#define EFI_LOAD_ERROR            RETURN_LOAD_ERROR
#define EFI_INVALID_PARAMETER     RETURN_INVALID_PARAMETER
#define EFI_UNSUPPORTED           RETURN_UNSUPPORTED
#define EFI_BAD_BUFFER_SIZE       RETURN_BAD_BUFFER_SIZE
#define EFI_BUFFER_TOO_SMALL      RETURN_BUFFER_TOO_SMALL
#define EFI_NOT_READY             RETURN_NOT_READY
#define EFI_DEVICE_ERROR          RETURN_DEVICE_ERROR
#define EFI_WRITE_PROTECTED       RETURN_WRITE_PROTECTED
#define EFI_OUT_OF_RESOURCES      RETURN_OUT_OF_RESOURCES
#define EFI_VOLUME_CORRUPTED      RETURN_VOLUME_CORRUPTED
#define EFI_VOLUME_FULL           RETURN_VOLUME_FULL
#define EFI_NO_MEDIA              RETURN_NO_MEDIA
#define EFI_MEDIA_CHANGED         RETURN_MEDIA_CHANGED
#define EFI_NOT_FOUND             RETURN_NOT_FOUND
#define EFI_ACCESS_DENIED         RETURN_ACCESS_DENIED
#define EFI_NO_RESPONSE           RETURN_NO_RESPONSE
#define EFI_NO_MAPPING            RETURN_NO_MAPPING
#define EFI_TIMEOUT               RETURN_TIMEOUT
#define EFI_NOT_STARTED           RETURN_NOT_STARTED
#define EFI_ALREADY_STARTED       RETURN_ALREADY_STARTED
#define EFI_ABORTED               RETURN_ABORTED
#define EFI_ICMP_ERROR            RETURN_ICMP_ERROR
#define EFI_TFTP_ERROR            RETURN_TFTP_ERROR
#define EFI_PROTOCOL_ERROR        RETURN_PROTOCOL_ERROR
#define EFI_INCOMPATIBLE_VERSION  RETURN_INCOMPATIBLE_VERSION
#define EFI_SECURITY_VIOLATION    RETURN_SECURITY_VIOLATION
#define EFI_CRC_ERROR             RETURN_CRC_ERROR
#define EFI_END_OF_MEDIA          RETURN_END_OF_MEDIA
#define EFI_END_OF_FILE           RETURN_END_OF_FILE
#define EFI_INVALID_LANGUAGE      RETURN_INVALID_LANGUAGE
#define EFI_COMPROMISED_DATA      RETURN_COMPROMISED_DATA
#define EFI_HTTP_ERROR            RETURN_HTTP_ERROR

#define EFI_WARN_UNKNOWN_GLYPH    RETURN_WARN_UNKNOWN_GLYPH
#define EFI_WARN_DELETE_FAILURE   RETURN_WARN_DELETE_FAILURE
#define EFI_WARN_WRITE_FAILURE    RETURN_WARN_WRITE_FAILURE
#define EFI_WARN_BUFFER_TOO_SMALL RETURN_WARN_BUFFER_TOO_SMALL
#define EFI_WARN_STALE_DATA       RETURN_WARN_STALE_DATA
#define EFI_WARN_FILE_SYSTEM      RETURN_WARN_FILE_SYSTEM
///@}

这些RETURN_SUCCESS/RETURN_LOAD_ERROR/RETURN_INVALID_PARAMETER,可以简单的理解为0/1/2,这里没有使用enum,一个优势就在于我们在查阅code的时候也好查!

二、如何对你的printf/debug语句分级?

编写代码的过程中,可以说printf语句使用的频率是最高的。我们无时无刻不在使用printf或者库中自带的debug方式,对程序运行的过程或结果信息进行输出。但往往会遇到一个问题,自己编写的代码,如果将全部信息都打印出来,未免过多,不利于自己去筛选;而有些信息还是希望在自己调试某个问题的时候展现出来,所以这就涉及一个debug print level的问题。
linux中对此采用面向用户态的分级日志消息来实现,而UEFI kernel中采用DebugPrintErrorLevel来实现,下面以UEFI kernel为例,看看如何对串口输出信息进行分离:

1.定义DebugPrintErrorLevel的划分细则

这里将debug message分为32个等级,分别用PcdDebugPrintErrorLevel这个PCD的每一个Bit来表示,PCD可以简单的理解为一个宏定义:
代码如下(示例):

## This flag is used to control the print out Debug message.<BR><BR>
  #  BIT0  - Initialization message.<BR>
  #  BIT1  - Warning message.<BR>
  #  BIT2  - Load Event message.<BR>
  #  BIT3  - File System message.<BR>
  #  BIT4  - Allocate or Free Pool message.<BR>
  #  BIT5  - Allocate or Free Page message.<BR>
  #  BIT6  - Information message.<BR>
  #  BIT7  - Dispatcher message.<BR>
  #  BIT8  - Variable message.<BR>
  #  BIT10 - Boot Manager message.<BR>
  #  BIT12 - BlockIo Driver message.<BR>
  #  BIT14 - Network Driver message.<BR>
  #  BIT16 - UNDI Driver message.<BR>
  #  BIT17 - LoadFile message.<BR>
  #  BIT19 - Event message.<BR>
  #  BIT20 - Global Coherency Database changes message.<BR>
  #  BIT21 - Memory range cachability changes message.<BR>
  #  BIT22 - Detailed debug message.<BR>
  #  BIT31 - Error message.<BR>
  # @Prompt Debug Message Print Level.
  # @Expression  0x80000002 | (gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel & 0x7F84AA00) == 0
  gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x80000000|UINT32|0x00000006

2.设计和Error Level相关联的print函数

下面这个函数的第一个参数就指明当前的error level的值,再是format以及VA_LIST:

VOID
EFIAPI
DebugPrint (
  IN  UINTN        ErrorLevel,
  IN  CONST CHAR8  *Format,
  ...
  )
{
  VA_LIST  Marker;

  VA_START (Marker, Format);
  DebugVPrint (ErrorLevel, Format, Marker);
  VA_END (Marker);
}

继续打开DebugVPrint的“盲盒”往下看:

VOID
EFIAPI
DebugVPrint (
  IN  UINTN         ErrorLevel,
  IN  CONST CHAR8   *Format,
  IN  VA_LIST       VaListMarker
  )
{
  DebugPrintMarker (ErrorLevel, Format, VaListMarker, NULL);
}

这里实际的实现函数是DebugPrintMarker,通过比较指定的ErrorLevel和当前宏PcdDebugPrintErrorLevel的大小关系,来决定需不需要再执行buffer的填充和串口数据的输出:

VOID
DebugPrintMarker (
  IN  UINTN         ErrorLevel,
  IN  CONST CHAR8   *Format,
  IN  VA_LIST       VaListMarker,
  IN  BASE_LIST     BaseListMarker
  )
{
  CHAR8    Buffer[MAX_DEBUG_MESSAGE_LENGTH];

  //
  // If Format is NULL, then ASSERT().
  //
  ASSERT (Format != NULL);

  //
  // Check driver debug mask value and global mask
  //
  if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
    return;
  }

  //
  // Convert the DEBUG() message to an ASCII String
  //
  if (BaseListMarker == NULL) {
    AsciiVSPrint (Buffer, sizeof (Buffer), Format, VaListMarker);
  } else {
    AsciiBSPrint (Buffer, sizeof (Buffer), Format, BaseListMarker);
  }

  //
  // Send the print string to a Serial Port
  //
  SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
}

3. 调整宏DebugPrintErrorLevel或入口参数errorlevel

从上面code可以看出,要想控制print/debug输出的信息,有以下两种方式:
(1)在使用DebugPrint时,修改error level这个参数,让这个参数在PcdDebugPrintErrorLevel这个某一个Bit上占有一席之地,相与不为0;
(2)如果要减少print/debug输出的信息,可以修改宏DebugPrintErrorLevel,让不为0的bit更少一些,从而关闭某些debug level message的输出。


三、如何批量替换一系列代码?

宏可以替换数值,当然也可以替换一系列执行的语句!
如UEFI kernel中对读写屏障功能代码的宏定义:

//
// GCC inline assembly for Read Write Barrier
//
#define _ReadWriteBarrier() do { __asm__ __volatile__ ("": : : "memory"); } while(0)

为什么要使用do…while(0)呢?不使用可以吗?
答案当然是否定的。假设不使用do…while(0)进行处理,索性替换到原文中,如果原文中出现if/for等分支执行语句,那么本意的整体执行,就导致最后只有某些语句执行,而某些没有被执行的情况。添加do…while(0)让宏里的代码作为整体执行!

总结

宏往往搭配预编译指令中的#define一起使用,在C语言使用中无处不在。以上就是常见的几个宏的应用场景,用好宏,让我们工作事半功倍,结构更加清晰!

UEFI开发历程4—串口调试功能的探索 前言 现如今,由于BIOS代码在生成bin文件烧录进板子后,我们无法看见程序变量的变化,故而导致调试困难。我们都知道,大部分语言程序都有几种方法:日志打印、单步调试等方法。然而BIOS是一个开机过程中的用于初始化的系统,它不是一个软件,因此没有实体界面可以观察变量的改变。但由于主板上存在着串口,因此,串口调试对于BIOS来说是一种非常重要的调试手段。 串口调试实现方法 串口调试功能的打开有三种方式:IO配置寄存器并通过寄存器发送/接收数据的方式、Protocol配置寄存器并通过Protocol提供的读 阅读详情

相关推荐

C/C++静态库封装实战:从原理到工程实践

在软件工程中,代码封装与模块化是构建可维护、可复用系统的核心原则。其基本原理在于通过接口与实现的分离,隐藏内部细节,对外提供稳定、清晰的契约。这一技术价值不仅体现在提升代码安全性和知识产权保护上,还能有效简化项目结构、加速编译过程,并强制良好的架构设计。在实际应用场景中,当需要将核心算法、业务逻辑或基础组件以二进制形式分发给客户、合作伙伴或跨项目集成时,静态库(Static Library)便成为一种经典且高效的解决方案。它通过将源代码预编译为目标文件并打包,使核心实现安全地“溶解”在最终的可执行文件中,避

weixin_30768881的博客 250

EDK2之debug

在UEFI开发中,非常重要的一个部分就是添加串口调试信息打印,这个通过DEBUG宏来完成。

heshuangzong的博客 3111

ESP32C3启动流程揭秘:从复位向量到RTOS调度的关键步骤

本文深入解析了ESP32C3芯片从复位向量到RTOS调度的完整启动流程。详细拆解了ROM一级引导程序、Flash二级引导程序的关键步骤,包括启动模式选择、复位原因处理、分区表解析、安全启动验证等核心环节,并阐述了FreeRTOS调度器如何最终接管系统,为开发者解决启动相关问题和优化系统性能提供清晰指引。

weixin_29185167的博客 264

Delphi开发Linux的三个操作系统内核单元之网络传输运行时刻库Linuxapi.Curl.pas

Delphi开发Linux的三个操作系统内核单元之网络传输运行时刻库Linuxapi.Curl.pas ......不断补充中...... 一、网络传输运行时刻库Linuxapi.Curl.pas Delphi开发Linux在使用CURL时的建议的作为暂存区的缓冲区大小CURL_MAX_WRITE_SIZE: //uses Linuxapi.Curl.pas; const CURL_MAX_WRITE_SIZE = 16384; {$EXTERNALSYM CU...

pulledup的博客 1554

Python离线开发全攻略:从Whl到Anaconda虚拟环境

本文详细介绍了Python离线开发的两大核心方法:手动处理Whl文件与迁移Anaconda虚拟环境。针对无法联网的开发场景,文章提供了从依赖包递归下载、安装顺序到完整环境打包迁移的实战指南,并分享了搭建本地仓库、依赖清单管理等高级技巧,帮助开发者在封闭环境中高效部署Python项目。

weixin_29063035的博客 221

宝塔面板下Nginx集成GeoIP2模块实战指南

本文详细介绍了在宝塔面板环境下,为Nginx手动编译并集成GeoIP2模块的完整实战指南。通过步骤解析,帮助用户实现基于IP地址识别访客地理位置的功能,从而轻松实现网站内容地域限制、差异化展示或流量屏蔽,提升运维效率与安全性。

weixin_28455801的博客 408

Buzz终极指南:完全离线语音转文字,保护隐私的免费开源方案

你是否曾担心会议录音上传到云端会泄露商业机密?🤔 是否因为网络不稳定而无法使用在线语音识别服务?在数字时代,隐私保护和数据安全已成为每个职场人士的核心关切。今天,我要为你介绍一款革命性的**完全离线语音识别工具**——Buzz,它让你的音频转录**100%在本地完成**,彻底告别隐私泄露风险! ## 痛点分析:为什么传统语音转录服务令人担忧? 想象一下这个场景:你正在参加一场重要的商业会议,

gitblog_00183的博客 460

基于OpenCV与C++的二维码定位识别:从图像处理原理到工程实践

在计算机视觉领域,图像处理是理解与解析视觉信息的基础技术。其核心原理在于通过算法对数字图像进行分析、增强和特征提取,从而让计算机能够“看懂”图像内容。这项技术的核心价值在于将像素数据转化为结构化信息,广泛应用于自动化、检测与识别场景。二维码识别便是其典型应用之一,它不依赖于专用解码库,而是通过图像预处理、轮廓分析和几何验证等通用视觉方法实现。本文聚焦于使用OpenCV和C++实现二维码的定位与校正,详细探讨了**自适应阈值**与**轮廓层级**等关键技术在解决复杂背景与光照不均问题中的应用,为嵌入式设备和高

weixin_29171129的博客 253

C硬核:聊聊预编译指令和宏的应用场景(一)

C语言硬件编程栏目 往期文章:工作数年还是被指针坑了——谈谈C语言指针运算 C硬核:聊聊预编译指令和宏的应用场景C语言硬件编程栏目前言一、预编译指令#define#if#ifdef#include#pragma二、宏的应用场景编译时确定值的参数定义print error level定义函数或函数组合总结 前言 C语言编程中离不开预编译指令,编译器在预编译阶段,会根据预编译指令对你编写的代码进行处理。 例如,我们在写第一段C程序"HelloWorld"的时候,就用到了#include指令来包含stdi

Cerman的博客 717

YOLO11实战:手把手教你优化钢材表面缺陷识别模型(基于NEU-DET数据集)

本文详细介绍了如何使用YOLO11优化钢材表面缺陷识别模型,基于NEU-DET数据集进行实战训练。从数据增强、模型架构优化到训练过程控制,全面解析提升钢材缺陷检测性能的关键技术,特别针对裂纹、划痕等典型缺陷提出针对性解决方案。

weixin_29081163的博客 380

从SD更新字库到FLASH,再用LCD显示

用Flash当字库存储载体。思路是先将要用到的字库文件存在SD卡,然后存储到Flash,LCD显示时候从Flash中读取 还挺顺利的,移植的原子的程序,自己稍加修改,主要是我的液晶屏函数,Flash读写函数,还有存储文件的flash地址不一样。一晚上搞定,大小字体都OK。挺高兴哈哈。这几天忙工作事情有点耽搁了学习进展嘿嘿 在text.c的showstr函数中char的字体颜色随意设置的,可以显...

weixin_30505751的博客 914

SenseVoice-Small语音识别入门:C语言调用ONNX Runtime推理引擎教程

本文介绍了如何在星图GPU平台上自动化部署sensevoice-small-语音识别-onnx模型(带量化后),实现高效的本地语音识别应用。通过C语言调用ONNX Runtime推理引擎,开发者可以轻松集成该模型,适用于嵌入式设备或桌面程序的语音转文字场景,如语音指令识别、实时字幕生成等。

weixin_31139479的博客 157

【Anaconda】conda国内镜像源快速配置指南(清华/阿里云)

本文详细介绍了如何为Anaconda配置国内镜像源(清华/阿里云),以显著提升conda包下载速度并减少安装失败率。通过分步指南和实用技巧,帮助开发者快速完成配置,优化Python开发环境。

weixin_33725722的博客 1488

云容笔谈·东方红颜影像生成系统C语言基础调用示例:通过C接口实现高性能集成

本文介绍了如何在星图GPU平台上自动化部署💃 云容笔谈 · 东方红颜影像生成系统镜像,并通过C语言接口实现高性能集成。该方案特别适用于对性能有极致要求的场景,例如在嵌入式设备或服务器中直接调用模型进行AI图片生成,从而满足低延迟、高效率的内容创作需求。

weixin_42126677的博客 22

物流系统集成实战:从零开始用Java对接国际快递(DHL/FedEx/UPS)

本文详细介绍了如何使用Java技术栈对接DHL、FedEx和UPS三大国际快递巨头的API,构建高效、稳定的物流集成解决方案。内容涵盖认证机制、报文标准、多语言支持等关键点,并提供实战代码示例和最佳实践,帮助开发者快速实现国际快递系统集成。

efc1234567的博客 694

手把手写深度学习(27):如果获得相机位姿态的plücker embedding?以RealEstate10K为例

用plücker embedding表示相机的位姿是一种非常常用的方法,这篇博客以RealEstate10K数据集为例子,详细讲解如何从相机的轨迹坐标中获得plücker embedding,用于下一步模型的学习。

沉迷单车的追风少年 2239

李慕婉-仙逆-造相Z-Turbo C语言基础调用示例:轻量级嵌入式集成探索

本文介绍了如何在星图GPU平台上自动化部署李慕婉-仙逆-造相Z-Turbo镜像,并探索了其轻量级C语言调用方案。该方案使资源受限的嵌入式设备能通过网络API调用该AI模型,实现水墨画风格等特定场景的图片生成功能,为边缘AI应用提供了高效集成路径。

weixin_33363025的博客 109

C2000ware介绍

C2000的下载安装指南C2000目录。

小柚子的博客 2796

【硬核排障】Windows 下 Python 报 DLL load failed?从 CPython 编译机制讲透 VC++ 依赖地狱(附 AIO 修复包)

本文深入分析了Windows下Python报DLL加载失败的底层原因,主要涉及CPython解释器与MSVC运行库的依赖关系。文章指出: CPython核心和许多Python扩展库实质是通过C-API封装的DLL文件,依赖MSVCRT运行库 手动下载DLL文件存在架构兼容性和程序集注册问题 提供了DLL依赖链诊断脚本定位缺失文件 推荐使用微软官方VC++ AIO运行库合集进行修复 提供了包含静默安装脚本的完整修复包下载地址 解决方案避免了安装臃肿的Visual Studio,通过官方运行库即可解决DLL加载

ai-codex-python博客 213

芒果YOLO11改进176:2025最新顶会论文|尺度动态损失函数Scale-based Dynamic Loss,即插即用|以减少标签不准确对损失函数稳定性的影响

芒果YOLO11改进186:2025最新顶会论文|尺度动态损失函数Scale-based Dynamic Loss,即插即用|以减少标签不准确对损失函数稳定性的影响

包括YOLOv5、YOLOv7、YOLOv8等模型改进 2132

SAP MD81创建客户独立需求简介

正常我们用的最多的计划独立需求都是使用的是MD61 ,今天我们说下SAP的另外的一个标准功能客户独立需求MD81。虽然SAP给这个TCODE的描述是客户独立需求,但是实际是没有地方去关联对应的客户信息的。可以看到根据客户需求产生了对应的计划订单,我们创建的时候选择的KSV是按库存生产的,所以转换的时候生产订单也按单生产的。上面填写的这些字段的信息是不是和我们销售订单里面的字段的信息很相似。1)填写交货日期,可以选择按月 ,按日,按周等类型选择对应的日期。保存后会显示对应的客户独立需求的号码,如下图。

我小时候很黑的博客 2904

为什么从 esptool.py 转向 espflash:Rust 版 ESP32 串口烧录工具的 3 个硬核优势

做嵌入式开发的朋友,大概率都用过 esptool.py 给 ESP32 刷固件。但 Python 环境依赖、烧录后还得自己开串口监视器、无法融入 Rust 工作流——这些痛点,**espflash** 一次全解决了。 espflash 是一款基于 Rust 实现的 **ESP32 串口烧录工具**(Serial flasher utility),功能对标 esptool.py,支持 **ESP3

gitblog_00483的博客 649

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

嵌入式开发自学指南:从C语言到RTOS与Rust的实战路径

嵌入式开发是计算机系统与物理世界交互的核心技术领域,其本质在于通过微控制器或微处理器执行特定任务,实现对硬件设备的直接控制。其技术原理建立在底层硬件认知、高效的编程语言以及实时操作系统之上,通过直接操作寄存器、管理内存和处理中断来确保系统的可靠性与实时性。这一技术价值在于能够构建高可靠性、低功耗且响应迅速的系统,广泛应用于物联网、汽车电子、工业控制及消费电子等场景。对于初学者而言,掌握以C语言为核心的编程基础、理解ARM Cortex-M系列微控制器架构,并熟练使用如VSCode配合GCC和OpenOCD的

weixin_30482383的博客 529

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

在 Deepin 20.9 + N卡 930MX(2GB) 上跑 Qwen3.5 模型

折腾日志。

举世誉之而不加劝,举世非之而不加沮,定乎内外之分,辩乎荣辱之境,斯已矣。 863

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

你心中最硬核的中国芯是谁?

慕尼黑华南电子展将推出特色活动专区及活动包括:智慧出行科技园、物联网科技园、硬核中国芯科技园、特斯拉model3拆解秀,以及意在扶植华南初创企业的创新公园。通过更深入的交流学习及系统集成...

634

ARM Cortex-M1 FPGA软核:技术遗产、商业博弈与当代启示

在嵌入式系统与可编程逻辑领域,处理器软核扮演着连接硬件灵活性与成熟软件生态的关键角色。其核心原理在于通过硬件描述语言在FPGA内部构建可定制的计算单元,实现软硬件协同设计。这项技术的价值在于能针对特定应用优化性能与功耗,并复用庞大的现有软件资产。典型的应用场景包括实时控制、信号处理加速和高度定制化的嵌入式系统。ARM Cortex-M1作为一款专为FPGA优化的32位ARM处理器软核,正是这一技术路线的早期重要实践。它基于Cortex-M3架构深度裁剪,支持Thumb-2指令集与紧耦合内存(TCM),旨在将

weixin_30565327的博客 465
上一篇: C硬核:聊聊预编译指令和宏的应用场景(一)
下一篇: 浅谈MOS管的米勒效应
Cerman
博客等级 码龄11年 63粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cerman

你的鼓励是探索和创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值