Read/write llvm 中的 Arduino 端口
Read/write Arduino ports in llvm
为了避免误读,我的问题简而言之:
我想通过 llvm
C++ api.
读写 Arduino 端口 D
写
DDRD = 0xFF;
PORTD = 12;
阅读:
DDRD = 0x00;
int x = PORTD;
阅读更多:
我想知道如何通过 llvm
read/write Arduino 端口。我不需要特定的 AVR 微控制器,只需要一般知识。
我的努力是天赐良机,但没有奏效。我不确定那里是否支持我需要的东西。
我在本地试过了,
main.cpp
void foo(){
DDRD = 0xFF;
PORTD = 12;
}
clang++ -c -O0 --target=avr -mmcu=atmega328p -DF_CPU=16000000 -emit-llvm main.cpp
clang: error: unknown argument: '-mmcu=atmega328p'
如何通过 llvm::AllocaInst
实现这个?或者通过 llvm::LoadInst
?
读取这个端口
我主要是在C++ api
解决之后。 IR llvm 对我来说并不理想,但它会帮助我最终找到主要问题的答案。
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,就像您不能在 Arduino IDE 目标 AVR 中使用 gcc API 一样,它使用 avrg++为 AVR 目标编译。
LLVM IR 是前端产生的,而你can’t embed IR within C nor C++,所以我也不知道你为什么问这个。
我还是不知道你想做什么。你能用简单的话解释一下吗?您只想使用 clang 编译任意 Arduino 程序吗?您的问题特别令人困惑,因为您使用的词语具有明确的技术含义,但您以一种毫无意义的方式使用它们。
为了避免误读,我的问题简而言之:
我想通过 llvm
C++ api.
写
DDRD = 0xFF;
PORTD = 12;
阅读:
DDRD = 0x00;
int x = PORTD;
阅读更多:
我想知道如何通过 llvm
read/write Arduino 端口。我不需要特定的 AVR 微控制器,只需要一般知识。
我的努力是天赐良机,但没有奏效。我不确定那里是否支持我需要的东西。
我在本地试过了,
main.cpp
void foo(){
DDRD = 0xFF;
PORTD = 12;
}
clang++ -c -O0 --target=avr -mmcu=atmega328p -DF_CPU=16000000 -emit-llvm main.cpp
clang: error: unknown argument: '-mmcu=atmega328p'
如何通过 llvm::AllocaInst
实现这个?或者通过 llvm::LoadInst
?
我主要是在C++ api
解决之后。 IR llvm 对我来说并不理想,但它会帮助我最终找到主要问题的答案。
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,就像您不能在 Arduino IDE 目标 AVR 中使用 gcc API 一样,它使用 avrg++为 AVR 目标编译。
LLVM IR 是前端产生的,而你can’t embed IR within C nor C++,所以我也不知道你为什么问这个。
我还是不知道你想做什么。你能用简单的话解释一下吗?您只想使用 clang 编译任意 Arduino 程序吗?您的问题特别令人困惑,因为您使用的词语具有明确的技术含义,但您以一种毫无意义的方式使用它们。