专栏首页裸机思维大白话存储器模型(1)——“一个藤上七朵花”

大白话存储器模型(1)——“一个藤上七朵花”

【前言其一—— 你听说过 Memory Model 么】


不知道读者中有多少人听说过 Memory Model 这个概念,中文通常翻译成存储器模型,实际上,这种直接对英文单词的机械翻译为大部分人带来了巨大的误解——很多没有没有接触过Memory Model实际内容的小伙伴可能都会像我当年一样望文生义,以为它是关于:

  • 描述存储器结构的一种模型
  • 描述各类ROM、RAM特点和差异的数学或者设计模型
  • 描述各种常见存储器分配的算法模型,比如栈(STACK)、堆(HEAP)以及池(POOL)等等

然而 Memory Model 和上述内容一点关系都没有。不得不说,这是一个由不走心翻译所毁掉的概念。Memory 在这里并不能直接翻译为“存储器” ,它实际上是一个类似行业黑话(Jargon)的缩略语,而Memory Model真实想讨论的议题是:当我们把目标对象(比如外设等)“当做普通存储器”一样来访问时,这个存储器有啥特点——在这里,“当做普通存储器” 对应 Memory 这个词,而 Model 则更接近“为理解和体现某些特点而建立的模型”——用大白话来说就是:

  • 有一个本身可能不是存储器的外设或者加速器;
  • 为了方便类似C/C++这样的高级语言来访问这样的设备,我们把这个设备映射到一段地址空间中,从而把它当成一个存储器一样来访问;
  • 毕竟,这是一个模拟出来的存储器——那么这个模拟出来的存储器有什么特点?有什么注意事项?我们访问的时候会遇到什么问题呢?——不妨用一个模型来描述一下这些特点和行为方便更为广泛的讨论。

一言以蔽之:当我们把某个东西映射到地址空间中、当成一个普通存储器一样的来访问的时候

  • 有哪些坑在前方等着我们?
  • 它们的现象是什么?
  • 后果是什么?
  • 由什么导致?
  • 如何解决?
  • 它跟我们常见的各类Hardfault有什么关系?
  • 它跟系统性能优化有什么关系?

如果你对上述问题一头雾水,甚至不知从何谈起,那就不妨随着本系列一点一点抽丝剥茧——慢慢来学吧。


首先,可能浮现在你脑海里的第一个问题就是:你说这里的 Memory 是“把目标对象当做存储器一样来访问”——就以寄存器为例子——难道还有“不把目标对象当做存储器一样”来访问的方式么?

还真的有!回想一下,你怎么访问普通存储器?是不是C语言里只要知道目标变量的地址就可以用指针进行访问了?——通过地址进行访问就是“像存储器一样访问”的最大特点。当我们用指针访问外设寄存器的时候,可以说:我们是把这些寄存器映射在地址空间中——当做普通存储器一样通过地址来访问它们。与之相对,有一类寄存器必须借助特殊的指令或者其它手段才能访问,比如CONTRL寄存器、PRIMASK寄存器等等——这些Cortex-M的“特殊功能寄存器”只能通过专门的指令“MSR和MRS”以指名道姓的方式进行读写——它们就不属于一般意义上Memory Model所要讨论的范畴,而是开发者模型(Programmers' Model)所要关心的内容。


【前言其二 —— Memory Model 对我们真的有意义么?】


从实践经验来看,很多从事嵌入式开发不下3年甚至更久的小伙伴可能会心生疑惑:我搞了这么久的嵌入式开发,不懂所谓的 Memory Model 似乎也没觉得有啥不方便啊?

其实,这是因为很多我们常见的微控制器,比如各类Cortex-M0/M0+/M3/M4 使用的都是最简单的 Memory Model,而这类最简Memory Model的特点就是简单易用——你之所谓感觉不到它的存在,是因为这类简单 Memory Model 中很少存在陷阱——当然也不是没有陷阱,只不过我们已经非常熟悉他们了,比如:

  • 对齐和非对齐访问的问题
  • volatile 的使用问题
  • 地址空间布局的问题(linkscript相关的问题)

是的,以上问题其实都是 Memory Model 所涉及的一些非常具体的点,所谓“不闻庐山真面目,只缘身在此山中”是也。对上述话题感兴趣的小伙伴,可以单击这里查看相关的文章。

Memory Model 绝非仅有这些内容而已,实际上,你们所接触的部分仅仅是简单MCU所使用的简化 Memory Model,而随着芯片资源愈发丰富:

  • 更大的FLASH和SRAM
  • 更多类型的存储器,比如 TCM、Cache、XIP、DDR
  • 更复杂系统结构,比如多个Cortex-M核,或者Cortex-M与其它类型的加速器放置在同一个SoC里,甚至是Cortex-M与Cortex-A/R混搭的结构等等

我们的面前事实上出现了一座名为 Memory Model 的冰山——如果不能了解掩藏在水面之下的全貌,当我们拿到新一代的芯片,比如 NXP的 i.MX系列,ST的STM32F7/H7/M1系列;面对新一代的内核Cortex-M7/M33/M55,即便不全军覆没,也必然是损失惨重。

这里,有的小伙伴会问了:Memory Model 复杂么?有什么书可以看么?你这个系列会介绍到什么程度呢?

Memory Model 本身相当庞杂,但具体每一个知识点却非常简单,也容易理解;遗憾的是,Memory Model 最终所要解决的问题却不是 1+1=2 这样的简单。


我们不妨打个比方:

  • 小时候,爸妈给了你几百块压岁钱,让你自己支配,你决定为自己组装一个心怡的四驱车;
  • 四驱车看似是跑得越快越好,但实际上要考虑很多细节——具体包括但不限于:如何才能过弯道的时候不直接冲出赛道?马达的加速能力和轮胎材质如何配合?如何取舍重量和各类金属框架结构带来的好处等等……
  • 你可以从小店老板、同伴和杂志上了解和学习了每一个配件的特点,价格——甚至做到了如指掌,如数家珍
  • 但你在最终如何做出最优的排列组合,最大化的发挥预算获得最优性能的问题上仍然会纠结良久——甚至无法说服明天的自己。

在一个嵌入式系统中,Memory Model 所关心的是访问的功能正确性与数据吞吐量之间的平衡问题,而在这一过程中,即便你了解了每一个简单的知识点,在面对最终的性能和功能正确性的平衡问题时,也会同样纠结良久——问题没有标准答案,只有较优解和更优解之间的区别

在了解了Memory Model所要解决问题的复杂性和开放性后,你一定能想象出对其进行介绍和讨论的书籍与文章可谓灿若星海。你甚至可以认为经典的研究生教材《Computer Architecture》很大的篇幅其实就在介绍流水线、Memory Model以及流水线和Memory Model之间的各种“爱恨情仇”。

本系列的目的就是以连载的方式、通过一系列专题文章,慢慢为您介绍Memory Model 所涉及的一些简单知识点、讨论它们在实际嵌入式开发中会给我们带来怎样的麻烦、以及如何解决这些问题。我当然不是要写教科书,所以选题可能会有所偏重,无法面面俱到,但相信我所偏重点的也是大家所最关心的——

作为一个普通嵌入式程序员:

  • 有哪些必须知道的 Memory Model的知识? 如何使用这些知识解决遇到的问题?
  • 如何写出正确而可靠的代码?
  • 如何提升代码的性能?

闲话少说,让我们开始吧。

【总线——故事开始的地方】


应该没有哪个从事嵌入式开发的软件工程师没听说过总线这个概念吧?然而,大部分情况也仅限于此——也就只知道总线是用来传输数据的,存储器啊、外设啊、内核啊、DMA都连接在上面。受到芯片数据手册的影响,在大部分人的心中,总线是一个盘根错节的复杂网络,如“何首乌和木莲藤”那般“缠络着”。

一方面,看到Cortex-M的官方文档和权威指南有提到一些诸如AMBA、AHB、APB、PPB之类半懂不懂的名词;另一方面,总线本身的存在对日常的软件开发来说似乎就是个小透明——这一切的一切加在一起,给人营造了一种“不要问,问就是一团乱麻;不要提,提就一堆高大上的名词”的难以名状的复杂心情——你说她犹抱琵琶半遮面很诱人吧,它又经常“洒家装逼关你鸟事?

其实,作为本系列故事开始的地方,有几个关于总线的误解还是需要澄清的,即,就软件开发工程师来说:

  • 并不需要关心总线的时序是怎样的,但一定需要知道特定总线的“能耐”和“忌讳”
  • 并不需要知道总线工作的细节,但一定要知道总线有哪些特殊的功能
    • 这些功能是解决什么问题的?
    • 有什么特殊的脾气?
    • 编写软件的时候有哪些注意?
  • 总线和时钟系统是什么关系
  • 总线和功耗是什么关系
  • 总线和性能是什么关系
  • 总线和地址区间是什么关系

【主从“关系”可不是你想的那样“简单”】


从模型上来说,首先要抛弃“总线是一个网络”的想法——不是说总线不是网络,而是说实际上不能“直接”将总线看做一个网络。为什么这么说呢?

首先,需要明确区分,我们这里所讨论的总线并不包括一般的外设总线,比如SPI、I2C等等。我们说的是用于芯片内部数据通信的总线。

其次,这里所说的总线实际上有主机(Master)和从机(Slave)两种角色——多嘴一句,目前国外受到政治正确风潮的影响,主流的架构和芯片公司正在寻求使用新的单词来替代过去的Master和Slave这样的说法,而具体用哪些单词来替代,目前仍无定论,唯一确定的是,Master和Slave这样的敏感单词是肯定不会继续使用了。这里,主机的特权是可以主动的发起数据传输。每一个主机都直接与自己可能会访问的从机相连——从主机看来,自己就是一个小的星状结构的核心——自己位于正中间,而那些从机“你们都是我的翅膀”。

然而,一个系统中不可能只有一个主机,且不说多核MCU了,普通的单核MCU也有多个主机——比如,DMA至少拥有一个总线主机、以太网控制器、USB控制器都有总线主机接口,换句话说,它们都能主动的发起数据通信。这里需要特别强调的是,主机与主机之间是不可能进行通信的——你可以认为这帮“极端自我中心主义”的主机们“老死不相往来”;它们甚至人人都武断的认为自己独占整个芯片,所有的从机都是它鱼塘里的鱼。

然而,“小丑居然是我自己”,主机自己为是后宫之主,其实想想也知道,每个从机其实都脚踏n之船——谁还不是个海王?

在每个从机看来,不光自己是“女神”、拥有一个独占的逆后宫——同样拥有一个星状的网络——而且她切实的拥有一个所有主机都不曾享有的特权:当多个主机都主动发出(通信)邀请时,她可以一边说“你们不要争了啦~”,一边任性的决定“今天想临幸谁就临幸谁”——是的,总线仲裁的大权是在从机手里的

另外补充一句,从机之间也是极端自我,老死不相往来的。

现在,聪明的你一定明白了:单独从每一个个体看来(无论是主机还是从机),自己都拥有一个极其简单的星状连接关系,而且自己都是这个结构的中心。站在上帝视角的我们会发现,正是这种“互为鱼塘”的混乱关系造就了所谓的总线网络——学名叫 Bus Matrix——八卦一点来说就是谁跟谁有一腿,谁跟谁不对付的一张图。是不是突然就无法直视数据手册中的总线矩阵了呢?

主机:我想追谁就追谁

从机:我想选谁就选谁

【说个笑话:在SRAM里执行代码】


现代32位的微控制器通常都有流水线的概念,无论结构多复杂,可以近似的认为在流水线的起点有一个负责指令读取(Instruction Fetch)阶段叫IF;而在流水线后半部分,负责指令执行的阶段,也会有从地址空间中读写数据的需求。简单来说,一个流水线温饱的最基本要求就是两个:通过总线读取指令,以及通过总线读写数据。

  • 如果处理器在满足这两个需求的时候,给它们一人分配了一个独立的主机,则称为“改进的哈佛架构”:
  • 如果处理器单纯为了追求自身结构的简单(同时也为了降低功耗),让它们共享同一个主机,则称为“冯诺依曼架构”:

对比下来,你会发现,由于冯诺依曼结构让“指令读取”和“数据访问”在“窝里”就开始“斗”了——还没有上总线就开始争抢主机的使用权,因而从一开始就遇到了“自古指令与数据不可两全”的系统性难题。这样的结构从一开始就存在性能瓶颈。

然而,拥有两个主机接口的哈佛总架构也只是理论上可能进行指令读取和数据访问同时进行,回想一下,如果这两个主机同时向同一个从机“示好”,你说从机还不是要“二选一”?具体到实践中,比如芯片里只有一个SRAM从机,如果你把程序也放在SRAM里运行,显然就相当于直接把哈佛结构当冯诺依曼用了……

当然,换个角度思考,如果一款芯片有多个SRAM从机(而且他们的地址不是交错在一起的),如果程序放在一个独立的SRAM从机里,而数据放在另外的SRAM从机上,本质上就是为两个主机各自分配了一个老婆,自然皆大欢喜。

更进一步,一款芯片虽然FLASH较慢,但考虑到FLASH拥有独立的从机,而且假设该从机配备有自己的高速缓存(因此速度也不是大问题),此时,如果强行把代码拷贝到系统唯一的SRAM里运行——并美其名曰:SRAM速度比FLASH快,这样我可以提高性能——所有这里看懂了的小伙伴就都要要呵呵了。

【大师,我悟了,世上时钟只有两种……】


不管你之前听说过没有——总线上是有时钟的,而时钟的作用自然是帮助数据传输的。为了访问存储器或者映射在总线上的外设寄存器,总线都为它们提供了一个时钟源——如果主机想读取存储器中的内容,或者是想操作寄存器,则目标从机都必须使用该时钟源,或者是该时钟源整数分频后的结果。

然而,从机有的选么?是的从机有的选——对于总线所提供的时钟源,外设可以选择我用还是不用——或者说使能还是不使能:

  • 如果使能了,则主机就可以正确的访问目标存储器或者寄存器的内容;
  • 如果不使能(或者说拒绝了),则主机就无法正确访问从机,其结果是“不确定的”——即可能是bus fault,也可能是读了个寂寞(但没有触发错误);

在我们开始后续内容之前,请首先在大脑中默念:

“总线时钟的作用只是为了数据访问”

“总线时钟的作用只是为了数据访问”

“总线时钟的作用只是为了数据访问”

……

然而,外设和存储器工作也是需要时钟的啊(我们称为外设时钟),这时候有些外设就动了歪脑筋:干嘛辛辛苦的去考虑时钟源从哪里来的问题,咱们直接用总线时钟就好了嘛——概念上,我们把总线时钟,以及总线时钟分频后的时钟都称为同步时钟。这里的同步就是“跟总线时钟保持同步”的意思

虽然很羡慕,但有一些外设处于各种跟样的原因,没法直接使用同步时钟来完成自己的工作,因此它必须要另外寻求一个额外的时钟源来作为自己的外设时钟,正因为“此时的”时钟往往无法直接从同步时钟分频而来,因此,我们又把这类额外提供给外设实现功能的时钟称为异步时钟——这里的异步强调的就是时钟源与总线时钟不同步。

对于这种拥有异步时钟的外设,同步时钟的作用就单纯只是用来实现寄存器访问了——外设的功能完全由异步时钟来确保。这就造就了以下两种奇观:

  • 同步时钟开启,但异步始终关闭——可能是为了低功耗,由于外设暂时不需要工作,但是却需要访问寄存器,因此关闭了异步时钟,而开启了同步时钟;
  • 同步时钟关闭,但开启异步时钟——仍然可能是为了低功耗,由于寄存器连接到同步时钟时会产生动态功耗(后面会介绍),如果应用确认不会在外设工作的时候修改外设寄存器的内容,就可以干脆把该外设的同步时钟关闭了,从而实现了降低功耗的目的。这样做还有一个功能,就是实现了寄存器的只读化——没有同步时钟,你根本没法修改寄存器的内容;
  • 同步时钟和异步时钟都关闭——彻底没有动态功耗了。
  • 同步时钟和异步时钟都开启——马力全开,功耗最大。

总结来说,芯片里的时钟以总线为中心实际上只有两种:与总线同步的,以及与总线异步的。外设时钟既可以直接使用同步时钟——比如很多定时器就是这么做的——也可以使用额外的时钟源,比如USB、I2S等就是这么做的。

芯片复位后,为了降低功耗,很多外设的时钟默认都处于关闭状态,在访问它们之前,不光要开启同步时钟,如果存在异步时钟,一样不要忘记正确的配置哦。最后,千万不要混淆外设时钟(Peripheral Clock)和总线时钟的概念。

【功耗管理的半壁江山】


现代的微控制器,往往可以对外设和存储器的功耗进行精细的控制。之所以可以这么做是因为,一个外设的功耗分为两大部分:

  • 只要通电就一定会存在的静态电流——也就是传说中的静态功耗,要想关闭它只有一个办法,就是拉闸断电。芯片设计上,一般把芯片拆分成很多区域,这些区域可以独立的控制供电——我们称为电源域(Power Domain)。通过控制电源域来控制功耗的方法称为Power-Gating(供电管理);
  • 在通电的情况下,只要有时钟翻转就会产生额外的功耗——也就是传说中的动态功耗。动态功耗是由于逻辑门翻转产生的,因而跟时钟频率存在二次方的关系。降低功耗的方法就是降低频率,甚至直接关闭时钟。芯片设计上,一般把数字电路拆分成很多区域,这些区域可以独立的控制时钟的频率和开关——我们称为时钟域(Clock Domain)。通过控制时钟开关来实现低功耗的方法称为Power-Gating(时钟管理)。

如大家所见,时钟管理实际上是整个功耗管理的半壁江山,因此按需开关外设的同步和异步时钟就是降低芯片总体功耗的关键之一。由于本系列着重介绍 Memory Model,这里功耗管理的部分只是在讨论总线时钟的时候顺带提及,因此将不做进一步展开。

【后记】


Memory Model中存在大量面向软件的抽象概念,而这些概念的硬件基础就是总线及主/从机间的各类错综复杂的“八卦”关系。实际上,在芯片设计者看来,总线(及配套的时钟和电源管理设施)才是整个芯片平台的本体:你要啥内核、要多大的存储器、要什么外设集合都可以像组装电脑一样——你要啥我就给你装啥。

从结构上来看,一个芯片系统本质上就像葫芦藤——总线是支撑整个系统的藤蔓,而扮演各种功能角色的模块则像葫芦一样挂在上面,熙熙攘攘的叫着“爷爷”,等着属于他们的高光时刻。

下一篇,我们将从最基本的数据传输开始,聊一聊总线和系统性能之间不得不说的那些事儿。

本文分享自微信公众号 - 裸机思维(bare-metal),作者:GorgonMeducer 傻孩子

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-03-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 七夕节送礼怎么让女朋友满意?快来抄作业!

    没有人不被这个亘古难题困住的,尤其是男性,在为女性挑选心爱的礼物方面,更是左右为难。

    数据STUDIO
  • 【典型案例】如何使用机器学习帮助你快速成为花朵分类专家

    随着信息时代的发展,伴随着照相装备和图片采集设备的普及,越来越多的图片数据广泛存在于生产生活的各个角落,如何对海量图片数据进行高效的分类和检索成为了一项新的挑战...

    腾讯云TI平台
  • 【新版典型案例】如何使用机器学习帮助你快速成为花朵分类专家

    图像分类是计算机视觉中重要的基本问题,也是目标检测、行为跟踪、图像分割等其他任务的基础。图像分类的应用涵盖交通、安防、医疗、政府、互联网等多种领域,其应用场景包...

    腾讯云TI平台
  • [总结] 与大脑智能相关的重要心理学术语

    本文小结一些在心理学领域定义的与大脑智能相关的重要术语:工作记忆、短期记忆、长期记忆、情节缓冲、视觉空间画板、语音回路、排练、以及中央执行。心理学家们把概念玩得...

    用户1908973
  • [第二波] QTX个人艺术家限定品公布!

    ? 五一假期去哪里? 5月1日-5月3日 深圳福田会展中心 QQ潮玩展   200+潮玩限定品 更有[QQ潮玩]重磅新品和限定品 整装待发,等你来冲! 前天...

    腾讯ISUX
  • 【典型案例】利用AI技术快速识别物体种类之火眼金睛目标检测

    目标检测任务在计算机视觉和数字图像处理领域扮演着重要角色,在各行各业也已得到广泛应用,如航空航天、机器人、智能监控等重大行业。精准地从图片中识别出目标所在位置,...

    腾讯云TI平台
  • 从零开始制作一个数据集

    下载完成之后需要人工筛选一下,里面会夹杂一些乱七八糟的图片,以及主体不是目标的图片,筛选两三遍,最后可能也就找几百张,像前面别人做好的数据集那样一下 60000...

    yichen
  • 【Python环境】Python分类现实世界的数据

    引入 一个机器可以根据照片来辨别鲜花的品种吗?在机器学习角度,这其实是一个分类问题,即机器根据不同品种鲜花的数据进行学习,使其可以对未标记的测试图片数据进行分类...

    陆勤_数据人网
  • 微信改版 | 从开屏动画看微信与头条理念之争

    12月21日,微信在App Store发布了7.0版本,首次运行时的开屏动画为蓝天背景下的一枝摇曳的格桑花,图上配有文案:因你看见,所以存在。张小龙...

    Python中文社区
  • 深度学习100例-卷积神经网络(VGG-19)识别灵笼中的人物 | 第7天

    本文将实现灵笼中人物角色的识别。较上一篇文章,这次我采用了VGG-19结构,并增加了预测与保存and加载模型两个部分。

    K同学啊
  • 小白入门最简单的机器学习算法

    阅读本文大概需要3分钟 菜鸟独白 上一篇(菜鸟学机器学习启航篇)对机器学习做了初步的介绍,机器学习的算法有很多,小白开始学习的时候,往往会被弄晕。有没有比较简单...

    企鹅号小编
  • 模仿人类智慧——“多任务学习”动手实践

    用户1737318
  • 【编程心里】编程大牛教你正确的学习心态

    小明问大师,大师我已经开始学习c语言编程了为什么感觉我只会用他做数学题,而不能写自己想写的游戏呢? 大师看着地上的教学文章不说话; 小明说大师你是让我静心学习之...

    程序员互动联盟
  • 深度好文丨黎斌:《易经》“数相”与“大数据”

    导读:人类已迈进“大数据”时代,当前学术界对“大数据”的研究较多,但从易学角度进行研究的却很少。该文从易学视角,以独特的《易经》数相思维,论述和研究了“大数据...

    灯塔大数据
  • 关于5G的SA与NSA架构

    今天又一次看了何同学的5G的视频,从视频上看了关于何同学讲联通试运行的是NSA架构,SA架构还在研发试运行中,我就纳闷了,作为一个计算机行业的学生,怎么不明白这...

    Meng小羽
  • 情人节脱单必备,程序员如何花式表白

    今天是七夕,一个对单身人士不怎么友好的一个节日,而对于已经有另外一半的情侣来说,今天应该是开心的一天,鲜花与巧克力也必然是在送去的路上。而对于众多程序员小哥哥们...

    用户6888863
  • 由浅入深的前端面试题 和矫情的“浪漫主义”诗句

    好吧,我承认太标题党了,这篇文章是通过一道前端面试题引出的纯技术讨论。我先要矫情无比的从中外诗歌说起。 传统的佛学经典里,被世人熟知的有这样一句话:“一花一世界...

    用户1667431
  • 今天给大家讲一个故事~

    张三的爱情故事:怎样用大数据思维追到“某江商学院”的美女班花 传统思维里,美女是产品,土豪是消费者。但事实上,土豪追求美女的过程即是打造自己、推销自己的过程。从...

    CDA数据分析师
  • 张三的爱情故事:怎样用大数据思维追到“某江商学院”的美女班花

    张三的爱情故事 传统思维里,美女是产品,土豪是消费者。但事实上,土豪追求美女的过程即是打造自己、推销自己的过程。从这个角度说,他们自己才是产品,而美女却是消费者...

    小莹莹

扫码关注云+社区

领取腾讯云代金券