C语言和汇编语言对比 - Go语言中文社区

C语言和汇编语言对比


        C语言中,程序员所定义的每一个变量,不管是基本类型(char,unsigned char,int unsigned int,short,unsigned short,long,unsigned long,double)的变量还是构造类型(数组,struct,enum,union,链表等)的变量,在编译之后都安排在了内存中的特定存储区域里面了, 每一个变量都对应特定的内存空间。

        汇编语言中,根本就没有变量的说法,程序员所面对的就是赤裸裸的存储空间,可能是RAM,可能是EEPROM,还可能是FLASH,程序员需要自己给这些存储空间命名(相对于C语言,汇编语言完全需要自己分配内存),然后直接进行访问(读操作或者写操作)。例如在RAM空间中给地址为$100的存储单元命名,然后清空它的值,接着把I2C数据寄存器中的值读取到该存储单元中,接着再对该值自加1,最后将它的值保存到EEPROM的某个存储单元和FLASH的某个存储单元中。代码如下:

stm8/

	#include "mapping.inc"
	#include "stm8s103f.inc"

;ram的存储空间为$0000~$03FF
;在ram存储空间中地址为$100的存储单元命名为data_ram
data_ram EQU $100  ;用data_ram代表地址为$100的存储单元
;eeprom的存储空间为$4000~$427F
;在eeprom存储空间中地址为$4001的存储单元命名为data_eeprom
data_eeprom EQU $4001 
;flash的存储空间为$8080~9FFF
;在flash存储空间中地址为$9000的存储单元命名为data_flash
data_flash EQU $9000

; I2C Bus Interface (I2C) at 0x5210
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.I2C_CR1			DS.B 1		; I2C control register 1
.I2C_CR2			DS.B 1		; I2C control register 2
.I2C_FREQR			DS.B 1		; I2C frequency register
.I2C_OARL			DS.B 1		; I2C Own address register low
.I2C_OARH			DS.B 1		; I2C Own address register high
reserved13		DS.B 1		; unused
.I2C_DR			DS.B 1		; I2C data register

; Flash at 0x505a
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.FLASH_CR1			DS.B 1		; Flash control register 1
.FLASH_CR2			DS.B 1		; Flash control register 2
.FLASH_NCR2			DS.B 1		; Flash complementary control register 2
.FLASH_FPR			DS.B 1		; Flash protection register
.FLASH_NFPR			DS.B 1		; Flash complementary protection register
.FLASH_IAPSR			DS.B 1		; Flash in-application programming status register
reserved2		DS.B 2		; unused
.FLASH_PUKR			DS.B 1		; Flash Program memory unprotection register
reserved3		DS.B 1		; unused
.FLASH_DUKR			DS.B 1		; Data EEPROM unprotection register
reserved4		DS.B 59		; unused

; Independent Watchdog (IWDG) at 0x50e0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.IWDG_KR			DS.B 1		; IWDG Key Register
.IWDG_PR			DS.B 1		; IWDG Prescaler Register
.IWDG_RLR			DS.B 1		; IWDG Reload Register
reserved10		DS.B 13		; unused
;----------------------------------------
;----------------------------------------
	segment 'rom'
main.l
  CLR data_ram ;72 5F 01 00
	LD A,I2C_DR ;C6 52 16
	LD data_ram,A ;C7 01 00
	INC data_ram ;72 5C 01 00
	CALL UnkeyprocessEep
	CALL unkeyprocessFla
  JRA main ;20 XX/20 A8

TAB1.L
  DC.B $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F
	
UnkeyprocessEep.L
	MOV FLASH_DUKR,#$AE ;35 AE 50 64
	NOP ;9D
	MOV FLASH_DUKR,#$56 ;35 56 50 64
	MOV IWDG_KR,#$AA ;35 AA 50 E0
	BTJF FLASH_IAPSR,#3,UnkeyprocessEep ;72 0n MS LS XX  /72 07 50 5F EE
UnkeyprocessendEep.L
	LD A,data_ram ;C6 01 00
	LD data_eeprom,A ;C7 40 01
	MOV IWDG_KR,#$AA ;35 AA 50 E0
	BTJF FLASH_IAPSR,#2,UnkeyprocessendEep ;72 05 50 5F F1
	RET
	
TAB2.L
  DC.B $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$AA,$BB,$CC,$DD,$EE,$FF
	
unkeyprocessFla.L
	MOV FLASH_DUKR,#$AE ;35 AE 50 64
	NOP ;9D
	MOV FLASH_DUKR,#$56 ;35 56 50 64 
	MOV IWDG_KR,#$AA ;35 AA 50 E0 
	BTJF FLASH_IAPSR,#3,unkeyprocessFla ;72 07 50 5F EE 
UnkeyprocessendFla.L
	LD A,data_ram ;C6 01 00
	LD data_flash,A ;C7 90 00
	MOV IWDG_KR,#$AA ;35 AA 50 E0
	BTJF FLASH_IAPSR,#2,UnkeyprocessendFla ;72 07 50 5F F1
	LD data_flash,A ;C7 90 00
	RET
	


	interrupt NonHandledInterrupt
NonHandledInterrupt.l
	iret ;80
	
	segment 'vectit'
	dc.l {$82000000+main}									; reset
	dc.l {$82000000+NonHandledInterrupt}	; trap
	dc.l {$82000000+NonHandledInterrupt}	; irq0
	dc.l {$82000000+NonHandledInterrupt}	; irq1
	dc.l {$82000000+NonHandledInterrupt}	; irq2
	dc.l {$82000000+NonHandledInterrupt}	; irq3
	dc.l {$82000000+NonHandledInterrupt}	; irq4
	dc.l {$82000000+NonHandledInterrupt}	; irq5
	dc.l {$82000000+NonHandledInterrupt}	; irq6
	dc.l {$82000000+NonHandledInterrupt}	; irq7
	dc.l {$82000000+NonHandledInterrupt}	; irq8
	dc.l {$82000000+NonHandledInterrupt}	; irq9
	dc.l {$82000000+NonHandledInterrupt}	; irq10
	dc.l {$82000000+NonHandledInterrupt}	; irq11
	dc.l {$82000000+NonHandledInterrupt}	; irq12
	dc.l {$82000000+NonHandledInterrupt}	; irq13
	dc.l {$82000000+NonHandledInterrupt}	; irq14
	dc.l {$82000000+NonHandledInterrupt}	; irq15
	dc.l {$82000000+NonHandledInterrupt}	; irq16
	dc.l {$82000000+NonHandledInterrupt}	; irq17
	dc.l {$82000000+NonHandledInterrupt}	; irq18
	dc.l {$82000000+NonHandledInterrupt}	; irq19
	dc.l {$82000000+NonHandledInterrupt}	; irq20
	dc.l {$82000000+NonHandledInterrupt}	; irq21
	dc.l {$82000000+NonHandledInterrupt}	; irq22
	dc.l {$82000000+NonHandledInterrupt}	; irq23
	dc.l {$82000000+NonHandledInterrupt}	; irq24
	dc.l {$82000000+NonHandledInterrupt}	; irq25
	dc.l {$82000000+NonHandledInterrupt}	; irq26
	dc.l {$82000000+NonHandledInterrupt}	; irq27
	dc.l {$82000000+NonHandledInterrupt}	; irq28
	dc.l {$82000000+NonHandledInterrupt}	; irq29

	end

上面的汇编代码被汇编器编译为如下的二进制机器码:

        最上面地址为8000~807F的区域为中断向量表;下边最左边绿框为对应单片机FLASH的地址;中间对应真正的机器码;右边框对应机器码的ASCLL码值。

        我们拿data_ram为例进行说明,站在C语言的角度来讲,data_ram其实就是一个变量,CLR data_ram其实就是将该变量清零;但是站在汇编语言角度来讲,它就代表了一个地址,这个地址就是0x0100,于是CLR data_ram最终生成的机器码就是72 5F 01 00,单片机CPU取出这个指令后就会把地址0x0100处的存储单元清零。另外为了说明常数是怎么存储的,我拿下面两个常熟表进行说明:

TAB1.L
  DC.B $00,$01,$02,$03,$04,$05,$06,$07,$08,$09,$0A,$0B,$0C,$0D,$0E,$0F

TAB2.L
  DC.B $00,$11,$22,$33,$44,$55,$66,$77,$88,$99,$AA,$BB,$CC,$DD,$EE,$FF

这两个表的数值直接跟代码一起混合放在了代码存储区,由于CPU执行代码完全是根据PC寄存器指定的地址进行的,而PC寄存器是不会指向上面的这两个表的,也就是说上面这两个表是不会当做代码执行的,比如CALL UnkeyprocessEep这条指令中标号UnkeyprocessEep就会跳过TAB1,而直接找到子程序UnkeyprocessEep处。

         汇编器生成机器码之后会组织成一个文件,这个文件可以是.bin格式的,可以是.hex格式的,可以是.s19格式的,可以是sx格式的,还可以是eep格式的,它们并不是直接把赤裸裸的机器码放在上面,而是基于特定的规范增加了前缀和后缀,最终下载到单片机内部FLASH的时候就会对其进行解码,生产赤裸裸的机器码,存放到单片机FLASH中。以S19格式为例,下图就是S19文件转为机器码再下载到FLASH中的过程:

如果上面代码用C语言描述就是:

//宏定义,下面就可以直接对一个地址读写操作
#define  I2C_DR        (*(uint8_t *)0x5216)
#define  FLASH_DUKR   (*(uint8_t *)0x5064)
#define  IWDG_KR      (*(uint8_t *)0x50E0)
#define  FLASH_IAPSR   (*(uint8_t *)0x505F)
#define  data_eeprom   (*(uint8_t *)0x4001)
#define  data_flash   (*(uint8_t *)0x9001)//要保证0x9001并没有被代码占用

//定义一个usigned char类型的变量data_ram
uint8_t data_ram;
//把I2C数据寄存器中的值搬运到data_ram存储单元中
data_ram=I2C_DR;
//eeprom解锁
do
{
	FLASH_DUKR=0xae;
	Delayus(1);
	FLASH_DUKR=0x56;
	IWDG_KR=0xaa;
}while(0==FLASH_IAPSR&(1<<3);
//把数据保存到eeprom中
data_eeprom=data1+1;
//flash解锁
do
{
	FLASH_DUKR=0xae;
	Delayus(1);
	FLASH_DUKR=0x56;
	IWDG_KR=0xaa;
}while(0==FLASH_IAPSR&(1<<3);
//把数据保存到flash中
data_flash=data_ram+1;

        从上面的汇编代码和C语言代码可以很明显的看出,C语言代码中有些东西是由编译器处理的,比如全局变量data_ram内存空间分配,编译器遇到uint8_t  data_ram;之后就会在RAM中给它安排一个存储单元,这个存储单元的地址是固定不变的,而这其实就是分配好了变量data_ram的存储空间。

 

 

       

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/tanguohua_666/article/details/89031718
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2019-09-13 23:44:12
  • 阅读 ( 2219 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢