6
votes

Comment réduire l'espace de code pour une conversion hexadécimale de caractères ASCII en utilisant un espace de code _small?

Comment réduire l'espace de code d'une conversion de caractères ASCII hexadécimale à l'aide d'un petit espace de code

dans une application intégrée, j'ai un espace limité extraordinaire (note 1). J'ai besoin de convertir des octets, de l'E / S série, avec les valeurs ASCII "0" à "9" et "A" à "F" aux valeurs hexadécimales habituelles 0 à 15. Aussi toutes les 240 combinaisons, y compris ' a 'à' f ', doit être détecté (comme une erreur).

Fonctions de la bibliothèque telles que Scanf (), ATOI (), Strtol () sont Loin trop grand à utiliser.

La vitesse n'est pas un problème. La taille du code est le facteur limitant.

Ma méthode actuelle recélère les codes de 256 octets en 256 codes tels que '0' à '9' et 'A' à 'Z' ont les valeurs 0 - 35. Toutes idées sur la manière de réduire ou de réduire les approches différentes sont appréciées. xxx


Note 1: 256 Les instructions sont disponibles pour le code et les données constantes (1 Données d'octets coûte 1 instruction) dans une mémoire protégée PIC pour un chargeur de démarrage. Ce code coûte ~ 10 instructions. Current AP a besoin d'une nouvelle écriture et d'une seule instruction de rechange, réducteur même 1 instruction est précieuse. Je passe à travers la pièce par pièce. Ont également examiné la reconstruction globale.

Notes: PIC16. Je préfère coder dans 'C', mais doit faire ce qu'il faut. Le code de montage suit. Une réponse rapide n'est pas requise. xxx

[modifier meilleure solution ]
Optimisation de la solution existante comme suggéré par @gJ. En C, effectuer le ch + = 7; ch & = (~ 64); au lieu de ch = (ch + 7) & (~ 64); 1 instruction enregistrée. Aller à l'assemblage sauvegardé un autre en ne faisant pas recharger ch dans le si () .


0 commentaires

3 Réponses :


2
votes

Peut-être utiliser ctype.h's isxdigit () code> :

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


10 commentaires

Cela devrait-il être ('A' - 10) plutôt que ('A' + 10) puisque vous soustrayez cette quantité de CH?


Merci - depuis isxdigit () retourne true sur A à f ', ch prend les valeurs 42 à 47 . Je suppose qu'un si () pourrait être ajouté. En supposant que isxdigit () n'est pas une zone de grande recherche, il utilise probablement 3 si () s.


@chux: Je ne suis pas sûr de ce que vous voulez dire, le résultat en ch sera de 0 à 15 selon les besoins. La transformation est effectuée si le chiffre est hexadécimal. Étant donné que isxdigit () est probablement une macro, vous pouvez trouver sa définition complète dans ctype.h.


@chux: J'ai ajouté une alternative qui n'utilise pas isxdigit () mais qui modifie ch même s'il n'est pas un chiffre hexagonal.


isxdigit () retourne vrai sur 0-9, A-F et A-F. La 1ère solution convertit ch de 'A' en 10, bien, mais convertit 'a' en 42 et n'est pas détecté transmis à l'erreur // poignée. La deuxième solution convertit ':' à '?' en 10 à 15 et ils ne sont pas détectés dans l'erreur // de la poignée.


Mon isxdigit () est en effet une macro: #define isxdigit (x) isamong (x, "0123456789abcdefabcdef") . Certainement plus de 10 instructions. BTW, plus tard, je serai dans le désert pendant quelques jours.


@Clifford si (ch <0x0 .. ne peut jamais être vrai pour un caractère non signé


@chux: Votre question indique clairement '0' à '9' et 'A' à 'F'. J'ai simplement suivi votre spec.


@JEB: vrai - encore mieux.


@chux: Je suis épais, je vois ce que tu veux dire sur A à F. Il a besoin d'un test Islower () mais la solution est de plus en plus insatisfaisante peut-être. Une solution consiste à convertir des minuscules en majuscules avant la transformation et accepter des chiffres hexagonales minuscules ch & = 0x20 .



5
votes

La famille PIC16 est RISC McPu, vous pouvez donc essayer d'optimiser votre code ASM. Ceci est votre code ASM C compilateurs C ...

        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


5 commentaires

Est BTFSC WRREG, 6 Valable sur un PIC16?


@D Krueger: WRREG est accessible uniquement sur New Pic16 et Pic12 McPus marqué comme technologie XLP. WRREG est une copie du registre de travail alu à l'adresse 0x09.


@Krueger: a ajouté également une version compatible avec l'ancien PIC16 MCPUS.


Merci. Dans C , effectuant le ch + = 7; ch & = (~ 64); au lieu de ch = (ch + 7) & (~ 64); 1 instruction enregistrée. Aller à l'assemblage sauver une autre.


@chux: Vérifiez aussi mon édition III Explication :)



4
votes

Avec une optimisation de la bonne compilation, cela peut prendre moins d'espace de code:

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

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

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


3 commentaires

Ce code n'est pas correct! Quel devrait être le résultat si l'entrée est le caractère @ (0x40)?


@ Gj.if sur l'entrée ch == 0x40 alors sa valeur finale sera 0xff , qui sera capturé par le (ch> 15) test.


Merci. Ma meilleure utilisation de votre réponse et de vos variations était encore +0 instruction sur l'original. (Cela comporte 3 branches par rapport à l'original 2.) Il a fallu un certain temps pour comprendre votre approche élégante, mais elle ouvre une pensée.