Embedded 如何使用较小的代码空间减少十六进制ASCII字符转换的代码空间?

Embedded 如何使用较小的代码空间减少十六进制ASCII字符转换的代码空间?,embedded,pic,bootloader,Embedded,Pic,Bootloader,如何使用较小的代码空间减少十六进制ASCII字符转换的代码空间? 在嵌入式应用程序中,我的空间非常有限(注1)。我需要将ASCII值为“0”到“9”和“A”到“F”的字节从串行I/O转换为通常的十六进制值0到15。此外,还需要检测所有其他240个组合,包括“a”到“f”(作为错误) 库函数,例如scanf()、atoi()、strtol()太大,无法使用 速度不是问题。代码大小是限制因素 我当前的方法将256字节代码重新映射为256个代码,以便“0”到“9”以及“A”到“Z”的值为0-35对于如

如何使用较小的代码空间减少十六进制ASCII字符转换的代码空间?

在嵌入式应用程序中,我的空间非常有限(注1)。我需要将ASCII值为“0”到“9”和“A”到“F”的字节从串行I/O转换为通常的十六进制值0到15。此外,还需要检测所有其他240个组合,包括“a”到“f”(作为错误)

库函数,例如
scanf()、atoi()、strtol()
太大,无法使用

速度不是问题。代码大小是限制因素

我当前的方法将256字节代码重新映射为256个代码,以便“0”到“9”以及“A”到“Z”的值为0-35对于如何减少或采用不同方法的任何想法,我们将不胜感激。

unsigned char ch = GetData(); // Fetch 1 byte of incoming data;
if (!(--ch & 64)) {           // decrement, then if in the '0' to '9' area ...
  ch = (ch + 7) & (~64);      // move 0-9 next to A-Z codes
}
ch -= 54;                     // -= 'A' - 10 - 1
if (ch > 15) { 
  ; // handle error
}
WREG = (--ch);                   
if (!(WREG & 64)) {              // decrement, then if in the '0' to '9' area ...
  WREG = (WREG + 7) & (~64);     // move 0-9 next to A-Z codes
}
ch = WREG - 54;                  // -= 'A' - 10 - 1 
if (WREG > 15) {    
  ; // handle error 
}
    decf    ch, f         ;//ch = (--ch)
    movf    ch, w         ;//WREG = ch
    btfsc   ch, 6         ;//if (!(ch & 64)) {
    goto    Skip  
    addlw   7             ;//WREG += 7
    andlw   0xBF          ;//WREG &= (~64)
Skip
    addlw   0x100 - 0x36  ;//WREG -= 54;
    movwf   ch            ;//ch = WREG
//    
    addlw   0x100 - 0x10  ;//if (WREG > 15) { 
    btfsc   STATUS, 0     ;//Check carry
    goto    HandleError

注1:256条指令用于引导加载程序的PIC保护内存中的代码和常量数据(1字节数据消耗1条指令)。这段代码大约需要10条指令。当前ap需要重新写入&只有一条备用指令,即使减少一条指令也很有价值。我一件一件地看。我们还研究了整体重建

注:图16。我更喜欢用“C”编写代码,但无论如何都必须这样做。下面是汇编代码。不需要快速回答

if (!(--ch & 64)) { 
  002D:DECF   44,F   002E:BTFSC  44.6    002F:GOTO   034     
  ch = (ch + 7) & (~64); 
  0030:MOVLW  07     0031:ADDWF  44,W    0032:ANDLW  BF    0033:MOVWF  44
}// endif 
ch -= 54; 
  0034:MOVLW  36     0035:SUBWF  44,F
[编辑最佳解决方案
]
按照@GJ的建议优化现有解决方案。在C中,执行
ch+=7;ch&=(~64)而不是
ch=(ch+7)和(~64)保存1条指令。通过不必在
if()

中重新加载
ch
来保存另一个程序集,可能需要使用ctype.h:

它是否更小在很大程度上取决于
isxdigit
的实现,也许还取决于您的编译器和处理器体系结构,但值得一试,而且可读性要高得多
isxdigit()
通常是一个宏,因此没有函数调用开销

另一种方法是无条件执行转换,然后检查结果的范围:

ch -= (ch >= 'A') ? ('A' - 10) : 
                    (ch >= '0') ? '0' : 0 ;
if( ch > 0xf )
{
    // handle error
}

我怀疑后者会更小,但在某些情况下,修改
ch
on error可能没有帮助,例如错误报告原始值。

PIC16系列是RISC MCPU,因此您可以尝试优化asm代码。 这是你的c编译器asm代码

    decf    ch, f
    btfsc   ch, 6
    goto    Skip
    movlw   07
    addwf   ch, w
    andlw   0xBF
    movwf   ch
Skip    
    movlw   0x36
    subwf   ch, f
这是我优化的上层代码

   decf     ch, w         //WREG = (--ch)
   btfsc    WREG, 6       //if (!(WREG & 64)) {
   goto     Skip  
   addlw    7             //WREG += 7
   andlw    0xBF          //WREG &= (~64)
Skip
   addlw    0x100 - 0x36  //WREG -= 54;
   movwf    ch            //ch = WREG
//
   addlw    0x100 - 0x10  //if (WREG > 15) { 
   btfsc    STATUS, 0     //Check carry
   goto     HandleError
…因此,只有7个操作码(少2个)没有范围错误检查,10个操作码有范围错误检查

编辑: 还可以尝试此PIC16 c编译器优化函数,不确定是否有效…

unsigned char ch = GetData(); // Fetch 1 byte of incoming data;
if (!(--ch & 64)) {           // decrement, then if in the '0' to '9' area ...
  ch = (ch + 7) & (~64);      // move 0-9 next to A-Z codes
}
ch -= 54;                     // -= 'A' - 10 - 1
if (ch > 15) { 
  ; // handle error
}
WREG = (--ch);                   
if (!(WREG & 64)) {              // decrement, then if in the '0' to '9' area ...
  WREG = (WREG + 7) & (~64);     // move 0-9 next to A-Z codes
}
ch = WREG - 54;                  // -= 'A' - 10 - 1 
if (WREG > 15) {    
  ; // handle error 
}
    decf    ch, f         ;//ch = (--ch)
    movf    ch, w         ;//WREG = ch
    btfsc   ch, 6         ;//if (!(ch & 64)) {
    goto    Skip  
    addlw   7             ;//WREG += 7
    andlw   0xBF          ;//WREG &= (~64)
Skip
    addlw   0x100 - 0x36  ;//WREG -= 54;
    movwf   ch            ;//ch = WREG
//    
    addlw   0x100 - 0x10  ;//if (WREG > 15) { 
    btfsc   STATUS, 0     ;//Check carry
    goto    HandleError
EDIT II:添加了与旧版PIC16 MCPU兼容的版本,该版本不是采用XLP技术制造的,但代码长度比旧版长一个操作码。

unsigned char ch = GetData(); // Fetch 1 byte of incoming data;
if (!(--ch & 64)) {           // decrement, then if in the '0' to '9' area ...
  ch = (ch + 7) & (~64);      // move 0-9 next to A-Z codes
}
ch -= 54;                     // -= 'A' - 10 - 1
if (ch > 15) { 
  ; // handle error
}
WREG = (--ch);                   
if (!(WREG & 64)) {              // decrement, then if in the '0' to '9' area ...
  WREG = (WREG + 7) & (~64);     // move 0-9 next to A-Z codes
}
ch = WREG - 54;                  // -= 'A' - 10 - 1 
if (WREG > 15) {    
  ; // handle error 
}
    decf    ch, f         ;//ch = (--ch)
    movf    ch, w         ;//WREG = ch
    btfsc   ch, 6         ;//if (!(ch & 64)) {
    goto    Skip  
    addlw   7             ;//WREG += 7
    andlw   0xBF          ;//WREG &= (~64)
Skip
    addlw   0x100 - 0x36  ;//WREG -= 54;
    movwf   ch            ;//ch = WREG
//    
    addlw   0x100 - 0x10  ;//if (WREG > 15) { 
    btfsc   STATUS, 0     ;//Check carry
    goto    HandleError
编辑三:解释

“D Kruegers”解决方案也很好,但需要一些修改

此代码

  if (((ch += 0xC6) & 0x80) || !((ch += 0xF9) & 0x80)) {
    ch += 0x0A;
  }
…我们可以翻译成

  if (((ch -= ('0' + 10)) < 0) || ((ch -= ('A' - '0' - 10)) >= 0)) {
    ch += 10; 
  }
if(((ch-=('0'+10))<0)|;((ch-=('A'-'0'-10))>=0)){
ch+=10;
}
之后我们可以在一个训练器中进行优化

        call    GetData 
//if GetData return result in WREG then you do not need to store in  ch and read it again!
//      movwf   ch
//      movf    ch, w

        addlw   0x100 - '0' - 10     //if (((WREG -= ('0' + 10)) < 0) || ((WREG -= ('A' - '0' - 10)) >= 0)) {
        btfss   STATUS, 0   
        goto    DoAddx
        addlw   0x100 - ('A' - '0' - 10)
        btfsc   STATUS, 0       
    DoAddx
        addlw   10                   //WREG += 10; }
        movwf   ch                   //ch = WREG;       

        addlw   0x100 - 0x10         //if (WREG > 15) { 
        btfsc   STATUS, 0            //Check carry
        goto    HandleError
调用GetData
//如果GetData返回结果为WREG,则不需要存储在ch中并再次读取!
//movwf-ch
//莫夫·切赫,w
addlw 0x100-'0'-10//if((WREG-=('0'+10))<0)| |((WREG-=('A'-'0'-10))>=0)){
btfss状态,0
后藤
addlw 0x100-('A'-'0'-10)
btfsc状态,0
DoAddx
addlw 10//WREG+=10;}
movwf ch//ch=鹪鹩;
addlw 0x100-0x10//if(WREG>15){
btfsc状态,0//检查进位
goto HandleError

通过良好的编译器优化,这可能会占用更少的代码空间:

unsigned char ch = GetData(); // Fetch 1 byte of incoming data;

if (((ch += 0xC6) & 0x80) || !((ch += 0xF9) & 0x80)) {
  ch += 0x0A;
}

if (ch > 15) { 
  ; // handle error
}

如果是('A'-10)而不是('A'+10),因为你要从ch中减去这个量?谢谢-因为
isxdigit()
A
f
时返回true,
ch
接受42到47的值。我想可以添加
if()
。假设
isxdigit()
不是什么大的查找表,它可能使用3
if()
s.@chux:我不确定你的意思,在
ch
中的结果将根据需要为0到15。如果数字是十六进制,则执行转换。因为
isxdigit()
很可能是一个宏。您可以在ctype.h中找到它的完整定义。@chux:我添加了一个替代项,它不使用
isxdigit()
,但可以修改
ch
,即使它不是十六进制数字。@chux:我变厚了,我明白您关于a到f的意思。它需要一个
islower()
测试,但解决方案可能越来越不令人满意。一种解决方案是在转换前将小写转换为大写,并接受小写十六进制数字
ch&=0x20
。btfsc WREG,6
是否在PIC16上有效?@D Krueger:WREG仅在标记为XLP技术的较新PIC16和PIC12 MCPU上可用。WREG是地址0x09处ALU工作寄存器的副本。@Krueger:还添加了一个与旧的PIC16 MCPU兼容的版本。谢谢。在
C
中,执行
ch+=7;ch&=(~64);
而不是
ch=(ch+7)和(~64)
保存了1条指令。将要保存另一条指令。@chux:同时检查我的编辑III解释:)此代码不正常!如果输入为字符@(0x40)?@GJ,结果应该是什么。如果输入时
ch==0x40
,则其最终值将是
0xff
,这将被
(ch>15)捕获
test.Thank-you.我对您的答案和变体的最佳使用方式仍然是在原来的基础上增加+0指令。(这有3个分支,而原来的2个分支)。花了一段时间才理解您巧妙的方法,但它打开了一些思路。