Möglichkeiten zum aufteilen der high/low byte aus einem 16-bit-Adresse?
Ich entwickle eine software, die auf dem 8051-Prozessor. Eine häufige Aufgabe ist zum teilen des high-und low-byte eines 16-bit-Adresse. Ich will sehen, es gibt, wie viele Möglichkeiten, es zu erreichen. Die Möglichkeiten, die ich kommen so weit sind: (sagen ptr ist ein 16-bit-Zeiger und int ist 16bit int) [Hinweis: die rn und arn ist registriert]
bitweise operation
ADDH = (unsigned int) ptr >> 8;
ADDL = (unsigned int) ptr & 0x00FF;
SDCC gibt die folgenden Assembler-code
; t.c:32: ADDH = (unsigned int) ptr >> 8;
mov ar6,r3
mov ar7,r4
mov _main_ADDH_1_1,r7
; t.c:33: ADDL = (unsigned int) ptr & 0x00FF;
mov _main_ADDL_1_1,r6
Keil C51 gibt mir:
; SOURCE LINE # 32
0045 AA00 R MOV R2,ptr+01H
0047 A900 R MOV R1,ptr+02H
0049 AE02 MOV R6,AR2
004B EE MOV A,R6
004C F500 R MOV ADDH,A
; SOURCE LINE # 33
004E AF01 MOV R7,AR1
0050 EF MOV A,R7
0051 F500 R MOV ADDL,A
die vielen nutzlosen code IMHO.
Zeiger trick
ADDH = ((unsigned char *)&ptr)[0];
ADDL = ((unsigned char *)&ptr)[1];
SDCC gibt mir:
; t.c:37: ADDH = ((unsigned char *)&ptr)[0];
mov _main_ADDH_1_1,_main_ptr_1_1
; t.c:38: ADDL = ((unsigned char *)&ptr)[1];
mov _main_ADDL_1_1,(_main_ptr_1_1 + 0x0001)
Keil C51 gibt mir:
; SOURCE LINE # 37
006A 850000 R MOV ADDH,ptr
; SOURCE LINE # 38
006D 850000 R MOV ADDL,ptr+01H
das ist das gleiche mit SDCC version.
Andrey ' s mathematische Ansatz
ADDH = ptr / 256;
ADDL = ptr % 256;
SDCC gibt:
; t.c:42: ADDH = (unsigned int)ptr / 256;
mov ar5,r3
mov ar6,r4
mov ar7,r6
mov _main_ADDH_1_1,r7
; t.c:43: ADDL = (unsigned int)ptr % 256;
mov _main_ADDL_1_1,r5
Ich habe keine Ahnung, warum sdcc verwenden Sie das register r7...
Keil C51 gibt mir:
; SOURCE LINE # 42
0079 AE00 R MOV R6,ptr
007B AF00 R MOV R7,ptr+01H
007D AA06 MOV R2,AR6
007F EA MOV A,R2
0080 F500 R MOV ADDH,A
; SOURCE LINE # 43
0082 8F00 R MOV ADDL,R7
Ich habe keine Ahnung, warum Keil verwenden Sie das register R2 weder...
semaj das Konzept der union
typedef union
{
unsigned short u16;
unsigned char u8[2];
} U16_U8;
U16_U8 ptr;
//Do something to set the variable ptr
ptr.u16 = ?;
ADDH = ptr.u8[0];
ADDL = ptr.u8[1];
SDCC gibt mir
; t.c:26: ADDH = uptr.u8[0];
mov _main_ADDH_1_1,_main_uptr_1_1
; t.c:27: ADDL = uptr.u8[1];
mov _main_ADDL_1_1,(_main_uptr_1_1 + 0x0001)
Keil C51 gibt mir:
; SOURCE LINE # 26
0028 850000 R MOV ADDH,uptr
; SOURCE LINE # 27
002B 850000 R MOV ADDL,uptr+01H
das ist sehr smiler auf den Zeiger trick. Allerdings ist dieser Ansatz erfordert zwei bytes mehr Speicher das speichern der union.
Hat jemand irgendwelche anderen Ideen? 😉
Und jemand kann mir sagen, welche Möglichkeit die effizientere ist?
Falls es jemanden interessiert, hier ist der test-Fall:
typedef union { unsigned short u16; unsigned char u8[2]; } U16_U8;
//call a function on the ADDs to avoid optimizition void swap(unsigned char *a, unsigned char *b) { unsigned char tm; tm = *a; *a = *b; *b = tm; }
main (void) { char c[] = "hello world."; unsigned char xdata *ptr = (unsigned char xdata *)c; unsigned char ADDH, ADDL; unsigned char i = 0;
U16_U8 uptr; uptr.u16 = (unsigned short)ptr; for ( ; i < 4 ; i++, uptr.u16++){ ADDH = uptr.u8[0]; ADDL = uptr.u8[1]; swap(&ADDH, &ADDL); } for ( ; i < 4 ; i++, ptr++){ ADDH = (unsigned int) ptr >> 8; ADDL = (unsigned int) ptr & 0x00FF; swap(&ADDH, &ADDL); } for ( ; i < 4 ; i++, ptr++){ ADDH = ((unsigned char *)&ptr)[0]; ADDL = ((unsigned char *)&ptr)[1]; swap(&ADDH, &ADDL); } for ( ; i < 4 ; i++, ptr++){ ADDH = (unsigned int)ptr / 256; ADDL = (unsigned int)ptr % 256; swap(&ADDH, &ADDL); }
}
"wer kann mir sagen, welche Möglichkeit die effizientere ist". Da hast du die 8051-compiler Recht gibt, und ich weiß nicht, wie über Sie post von der Demontage der einzelnen option, um es anderen zu geben eine sportliche chance zu kommentieren auf den Wirkungsgrad 😉
Danke für den Tipp. Ich hoffe, es ist ein Weg, um zu "sehen asm-code aus C-code". Aber als Sie fragte, werde ich hochladen, den asm-code von morgen.
Für die Effizienz, die Sie brauchen zu wissen, der Zyklus Anzahl der jeweiligen Unterricht beteiligt sind (1 oder 2 in jedem Fall). 8052.com/51mov hat die Liste, aber es ist ein PITA zu arbeiten für Ihre SDCC Montage, da es keine Liste der opcodes, so dass Sie haben, um herauszufinden, welche Variante von MOV jede Anweisung ist. Auch Vorsicht beim Vergleich von code-Varianten, die unterschiedliche Register, dass das Stück code, die Sie eigentlich suchen, bei haben kann knock-on-Effekte auf die anderen bits des Codes. Wie Sie sagen, einige Versionen sind mit mehr Register, als man erwarten würde, vermutlich für eine tatsächliche Grund...
So, in Zusammenfassung, ist vielleicht einfacher, nur um es zu testen. Vielleicht auf einem simulator.InformationsquelleAutor Grissiom | 2010-03-29
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die effizienteste Art und Weise ist völlig abhängig von dem compiler. Sie müssen auf jeden Fall herausfinden, wie man eine Baugruppe, Eintrag aus Ihrem compiler für einen 8051-Projekt.
Eine Methode, die Sie versuchen könnten, die ähnlich ist zu derjenigen, die bereits erwähnt ist eine union:
InformationsquelleAutor semaj
Anderen nicht so hell Weg nach split Adresse:
Mann, wissen Sie, die Kosten der div-Anweisungen auf CPUs, wie der 8051?
Ich weiß nicht, was Compiler für 8051, aber zumindest für einen unsigned-Typ, ich wäre erstaunt, wenn ein C-compiler (auf jeder Architektur), die behaupteten, eine Optimierung auf alle auf, die unterschiedlichen code für
ptr / 256
als gegenptr >> 8
. Ich kann nicht sagen, was insns es verwendet, aber es ist nicht schwer für den compiler an Ort und Stelle die Gleichwertigkeit und die besten auszuwählen. Negative Werte sind nicht unbedingt so einfach.InformationsquelleAutor Anders Westrup
meisten effizient ist die erste, da es im einzigen Instruktion.
NEIN! Ich habe dich belogen, sorry. Ich vergaß, dass 8051 Befehlssatz hat nur 1-bit-shift-Anweisungen. Zweite sollte schneller sein, aber der compiler erzeugt dumm-code, also Vorsicht und schauen Sie assembly-code.
Wie kann man das zweite erzeugt mehrere Anweisungen? Meine Vermutung ist, dass Sie gleichermaßen effizient
Hängt vom compiler. Der einfachste Weg ist es, kompilieren Sie und prüfen, Montage
der wichtigste Weg, den ich mir denken kann, dass ein einfacher compiler kann mess up 2, ist, dass es vielleicht schreiben
ptr
aus einem register auf dem stack, um die Adresse, dann Lesen Sie einen char wieder vom stack. So eine schreib-und zwei lese-Operationen für die zwei Zeilen code (hoffentlich schnelle Speicher, wie Caches, weiß ich nicht, 8051). Umgekehrt, die erste version des code Mai oder Mai nicht nur durchführen, einige integer-ops. Ich beachten Sie, dass die meisten 8051 - Register 8-bit, also entweder option könnte sein, eine no-op: Register konnte nur neu zugewiesen werden, so dass die registrieren, dass war der niedrige Teil der ptr ist jetzt ADDH.zunächst ist langsam. siehe meine überarbeitete Antwort. es ist kein cache bei 8051, aber es ist schnell auf-chip-Speicher, die nicht transparent für die Entwickler
InformationsquelleAutor Andrey
Ich nur zwei definiert(wie folgt).
Scheint es eher geradlinig und weniger fehleranfällig.
InformationsquelleAutor Jim T