解决有关C/C ++的知识和注册访问方面的差距 [英] Fixing Gap in knowledge about C/C++ and register access

查看:46
本文介绍了解决有关C/C ++的知识和注册访问方面的差距的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

诚然,我是C ++的新手.不幸的是,我所看到的大多数代码要么使用asm调用,要么定义了一个extern函数,其主体位于汇编文件中.

Admittedly I am new to C++. Unfortunately most of the code I have seen either uses the asm call or defines an extern function whose body is in an assembly file.

这就是为什么我很想找到以下代码的原因.我已经研究了代码库 3天了.

Which is why I was very exited to find the below code. I have been studying the codebase for 3 days now.

从语法上我理解下面的代码的每一行;除了因为我不了解它的工作原理而重要的那一个!

Syntactically I understand every line of the code below; except the one that counts because I don't get how it works!

  1. types.h定义了u32uintptr(我见过它们)
  2. 当C和C ++代码混合在一起时,需要
  3. ifdef __cplusplus.特别是由于extern C是C ++特定的.如果gcc具有-fno-exceptions参数
  4. ,则可以省略
  5. volatile用于防止编译器进行任何优化,因为地址必须是完美的,因为它是在向寄存器中写入/从寄存器中读取/读取的.
  1. types.h defines the u32 and uintptr ( I have seen them)
  2. ifdef __cplusplus is needed when C and C++ code are mixed. Particularly because of the extern C which is C++ specific. Can be omitted if gcc has the -fno-exceptions argument
  3. volatile is used to prevent the compiler from doing any optimization because the address has to be bite perfect since it's writing/reading to/from registers.

所有这些,我仍然不知道这段代码实际上是如何从寄存器中写入或读取的.

All that said, I still have no idea how this code actually writes or reads from the register.

#include <circle/types.h>
#ifdef __cplusplus
extern "C" {
#endif

static inline u32 read32 (uintptr nAddress)
{
    return *(u32 volatile *) nAddress;
}

static inline void write32 (uintptr nAddress, u32 nValue)
{
    *(u32 volatile *) nAddress = nValue;
}

#ifdef __cplusplus
}
#endif

#endif

*(unsigned int *)是什么意思?如何将其用于读取和写入寄存器?不必nAddress必须是物理地址

What does *(unsigned int *) mean? How is this used to read and write to a register? Wouldn't that nAddress have to be the physical address

推荐答案

您正在寻找"

CPU与外部硬件通信的最常见方式是通过内存总线-用来访问普通内存的总线.

The most common way for CPU to talk to external hardware is through memory bus - the same bus that is used to access normal memory.

首先,请记住,CPU与内存的交互不仅涉及读写,还涉及总线错误处理(无效访问),仲裁(多个设备访问同一内存)和路由(CPU可能要访问多个内存)存储设备).为了解决这个问题,使用了 bus协议.

First, keep in mind that CPUs interaction with memory involves not just reads and writes, but also things like bus error handling (invalid access), arbitration (multiple devices accessing the same memory) and routing (CPU might want to access multiple memory devices). To handles this, a bus protocol is used.

要写入或读取外部存储器,CPU必须启动事务.确切的顺序由使用的总线协议定义,但通常涉及以下步骤:

To write or read external memory CPU has to initiate a transaction. The exact sequence of this is defined by used bus protocol, but it usually involves steps like:

  • 发送交易地址,类型,长度等
  • 接收响应-允许或拒绝(总线错误).
  • 如果允许交易,则传输实际数据.

发起交易的设备称为 master initiator ,而负责处理交易的设备称为 slave 目标.

The device that initiates transcation is called master or initiator, while device that is responsible for handling the transaction is called slave or target.

决定哪个从站处理事务的设备称为 decoder router .因此,交易通常会从主设备转到解码器,再到从设备.

Device that decides what slave handles the transaction is called decoder or router. So transaction will usually go from master to decoder and then to slave device.

总线协议本质上提供了一种向设备传输数据或从设备传输数据的方法.该设备可以是存储设备,也可以是其他任何设备.对于存储设备,其控制器通过向存储单元阵列写入数据或从存储单元阵列读取数据来处理事务.

Bus protocol essentialy provides a way to transfer data to or from a device. This device can be a memory device or anything else. In case of memory device, its controller handles transcations by writing or reading data to or from memory cell array.

如果您熟悉面向对象的编程,可以考虑将CPU通过接口连接到外部设备,该接口允许在指定地址进行读写.该接口的实现可以执行任何操作.这就是完成内存映射I/O的方式-CPU连接到一堆设备,每个设备都在特定的地址范围内接收事务.将数据写入一个地址,该数据将由存储设备接收,该存储设备会将其存储到存储单元阵列,将数据写入另一个地址,并由SD控制器接收,并且将其解释为发送SEND_STATUS命令到SD卡".

If you are familiar with Object Oriented Programming, you can think of CPU being connected to external devices via interface which allows reading and writing at specified address. Implementation of this interface can do anything. And this how memory mapped I/O is done - CPU gets connected to a bunch of devices, each receiving transactions at specific address range. Write data to one address and this data will be received by memory device which will store it to memory cell array, write data to another address and it will be received by, lets say, SD controller and will be interpreted as "send SEND_STATUS command to SD card".

如果您还熟悉现代操作系统,则可以想到一切都是文件"的抽象.有些文件只是普通文件,例如他们充当记忆.其他文件是不同的.就像在Linux上阅读/proc/cpuinfo会为您提供有关CPU的信息一样,在某个地址处进行阅读可以为您提供有关当前正在挂起的IRQ的信息,或者告诉您当前邮箱有多少传入消息.

If you are also familiar with modern operating systems, you can think of "everything is a file" abstraction. Some files are just plain files e.g. they act as memory. Other files are different. Just like reading /proc/cpuinfo on Linux gives you information about your CPUs, reading at some address can provide you with information on what IRQs are currently pending or tell you how many incoming messages mailbox has at the moment.

总线协议的示例为 AXI AHB . AHB更简单,AXI更复杂且协议更快.对于Raspberry PI,很可能是AXI协议用于将CPU连接到硬件.

Examples of bus protocols are AXI and AHB. AHB is simpler, AXI is more complex and faster protocol. In case of Raspberry PI it is most likely AXI protocol that is used to connect CPU to hardware.

因此,关于您的问题,这两个功能用于通过内存映射的I/O访问外部设备的寄存器.您做对的所有其他事情:

So regarding your question, those two functions are used to access registers of external devices via memory mapped I/O. Everything else you got right:

  • volatile用于防止编译器删除,重新排序或以任何方式更改这些内存访问-没有此硬件将无法实现我们想要的功能.
  • 使用
  • u32的原因是,许多设备甚至不支持32位访问,而是保持硬件简单.
  • volatile is used to prevent compiler from removing, reordering or in any way changing those memory accesses - without this hardware will not do what we want it to do.
  • u32 is used because many device will not even support anything but 32-bit accesses to keep hardware simple.

这篇关于解决有关C/C ++的知识和注册访问方面的差距的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆