由ICCAVR编译mega128的mp文件,为何从0x06F1执行程序?
NOTE: AVR Code addresses are word addressesAll other addresses (including ones in FLASH) are byte addresses
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
lit 008C 0D0E = 3342. bytes (rel,con,rom)
AddrGlobal Symbol
-------------------------------------
008C_char14
008C__lit_start
016C_char16
022C_char24
073C_char32
083C_num32
0ABC_char8_1
0B5C_char8_2
0BDA_symble1_8
0BEA_symble2_8
0C06_num8
0CA6_num8_3
0CE6_num8_2
0D72_Channel
0D7A_DecimalHex
0D9A__lit_end
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
idata 0D9A 0048 = 72. bytes (rel,con,rom)
AddrGlobal Symbol
-------------------------------------
0D9A__idata_start
0DE2__idata_end
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
text 0DE2 3126 =12582. bytes (rel,con,rom)
AddrGlobal Symbol
-------------------------------------
06F1__text_start
06F1__start
0711_exit
0712_main
0949_uart0_init
0956_uart0_rx_isr
0A04_uart0_udre_isr
0A62_uart0_tx_isr
0A6B_SendUpdateData
0AB1_SendUpdateKey
0AEA_Port_init
0B07_Sys_init
0B0D_watchdog_init
0B13_Switch_driver
0B47_Delay
0B5E_Delay1
0B6C_E_to_P
0B84_SampleStart
0B8F_SampleStop
0B93_spi_stc_isr
0BF1_Ad_Sample
0C08_KEYscan
0C85_Timer2_init
0C92_Timer2OvfIsr
0CA0_Timer2Stop
0CA3_Timer2Start
0CA6_AD_To_Disp1
0CE2_AD_To_Disp2
0D23_WS_calculate
0D6E_ttvalue
0D85_kvalue
0DC1_pmdisp_calcu
0E24_Wr_Data
0E39_Wr_Ctrl
0E56_RD_Status
0E6D_RD_Datas
0E84_WRCTRL_2
0E91_WRCTRL
0E99_LCM_init
0ED5_WRCONST_auto
0EDE_RDATA_auto
0EE5_ADDRES_change
0EF4_RDADDRES_auto
0F11_WRADDRES_auto
0F2C_Dis_All
0F4B_Clrram
0F67_Clrgraph
0F83_Clr_Part
0FA4_Dis_zimo
0FEF_Dis_char16_16
101E_Dis_char16_14
1043_Dis_char16_32
1072_Dis_char8_14
109C_Dis_char24_24
10C1_Dis_char16_24
10E6_Dis_char8_16
1110_Put_pixel
1131_Clear_pixel
1152_Clear_liney
1164_Line_x
117E_Line_y
1198_Draw_line
11E2_Draw_on_line
1279_Draw_fullline
135A_Dis_coordinate
137A_Dis_xcoordinate
1399_Dis_ycoordinate
13B8_Dis_FIRSTscreen
13D6_Dis_EValue
1485_Dis_WMValue
14EE_Dis_PpMValue
17B7_Dis_TTValue
1817_Dis_WorkState
185B_Dis_TUnitage
1902_Dis_PUnitage
19CA_Dis_SndScreen
1A3B_Snd_Refurbish
1AA9_Dis_ESetScree
1B1D_Dis_PSetScree
1B91_Dis_WSetScree
1C36_Dis_TrdScreen
1C42_Trd_Refurbish
1C64_KEYanswer
1E1Dpush_arg4
1E1Fpush_arg2
1E22mod16u
1E24div16u
1E25xdiv16u
1E3Ediv32u
1E40mod32u
1E44div32s
1E46mod32s
1E71long_div_prolog
1E84long_div_epilog
1E93tst_R16_R19
1E98tst_R24_R27
1E9Dneg_R16_R19
1EA6neg_R24_R27
1EAFmod8u
1EB1div8u
1EB2xdiv8u
1EC7empy16s
1ED7empy32u
1ED7empy32s
1F07pop_gset2
1F0Apop_gset3
1F0Dpop_gset4
1F10pop_gset5
1F13push_gset1
1F16pop_gset1
1F17pop
1F2Apush_gset2
1F2Epush_gset3
1F32push_gset4
1F36push_gset5
1F3Along_prolog
1F48long_epilog
1F53tstzero1
1F59tstzero2
1F5Flsl16
1F66lsl32
1F72lsl8
1F78lsr32
1F84__text_end
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
data 0100 0048 = 72. bytes (rel,con,ram)
AddrGlobal Symbol
-------------------------------------
0100__data_start
0100_MainState
0101_EZeroNum
0102_EmData
0104_Pulse_flag
0105_ad_enable_flag
0106_ESetRange
0107_PSetRange
0108_EHoldflag
0109_WSetwave
010A_TimeUnit
0115_PowerUnit
011C_WorkState
011D_SetState
011E_Disp_change
011F_Trd_Disp_change
0120_P_Unitage
0122_TmpKey
0123_KeyTime
0124_KeyState
0125_DispState
0126_UartReceiveNum
0127_UartReceiveDataNum
0128_UartSendNum
0129_UartRecChk
012A_UartSendChk
012B_UartLength
012C_UartRecieveOver
012D_UartSendOver
012E_ADS7844State
012F_numx
0133_numy
0137_Wm_value
0139_E_Value
013B_P_Value
013D_EZEROsum
013F_Pm_bit_nub
0140_tmppm
0144_tmpk
0148__data_end
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
bss 0148 0837 = 2103. bytes (rel,con,ram)
AddrGlobal Symbol
-------------------------------------
0148__bss_start
0148_ADResult
0158_Rslt16
015A_UartSend
0163_UartSendData
0165_UartSendBuffer
0183_UartRecBuffer
018D_EZeroData
01F1_Curve
097D_Adrs
097F__bss_end
Area Addr Size Decimal Bytes (Attributes)
-------------------------------- ---- ---- ------- ----- ------------
vector 0000 0054 = 84. bytes (abs,ovr,rom)
Files Linked [ module(s) ]
C:\icc\lib\crtatmega.o [ crtatmega.s ]
6312a.o [ _6312a.c ]
<library> [ asave.s, div16u.s, div32.s, div8u.s, emul16s.s, emul32.s, gpop2.s, gpop3.s, gpop4.s, gpop5.s, gpush.s ]
[ gpush2.s, gpush3.s, gpush4.s, gpush5.s, longutil.s, lsl16.s, lsl32.s, lsl8.s, lsr32.s ]
User Global Definitions
ram_end = 0x10ff
hwstk_size = 0x10
User Base Address Definitions
func_lit = 0x8c
data = 0x100
eeprom:1.4096 首先,程序烧入mega128中能够正常运行,一切正常;其次,我的好奇心作怪,喜欢钻个究竟,当调试程序时发现,复位后程序不是从中断向量表后地址0x48开始运行,在打开mp文件、lst文件后,发现在0x48到启动代码之间为空白,百思不解,lst文件详见下:
__text_start:
__start:
06F1 EFCF LDI R28,0xFF
06F2 E1D0 LDI R29,0x10
06F3 BFCD OUT 0x3D,R28
06F4 BFDE OUT 0x3E,R29
06F5 51C0 SUBI R28,0x10
06F6 40D0 SBCI R29,0
06F7 EA0A LDI R16,0xAA
06F8 8308 STD Y+0,R16
06F9 2400 CLR R0
06FA E4E8 LDI R30,0x48
06FB E0F1 LDI R31,1
06FC E019 LDI R17,0x9
06FD 37EF CPI R30,0x7F
06FE 07F1 CPC R31,R17
06FF F011 BEQ 0x0702
0700 9201 ST R0,Z+
0701 CFFB RJMP 0x06FD
0702 8300 STD Z+0,R16
0703 E9EA LDI R30,0x9A
0704 E0FD LDI R31,0xD
0705 E0A0 LDI R26,0
0706 E0B1 LDI R27,1
0707 E01D LDI R17,0xD
0708 3EE2 CPI R30,0xE2
0709 07F1 CPC R31,R17
070A F021 BEQ 0x070F
070B 95C8 LPM
070C 9631 ADIW R30,1
070D 920D ST R0,X+
070E CFF9 RJMP 0x0708
070F 940E0712CALL _main
_exit:
0711 CFFF RJMP _exit
_main:
p --> Y+3
j --> Y+3
i --> Y+3
sum --> R10
tmpt --> R10
aveezerodata --> R10
tmpc --> Y+2
ADetmp16 --> R14
uarttmp --> Y+7
timer0 --> Y+6
ADwtmp16 --> R12
0712 9728 SBIW R28,0x8
FILE: D:\cx\atmega128\IccAvr6.3\scr\main.c
(0001) //#include "include.h"
(0002) /*******************************************************************************
(0003) * 函数功能:主函数
(0004) * 函数参数:无
(0005) * 函数返回:无
(0006) * 备 注:无
(0007) *******************************************************************************/
(0008) void main(void)
(0009) {
(0010)
(0011) INT16U ADwtmp16; //取波形通道采样值
(0012) INT16U ADetmp16; //取能量通道采样值
(0013) INT8Ui,j;
(0014) INT8U timer0 = 0;
0713 2400 CLR R0
0714 820E STD Y+6,R0
(0015) INT32U tmpc = 0;
0715 E040 LDI R20,0
0716 E050 LDI R21,0
0717 E060 LDI R22,0
0718 E070 LDI R23,0
0719 01FE MOVW R30,R28
071A 8342 STD Z+2,R20
071B 8353 STD Z+3,R21
071C 8364 STD Z+4,R22
071D 8375 STD Z+5,R23
(0016) INT8U tmpt = 0;
071E 24AA CLR R10
(0017)
(0018)
(0019) INT8U uarttmp = 0; //区别采样数据发送类别
071F 820F STD Y+7,R0 iccavr版本6.30C avrstudio版本4.13
经过avrstudio反汇编发现,复位后程序直接跳转到06F1处,为何?0x06F1到0x0711之间为启动代码,其主要功能为初始化硬件和软件堆栈指针,bss 区全部初始化为零,从idata 区拷贝初始化数据到直接寻址数据区data 区,调用main 函数,定义main函数退出点等。
我的理解是启动代码应该是在中断向量表之后的,即0x48处开始,请马老师指点指点。
反汇编代码如下:
+00000000: 940C06F1 JMP 0x000006F1 Jump
+00000002: FFFF ??? Data or unknown opcode
-------
-------
+00000048: 0007 ??? Data or unknown opcode
+00000049: 800A LDD R0,Y+2 Load indirect with displacement
+0000004A: 6032 ORI R19,0x02 Logical OR with immediate
+0000004B: 18C2 SUB R12,R2 Subtract without carry
+0000004C: E03F LDI R19,0x0F Load immediate
+0000004D: 2020 AND R2,R0 Logical AND
+0000004E: E03F LDI R19,0x0F Load immediate
+0000004F: 2020 AND R2,R0 Logical AND
+00000050: E03F LDI R19,0x0F Load immediate
+00000051: 0000 NOP No operation
+00000052: F8FF ??? Data or unknown opcode
+00000053: 0000 NOP No operation
+00000054: 0084 ??? Data or unknown opcode
+00000055: F067 BRIE PC+0x0D Branch if interrupt enabled
+00000056: 1024 CPSE R2,R4 Compare, skip if equal
+00000057: 1008 CPSE R0,R8 Compare, skip if equal
+00000058: D007 RCALL PC+0x0008 Relative call subroutine
+00000059: 50E4 SUBI R30,0x04 Subtract immediate
+0000005A: 5024 SUBI R18,0x04 Subtract immediate
+0000005B: D027 RCALL PC+0x0028 Relative call subroutine
+0000005C: 5024 SUBI R18,0x04 Subtract immediate
+0000005D: 5024 SUBI R18,0x04 Subtract immediate
+0000005E: D02F RCALL PC+0x0030 Relative call subroutine
+0000005F: 1030 CPSE R3,R0 Compare, skip if equal
+00000060: 6020 ORI R18,0x00 Logical OR with immediate
+00000061: 0000 NOP No operation
--------------
--------------
+000006F1: EFCF SER R28 Set Register
+000006F2: E1D0 LDI R29,0x10 Load immediate
+000006F3: BFCD OUT 0x3D,R28 Out to I/O location
+000006F4: BFDE OUT 0x3E,R29 Out to I/O location
+000006F5: 51C0 SUBI R28,0x10 Subtract immediate
+000006F6: 40D0 SBCI R29,0x00 Subtract immediate with carry
+000006F7: EA0A LDI R16,0xAA Load immediate
+000006F8: 8308 STD Y+0,R16 Store indirect with displacement
+000006F9: 2400 CLR R0 Clear Register
+000006FA: E4E8 LDI R30,0x48 Load immediate
+000006FB: E0F1 LDI R31,0x01 Load immediate
+000006FC: E019 LDI R17,0x09 Load immediate
+000006FD: 37EF CPI R30,0x7F Compare with immediate
+000006FE: 07F1 CPC R31,R17 Compare with carry
+000006FF: F011 BREQ PC+0x03 Branch if equal
+00000700: 9201 ST Z+,R0 Store indirect and postincrement
+00000701: CFFB RJMP PC-0x0004 Relative jump
+00000702: 8300 STD Z+0,R16 Store indirect with displacement
+00000703: E9EA LDI R30,0x9A Load immediate
+00000704: E0FD LDI R31,0x0D Load immediate
+00000705: E0A0 LDI R26,0x00 Load immediate
+00000706: E0B1 LDI R27,0x01 Load immediate
+00000707: E01D LDI R17,0x0D Load immediate
+00000708: 3EE2 CPI R30,0xE2 Compare with immediate
+00000709: 07F1 CPC R31,R17 Compare with carry
+0000070A: F021 BREQ PC+0x05 Branch if equal
+0000070B: 95C8 LPM Load program memory
+0000070C: 9631 ADIW R30,0x01 Add immediate to word
+0000070D: 920D ST X+,R0 Store indirect and postincrement
+0000070E: CFF9 RJMP PC-0x0006 Relative jump
+0000070F: 940E0712 CALL 0x00000712 Call subroutine
+00000711: CFFF RJMP PC-0x0000 Relative jump
@00000712: main
---- scr\main.c -----------------------------------------------------------------------------------
8: void main(void)
+00000712: 9728 SBIW R28,0x08 Subtract immediate from word
14: INT8U timer0 = 0;
+00000713: 2400 CLR R0 Clear Register
+00000714: 820E STD Y+6,R0 Store indirect with displacement
15: INT32U tmpc = 0;
+00000715: E040 LDI R20,0x00 Load immediate
--------------
-------------- 采用任何的高级语言环境,它在编译你的代码时都要加上其本身的系统初始化程序,这些程序包括中断向量的设置、堆栈指针的设置,必要的内存清零,以及系统本身需要使用的寄存器设置等。
作为程序员本身并没有编写这些必要的初始化代码,但编译系统必须要给你加上的。这样做节省了程序员的时间,也是使用高级语言的优点,但也容易培养出一批“高级傻瓜程序员”。
再者,系统从0000H开始执行跳转指令,但并没有规定必须跳到堆栈后执行,它是可以跳到任何地方的。ICCAVR先把一些它自己的内部函数、宏操作定位到堆栈后的代码空间中,然后在放置启动代码,最后是你的代码的。 “ICCAVR先把一些它自己的内部函数、宏操作定位到堆栈后的代码空间中”这句话最为点睛,谢谢马老师!!!
也就是说堆栈到启动代码之间的空间跟我所引用的ICCAVR内部函数及宏操作有直接关联,事实我做了几次实验,果真如此。原来我的想法是“0000H---堆栈结束”+“启动代码”+“应用程序”,还有就是原来我认为初始化代码==启动代码。
这次明白了,嘻嘻!
页:
[1]