倾销闪存的微小代码

时间:2014-06-10 21:36:56

标签: c assembly embedded arm firmware

我尝试编写尽可能小的代码来提取英飞凌XMC4500微控制器的固件。

代码必须适合 30 字节缓冲区,这允许我使用Thumb 16位指令集获得15条机器指令。

从C开始,我的尝试是在(see original question) nifty技巧之后通过单个GPIO引脚this转储闪存。

基本上我正在做的是:

  1. 设置GPIO引脚方向以输出
  2. 使用时钟(SPI串行时钟)闪烁LED1(引脚1.1)
  3. 使用数据位(SPI MOSI)闪烁LED2(引脚1.0)
  4. 使用逻辑分析仪嗅探引脚
  5. 修改

    1. 更新C代码块
    2. 添加装配代码块
    3. #include "XMC4500.h"
      
      void main() {
        // start dumping at memory address 0x00000000
        unsigned int* p = (uint32_t *)(0x0u);
      
        // configure port1 output (push-pull)
        PORT1->IOCR0 = 0x8080u;
      
        for(;;) {
          int i = 32;
      
          int data = *(p++);
      
          do {
            // clock low
            PORT1->OUT = 0x0;
      
            // clock high with data bits
            PORT1->OUT = 0x2u | data;
      
            data >>= 1;
      
          } while (--i > 0);
        }
      }
      
      main:
          ; PORT1->IOCR0 = 0x8080UL
          ldr r1, =0x48028100 ; load port1 base address to R1
          movw r2, #0x8080 ; move 0x8080 to R2
          str r2, [r1, #0x10]
      
      main_1:
          ; start copying at address 0x00000000
          ; R12 is known to be zeroed
          ldr.w r2, [r12], #0x4 ; int data = *(p++)
          movs r3, #32 ; int i = 32
      
      main_2:
          ; PORT1->OUT = 0x0
          ; clock low
          ; R12 is known to be zeroed
          str r12, [r1]
      
          ; PORT1->OUT = 0x2 | data
          ; clock high with data bits
          orr r4, r2, #0x2
          str r4, [r1]
      
          asrs r2, r2, #0x1 ; data >>= 1
      
          subs r3, r3, #0x1 ; i--
          bne.n main_2 ; while (--i > 0)
          b.n main_1 ; while(true)
      

      但是代码大小仍然太大,无法满足我的要求。

      我可以采取哪些措施来进一步缩减我的代码吗?什么可以优化或遗漏?

2 个答案:

答案 0 :(得分:3)

如果在此过程中Port1的高位没有改变,并且你可以确保在时钟变高后稍微读取数据位,你可以尝试这样的事情:

#define P1_DEFAULT =   ?//constant high bits of port 1, zeros in low two bits
int* dp=0;             //maybe use a register which is known to be zeroed.
PORT1->IOCR0 = 0x8080;  //should be 3 ins
for(;;){
  int i=32;            //
  int data=*(dp++);    //LDMIA instruction may do load and increment in 1 step.
  do{
    PORT1->OUT = P1_DEFAULT  #clock low
    PORT1->OUT = P1_DEFAULT + 2+ (data&1); #clock high with data
    data>>=1;
  } while (--i>0);
}

这应该删除三个端口读取,一个端口写入和一个条件 在一个函数中完成所有操作以避免任何调用开销。我将从生成的程序集开始,看看你可以做些什么来改进它。

答案 1 :(得分:2)

十六条指令不是很多;我不希望C编译器能够生成足够高效的代码来对内存转储进行bit-bang。如果你对输出位模式不太挑剔,我认为使用类似的东西32个字节就足够了:

    ldr  r1,=Port1      ; Address of IO Port
    mov  r3,#1
    str  r3,[r1+IOCR0]
    lsl  r0,r3,#27
bytes:
    mov  r5,#9
    strb r5,[r1+OUT]
    add  r0,#1
    ldrb r4,[r0]
bits:
    strb r4,[r1+OUT]
    lsr  r4,#1
    sub  r5,#1
    bne  bits
    b    bytes

每个字节将作为高脉冲输出,然后是8位可能为高或低(取决于数据读取),然后是位时间,该位时间始终为零,以确保下一个高脉冲的上升沿将是可见的。基本上类似于异步串行通信,但水平相反。