如何使用_small_代码空间减少十六进制ASCII字符转换的代码空间? [英] How to reduce the code space for a hexadecimal ASCII chars conversion using a _small_ code space?

查看:248
本文介绍了如何使用_small_代码空间减少十六进制ASCII字符转换的代码空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



库函数如 scanf(),atoi() strtol()太远,不能使用。



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



我现在的方法将256字节代码重新映射为256个代码,使得0到9和A 'Z'的值为0 - 35. 赞赏任何有关如何减少或不同方法的想法。

  unsigned char ch = GetData(); //提取1字节的传入数据; 
如果(!( - ch& 64)){//递减,那么如果在'0'到'9'区域...
ch =(ch + 7)& (〜64); //移动0-9在A-Z代码旁边
}
ch - = 54; // - ='A' - 10 - 1
if(ch> 15){
; //处理错误
}






注意引导加载程序的PIC保护的存储器中的代码和常量数据(1字节数据费用为1指令)为1:256。此代码费用〜10条指令。当前ap需要重新写入&只有1个备用指令,减少1个指令是有价值的。我一个接一个地穿过它。还要看整体重建。



注意:PIC16。我更喜欢用'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()中 c $ c

$ b $之前,不需要重新加载 ch b

解决方案

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

  decf ch,f 
btfsc ch,6
goto跳过
movlw 07
addwf ch,w
andlw 0xBF
movwf ch
跳过
movlw 0x36
subwf ch, f

这是我的优化代码...

  decf ch,w // WREG =(--ch)
btfsc WREG,6 // if(!(WREG& 64)){
goto跳过
addlw 7 // WREG + = 7
andlw 0xBF // WREG& =(〜64)
跳过
addlw 0x100 - 0x36 // WREG - = 54;
movwf ch // ch = WREG
//
addlw 0x100 - 0x10 // if(WREG> 15){
btfsc STATUS,0 //检查携带
goto HandleError

...所以只有7个操作码(少2个),无范围错误检查和10个操作码与范围错误检查!



编辑:
尝试这个PIC16 c编译器优化的功能,不知道如果工作...
/ p>

  WREG =(--ch); 
if(!(WREG& 64)){//递减,那么如果在'0'到'9'区域...
WREG =(WREG + 7)& (〜64); //移动0-9在A-Z代码旁边
}
ch = WREG - 54; // - ='A' - 10 - 1
if(WREG> 15){
; //处理错误
}

编辑II:与旧的PIC16 MCPU不是用XLP技术制造的,代码尺寸是一个操作码的长度。

  decf ch,f; // ch =(-ch)
movf ch,w; // WREG = ch
btfsc ch,6; // if(!(ch& 64)){
goto跳过
addlw 7; // WREG + = 7
andlw 0xBF; // WREG& =(〜64)
跳过
addlw 0x100 - 0x36; // WREG - = 54;
movwf ch; // ch = WREG
//
addlw 0x100 - 0x10; // if(WREG> 15){
btfsc STATUS,0; //检查进位
goto HandleError

编辑III:说明



'D Kruegers'解决方案也非常好,但需要一些修改...



此代码.. <如果(((ch + = 0xC6)& 0x80)||!((ch + = 0xF9)& 0x80)),p>

  {
ch + = 0x0A;
}

...我们可以翻译成...

$ b如果(((ch - =('0'+ 10))< 0)||((ch - =('A' - ' 0' - 10))> = 0)){
ch + = 10;
}

之后,我们可以在汇编程序中优化...

 调用GetData 
//如果GetData在WREG中返回结果,那么您不需要在ch中存储并再次读取!
// 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


How to reduce the code space for a hexadecimal ASCII chars conversion using a small code space?

In an embedded application, I have extraordinary limited space (note 1). I need to convert bytes, from serial I/O, with the ASCII values '0' to '9' and 'A' to 'F' to the usual hexadecimal values 0 to 15. Also, all the other 240 combinations, including 'a' to 'f', need to be detected (as an error).

Library functions such as scanf(), atoi(), strtol() are far too large to use.

Speed is not an issue. Code size is the the limiting factor.

My present method re-maps the 256 byte codes into 256 codes such that '0' to '9' and 'A' to 'Z' have the values 0 - 35. Any ideas on how to reduce or different approaches are appreciated.

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
}


Note 1: 256 instructions exist for code and constant data (1 byte data costs 1 instruction) in a PIC protected memory for a bootloader. This code costs ~10 instructions. Current ap needs a re-write & with only 1 spare instruction, reducing even 1 instruction is valuable. I'm going through it piece by piece. Also have looked at overall reconstruction.

Notes: PIC16. I prefer to code in 'C', but must do what ever it takes. Assembly code follows. A quick answer is not required.

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

[edit best solution]
Optimizing existing solution as suggested by @GJ. In C, performing the ch += 7; ch &= (~64); instead of ch = (ch + 7) & (~64); saved 1 instruction. Going to assembly saved another by not having to reload ch within the if().

解决方案

PIC16 family is RISC MCPU, so you can try to optimize your asm code. This is your c compilers asm code...

    decf    ch, f
    btfsc   ch, 6
    goto    Skip
    movlw   07
    addwf   ch, w
    andlw   0xBF
    movwf   ch
Skip    
    movlw   0x36
    subwf   ch, f

This is my optimization of upper code...

   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

...so only 7 opcodes (2 less) without range error check and 10 opcodes with range error check!

EDIT: Try also this PIC16 c compiler optimized function, not sure if works...

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 
}

EDIT II: added version which is compatible with older PIC16 MCPUs not made in XLP technology, but code size is one opcode longer.

    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 III: explanation

The 'D Kruegers' solution is also very good, but need some modification...

This code..

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

...we can translate to...

  if (((ch -= ('0' + 10)) < 0) || ((ch -= ('A' - '0' - 10)) >= 0)) {
    ch += 10; 
  }

After that we can optimize in asembler...

        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

这篇关于如何使用_small_代码空间减少十六进制ASCII字符转换的代码空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆