通过系留(主机)PC 的串行线路对 Arduino/Atmel328 进行机器编码

Machine coding an Arduino/Atmel328 over a serial line from a tethered (host) PC

我正在尝试为 AVR Atmel 328 芯片编写一个程序,它允许我通过串行线向芯片发送机器代码指令,run/execute 他们在芯片上,并通过读取芯片内存并通过串行线将内容发回来查询结果。这是这个想法的起源:3-instruction Forth by Frank Sergeant.

远程存储和远程获取指令似乎工作正常,但我无法使远程调用指令(XCALL() 函数)工作。 我采用的方法是通过将 16 位地址转换为函数指针将其强制转换为子例程。

下面是 Arduino Nano 上 运行 的代码(在 Arduino IDE 中编译并通过引导加载程序使用 USB 数据线上传)

任何见解将不胜感激! (如果有帮助,我可以添加反汇编代码、我的远程指令等)。

提前致谢!

// Remote serial development platform for machine coding ArduinoNano/ATmel328, AKE, Jun 9, 2020

// global variables
unsigned char byt;                  // command token from host
unsigned char mem[255];             // memory window under programmatic control
unsigned char dat;                  // data byte from host
unsigned char adr_lo;               // address from host, low byte first
unsigned char adr_hi;           
unsigned short adr;                 // combined 16-bit address
typedef void (*GeneralFunction)();  // template to call memory address (as a subroutine)

void setup() {
  Serial.begin(9600);              // Turn UART serial protocol ON for comms with host PC
  Serial.write(0xFF);              // magic number to verify transmission
  Serial.write(0xFE);
  Serial.write((int) mem);         // Informs you of the writeable address space available (LSB, MSB) for tethered memory access
  Serial.write((int) mem>>8);      
}

char get_byte(void) {
    while (!(Serial.available()>0)) { delay(50); }
    return Serial.read();
}
short get_adr(void) {
    adr_lo=get_byte();
    adr_hi=get_byte();
    return ( (short)adr_hi<<8 )   |   (short)adr_lo;
}
void xstore() {             // Instruction 1 = xstore(data,adr_lo,adr_hi).  Store byte from host at indicated address in target.
    dat=get_byte();
    adr=get_adr();
    *(char *)adr=dat;
}
void xfetch() {             //  Instruction 2 = xfetch(adr_lo,adr_hi).  Read byte from target memory and return to host.
        adr=get_adr();
        dat=*(char *)adr;
        Serial.write(dat);
}
void xcall() {              //  Instruction 3 = xcall(adr_lo,adr_hi).  Execute subroutine in target memory from indicated address.
                            //  WARNING!  User must have stored RET instruction to send control back to serial monitor.
        adr=get_adr();
        GeneralFunction fGf=adr;
        fGf();
}

void loop() {
    byt = get_byte();               // user specified instruction token (1,2,3)
    if(byt == 0x01 )      { xstore(); } 
    else if (byt == 0x02) { xfetch(); } 
    else if (byt == 0x3 ) { xcall(); } // else ignore any other serial inputs
}

你没有告诉我们你芯片的确切名称,但我怀疑你使用的是 ATmega328P。

A​​Tmega328P 无法执行来自RAM 的指令。在执行之前,您需要弄清楚如何将代码写入闪存。您可能想使用 Optiboot 之类的引导加载程序将程序写入闪存,或者您可以研究 Optiboot 以了解其工作原理。请注意,闪光灯的额定循环次数有限 erase/write(通常为 10000)。

此外,您的 C++ 语法有误。要调用一个函数,你总是需要使用括号。所以你会写 fGf()。而不仅仅是 fGf.