Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何从16位地址中划分高/低字节?_C_8051_Sdcc_Keil - Fatal编程技术网

C 如何从16位地址中划分高/低字节?

C 如何从16位地址中划分高/低字节?,c,8051,sdcc,keil,C,8051,Sdcc,Keil,我正在8051处理器上开发一个软件。一项常见的工作是划分16位地址的高字节和低字节。我想看看有多少种方法可以实现它。到目前为止,我提出的方法是:(假设ptr是一个16位指针,int是16位int)[注意rn和arn是寄存器] 位运算 SDCC提供以下汇编代码 ; t.c:32: ADDH = (unsigned int) ptr >> 8; mov ar6,r3 mov ar7,r4 mov _main_ADDH_1_1,r7 ; t.c:33: ADDL =

我正在8051处理器上开发一个软件。一项常见的工作是划分16位地址的高字节和低字节。我想看看有多少种方法可以实现它。到目前为止,我提出的方法是:(假设ptr是一个16位指针,int是16位int)[注意rn和arn是寄存器]

位运算 SDCC提供以下汇编代码

;   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

;   t、 c:32:ADDH=(无符号整数)ptr>>8;
mov ar6,r3
mov ar7,r4
移动主地址1,r7
;   t、 c:33:ADDL=(无符号整数)ptr&0x00FF;
移动主地址1,r6
Keil C51给了我:

                                           ; 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

                                           ; SOURCE LINE # 37
006A 850000      R     MOV     ADDH,ptr
                                           ; SOURCE LINE # 38
006D 850000      R     MOV     ADDL,ptr+01H

                                           ; 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

                                           ; SOURCE LINE # 26
0028 850000      R     MOV     ADDH,uptr
                                           ; SOURCE LINE # 27
002B 850000      R     MOV     ADDL,uptr+01H

; 源行#32
0045 AA00 R移动R2,ptr+01H
0047 A900移动R1,ptr+02H
0049 AE02 MOV R6,AR2
004B EE MOV A,R6
004C F500 R移动地址,A
; 源线#33
004E AF01 MOV R7,AR1
0050 EF MOV A,R7
0051 F500 R移动地址,A
里面有很多无用的代码

指针戏法

ADDH=((无符号字符*)&ptr)[0];
ADDL=((无符号字符*)&ptr)[1];
SDCC给了我:

;   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)

;   t、 c:37:ADDH=((无符号字符*)&ptr)[0];
移动主地址1,主地址1
;   t、 c:38:ADDL=((无符号字符*)&ptr)[1];
mov主地址1(主地址1+0x0001)
Keil C51给了我:

                                           ; 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

                                           ; SOURCE LINE # 37
006A 850000      R     MOV     ADDH,ptr
                                           ; SOURCE LINE # 38
006D 850000      R     MOV     ADDL,ptr+01H

                                           ; 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

                                           ; SOURCE LINE # 26
0028 850000      R     MOV     ADDH,uptr
                                           ; SOURCE LINE # 27
002B 850000      R     MOV     ADDL,uptr+01H

; 源线#37
006A 850000移动地址,ptr
; 源线#38
006D 850000 R移动地址,ptr+01H
这与SDCC版本相同

安德烈的数学方法

ADDH=ptr/256;
ADDL=ptr%256;

SDCC提供:

;   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

;   t、 c:42:ADDH=(无符号整数)ptr/256;
mov ar5,r3
mov ar6,r4
mov ar7,r6
移动主地址1,r7
;   t、 c:43:ADDL=(无符号整数)ptr%256;
移动主地址1,r5
我不知道sdcc为什么使用r7寄存器。。。 Keil C51给了我:

                                           ; 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

                                           ; SOURCE LINE # 37
006A 850000      R     MOV     ADDH,ptr
                                           ; SOURCE LINE # 38
006D 850000      R     MOV     ADDL,ptr+01H

                                           ; 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

                                           ; SOURCE LINE # 26
0028 850000      R     MOV     ADDH,uptr
                                           ; SOURCE LINE # 27
002B 850000      R     MOV     ADDL,uptr+01H

; 源行#42
0079 AE00 R MOV R6,ptr
007B AF00 R移动R7,ptr+01H
007D AA06 MOV R2,AR6
007F EA MOV A,R2
0080 F500 R移动地址,A
; 源行#43
0082 8F00 R移动地址,R7
我不知道Keil为什么也用R2寄存器

semaj的联合方法

typedef联合
{
无符号短u16;
无符号字符u8[2];
}U16_8

U16_8PTR

//做一些事情来设置变量ptr ptr.u16=

ADDH=ptr.u8[0]; ADDL=ptr.u8[1];

SDCC给了我

;   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)

;   t、 c:26:ADDH=uptr.u8[0];
移动主地址1、主地址1、主地址1
;   t、 c:27:ADDL=uptr.u8[1];
mov主地址1(主地址1+0x0001)
Keil C51给了我:

                                           ; 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

                                           ; SOURCE LINE # 37
006A 850000      R     MOV     ADDH,ptr
                                           ; SOURCE LINE # 38
006D 850000      R     MOV     ADDL,ptr+01H

                                           ; 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

                                           ; SOURCE LINE # 26
0028 850000      R     MOV     ADDH,uptr
                                           ; SOURCE LINE # 27
002B 850000      R     MOV     ADDL,uptr+01H

; 源线#26
0028 850000移动地址,上行
; 源线#27
002B 850000 R移动地址,上行+01H
这是非常微笑的指针技巧。但是,这种方法需要多存储两个字节的内存来存储union

有人有其他好主意吗?;)


谁能告诉我哪种方法更有效

如果有人感兴趣,以下是测试用例:

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);
}

typedef联合
{
无符号短u16;
无符号字符u8[2];
}U16_8

//在ADDs上调用函数以避免优化 无效交换(无符号字符*a,无符号字符*b) { 无符号字符tm; tm=*a; *a=*b; *b=tm; }

主(空) { 字符c[]=“你好,世界。”; 无符号字符扩展数据*ptr=(无符号字符扩展数据*)c; 无符号字符ADDH,ADDL; 无符号字符i=0

 ADDH = ptr / 256;
 ADDL = ptr % 256;
U16_8uptr;
uptr.u16=(无符号短)ptr;
对于(;i<4;i++,uptr.u16++){
ADDH=uptr.u8[0];
ADDL=uptr.u8[1];
掉期交易(&ADDH,&ADDL);
}
对于(;i<4;i++,ptr++){
ADDH=(无符号整数)ptr>>8;
ADDL=(无符号整数)ptr&0x00FF;
掉期交易(&ADDH,&ADDL);
}
对于(;i<4;i++,ptr++){
ADDH=((无符号字符*)&ptr)[0];
ADDL=((无符号字符*)&ptr)[1];
掉期交易(&ADDH,&ADDL);
}
对于(;i<4;i++,ptr++){
ADDH=(无符号整数)ptr/256;
ADDL=(无符号整数)ptr%256;
掉期交易(&ADDH,&ADDL);
}
}

效率最高的是第一条指令,因为它是在一条指令中完成的


不!对不起,我骗了你。我忘了8051指令集只有1位移位指令。第二种方法应该更快,但编译器可能会生成愚蠢的代码,所以请注意并检查汇编代码。

另一种不太聪明的地址拆分方法:


;   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
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];

最有效的方法完全依赖于编译器。您一定要弄清楚如何从8051项目的编译器中获取程序集列表

您可以尝试的一种类似于前面提到的方法是联合:

#define HI(x)  ((x) >> 8)
#define LO(x)  ((x) & 0xFF)
我只创建了两个定义(如下所示)

它看起来更直截了当,更不容易出错


但是有没有其他方法来划分地址?第二种方法如何生成多条指令?我的猜测是,它们在编译器上同样有效。最简单的方法是编译和检查assembly@Anders:我认为一个简单的编译器可能会弄乱2的主要方式是,它可能会将寄存器中的
ptr
写入堆栈,以获取其地址,然后从堆栈中读回字符。因此,对两行代码进行一次写入和两次读取(希望是为了快速存储,比如缓存,我根本不知道8051)。相反,代码的第一个版本可能会也可能不会只执行一些整数运算。我注意到,8051的大多数寄存器是8位的,因此任何一个选项都可能是不可操作的:寄存器可以重新分配,因此ptr的低位寄存器现在是ADDH。first是慢的。看我修改过的答案。