【问题标题】:Read/write Arduino ports in llvm在 llvm 中读/写 Arduino 端口
【发布时间】:2020-12-12 01:43:21
【问题描述】:

为了避免ab解释,我的问题简而言之:

我想通过llvmC++ api读写Arduino端口D。

DDRD = 0xFF;
PORTD = 12;

阅读:

DDRD = 0x00;
int x = PORTD;

阅读更多:

我想知道如何通过llvm 读/写 Arduino 端口。我不是在追求特定的 AVR 微控制器,只需要一般知识。

我的努力是天旋地转,但没有奏效。我不确定那里是否支持我的需求。

https://godbolt.org/z/Wb5aGs

我在本地试过,

main.cpp

void foo(){
    DDRD = 0xFF;
    PORTD = 12;
}
clang++ -c -O0 --target=avr -mmcu=atmega328p -DF_CPU=16000000 -emit-llvm main.cpp

clang:错误:未知参数:'-mmcu=atmega328p'


如何通过 llvm::AllocaInst 实现此功能?或者通过llvm::LoadInst读取这个端口?

我主要是在C++ api 解决方案之后。 IR llvm 对我来说并不理想,但它会帮助我最终找到主要问题的答案。

【问题讨论】:

  • 不,因为不太可能有人知道您想要实现的目标。您同时在谈论使用 LLVM构建 东西,以及使用 LLVM API 或 IR。您的陈述“我想知道如何通过 LLVM 读取 Arduino 端口”毫无意义。您想知道如何从您编译的 C++ 程序中执行此操作,或者您自己生成 IR 时,或者什么。这个问题是不可理解的。请清楚地说出你的想法。您的第一个问题是您的 llvm 构建中没有 AVR 目标,或者您没有正确命名它。确保您了解可用的目标。
  • @UnslanderMonica,正如我所说,我在 LLVM api 之后。但如果没有人知道,我至少对 IR 感到满意。
  • 您在问题中没有陈述任何自洽的内容。为什么你认为你需要一个 LLVM API?你是什​​么意思?看起来你把事情搞混了。 LLVM API 不适用于使用 LLVM 编译的应用程序内部。它用于代码生成器、代码分析器、LLVM 传递/后端等。如果您询问如何从使用 LLVM 编译的 C/C++ 代码生成特定于目标的 I/O 端口输出指令,您必须查看文档将用于此的内在函数的目标。

标签: c++ arduino clang llvm llvm-c++-api


【解决方案1】:

llvm C++ api

不。这些话并不意味着你似乎在暗示什么。 “llvm C++ API”在您为 Arduino 等编译的程序中不可用。有关详细信息,请参阅此答案末尾的行下方。如果你真的有 LLVM C++ API,你就不会问这个问题,因为寄存器访问与任何其他常量指针解引用没有太大区别,并且不需要特殊处理。

首先请注意,Arduino 是一个概念,而不是任何特定的 CPU。您至少需要参考特定的 Arduino 模型,例如。 UNO,但最好说一下像 AVR 这样的特定架构。

假设这就是你想要的:AVR 上没有“端口”,所以你不需要做任何特别的事情。只需使用给定的固定地址写入内存 - C 和 C++ 在所有合理的平台上都支持它。

外设和 CPU 控制寄存器是内存映射的。因此,假设您在地址 0x1234 处有一个字节宽的控制寄存器。您可以将其定义为:

#include <stdint.h>
...
#define CREG (*(volatile uint8_t*)0x1234)

然后,CREG = 42; 语句会将值 42 写入地址 0x1234 处的该寄存器。这就是它的全部。您可以在给定 MCU 的文档中找到寄存器地址。

当然这只是第一步,你可能想要更高的水平 API比这个。我发现使用引用而不是这种邪恶的宏很实用。它们提供了更多的编译时类型安全性。在 C++ 中:

constexpr volatile uint8_t &CREG = *(volatile uint8_t)0x1234;
...
CREG = 42;

只读寄存器也​​是可能的:

constexpr volatile const char &RXD0 = *(volatile const char)0x5678;

RXD0 = 3; // won’t compile
char c = RXD0; // will compile OK

有时您需要执行多步操作来访问寄存器,例如。首先设置一些地址寄存器,然后通过访问寄存器间接加载它。访问器函数做得很好:

enum class AREG_ : uint8_t { QREG = ... };
constexpr volatile AREG_ &AREG = *(volatile AREG_*)0x3456;

inline void setQREG(uint8_t val) { AREG = AREG_::QREG; BREG = val; }

工具使用 LLVM API,即使用 LLVM 分析代码或生成代码的软件。您不能在使用 LLVM 编译的任意程序中使用 LLVM API,就像您不能在针对 AVR 的 Arduino IDE 中使用 gcc API,后者使用 avrg++ 为 AVR 目标进行编译。

LLVM IR 是前端产生的,而你 can’t embed IR within C nor C++,所以我也不知道你为什么问这个问题。

我仍然不知道您要做什么。你能用简单的话解释一下吗?您是否只想使用 clang 编译任意 Arduino 程序?您的问题特别令人困惑,因为您使用的词语具有明确的技术含义,但您以一种合在一起没有意义的方式使用它们。

【讨论】:

  • 非常感谢您的回答。我正在使用 llvm c++ api 开发一个用于编译到 arduino 目标的工具。我的工具是用 C++ 编写的。
  • 我想我可能有一些想法。如果内存映射端口的地址是 1234,则向其写入值 56 涉及new StoreInst(ConstantInt::get(..., 56), ConstantExpr::getintToPtr(ConstantInt::get(..., 1234) , …), …);
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多