Gdb/Armulator 源代碼分析
作者Email: Anti_chen2000@sohu.com 摘要 Gdb/Armulator 是Gdb自帶的arm7模擬器,是調試arm程序的一個好工具.而了解它的原碼結構對擴展它的IO功能有重要意義.本文介紹了從Armulator的啟動到其內部運作和IO擴展的大部分原代碼功能. 說明 源代碼用的是gdb-5.0.tar+ gdb-5.0-uclinux-armulator-20021127.patch A.和GDB間的通迅 Armulator一般和Gdb通訊有兩種方式,其一是在Gdb內部直接調用模擬器的相關函數(shù),另一方法則是用pipe或socket傳遞RDP協(xié)議來連接Gdb和Amulator.而第一種方法是現(xiàn)在Gdb/Armulator所真正使用的(第二種是早期使用的方法),下面就分析了函數(shù)直接調用法. 函數(shù)直接調用 這個方法是由Steve (sac@cygnus.com) 修改原RDP方法而來的,Steve本人的描述如下: It likes to use TCP/IP between the simulator and the host, which is I've added created a new Makefile.in (the original in Makefile.orig) It should be possible (barring major changes in the layout of (Except that I changed armos.c to work more simply with our 以下是RDP 通訊和直接函數(shù)調用的圖示: 要清楚Armulator的執(zhí)行過程就要從它的啟動說起,當你在Gdb中鍵入target sim 去激活Amulator后Gdb首先進行命令行解釋,并將current_target指針指向sim變量,即將Armulator的調試函數(shù)集賦予Gdb,隨后的函數(shù)調用堆棧如下: --gdbsim_open (…) in remote-sim.c. 至此Armulator被裝載完畢,其后Gdb就是通過target_ops(定義在target.h)結構中的各個函數(shù)指針來完成對它的調試工. B.Armulator 內部機制 a.初始化 從上述可知整個模擬器的初始化入口是在wrapper.c中的init( )函數(shù),那么它到底又做了些什么呢? (原始的Gdb5.0中的Armulator是模擬ARM7DTMI 的,而補丁代碼修改了memory map 并添加了timer 和uart 的IO能力使其能夠模擬AT91.因為后者是對前者的增強,所以我們的分析以后者為準) Once the armulator to reset ,the ARMul_NewState will be called.And its task is to malloc a ARMul_state stuct which saves the armulator’s states and initialize it .And the ARMul_MemoryInit() will malloc 4m ram for you. 因為這是補丁代碼,難免又冗余出現(xiàn),實際10-11行的兩處掉用是沒有實際意義的,而12行是協(xié)處理器的初始化,因為并沒又模擬協(xié)處理器所以此處只是以備擴展. 重點的初始化過程是在ARMul_NewState(…)中的.首先它給模擬器的核心狀態(tài)結構ARMul_State分配了空間,這個結構里保存了Armulator的所有方面的狀態(tài),包括arm寄存器,流水線狀態(tài)等等. 并賦予初值,我們以后就用state表示之.然后調用ARMul_Reset(…)進行更近一步的設置.而后者又主要完成模擬器內存結構的分配和rom映象的加載--/sim/arm/armmem.c/mem_reset(…),IO設備的狀態(tài)初始―/sim/arm/armio.c/io_reset(…),你也可在這添加你的初始代碼.到這就完成了Armulator的裝載. (大家注意到18行也調用了ARMul_Reset(…),這是一個BUG,使得模擬器進行了兩次內存分配,而浪費了系統(tǒng)內存.此處可刪去.) Memory map 是所有模擬器的關鍵.Armulator由AT91向其他MCU移植時Memory map又是首先要處理的.Armulator的各個內存區(qū)是由mem_bank_t結構來描述的: typedef struct mem_bank_t { 根據(jù)mem_banks,mem_reset( )將分配空間,加載boot.rom文件. (原來的內存是由ARMul_MemoryExit( )釋放的,但補丁后的代碼就沒了釋放功能,這也是需要糾正的地方) a.指令流 Armulator 加載完成后,就開始等待Gdb的運行命令了.最終/sim/wrapper.c/sim_resume( )是啟動arm指令執(zhí)行的地方. Sim_resume( )根據(jù)Gdb的要求選擇用/sim/arm/arminit.c/ARMul_DoInstr()還是用/sim/arm/arminit.c/ARMul_DoProg()來調用 流水線模擬函數(shù)/sim/arm/armemu.c/ARMul_Emulate32().ARMul_DoInstr()和ARMul_DoProg()的區(qū)別就是一個單步執(zhí)行,一個連續(xù)執(zhí)行指令. ARMul_DoProg()又不停的判斷state->Emulate是否為STOP,如果是,模擬器又將停下等待Gdb的調試. 而在arm/armemu.c, /arm/armvirt.c 和 /arm/armsupp.c中的函數(shù)則模擬指令預取,指令譯碼,指令執(zhí)行以及數(shù)據(jù)回寫的功能.這三個文件時可以說時Armulator的核心! b.中斷 Armulator 的中斷機制主要靠以下兩個例程實現(xiàn): 1.IntPending(): 用來檢測state中的各個中斷標志是否置位,從而判斷是否又需要中斷. 2.ARMul_Abort():當需要中斷時,用來改變處理器模式,并將pc指向相應的中斷向量. 在流水線函數(shù)ARMul_Emulate32()執(zhí)行當中,有多處調用IntPending() 去檢測中斷.而Ispending() 也十分簡單,它僅僅判斷state中的四個變量: State->Exception : 中斷使能標志. b.讀寫操作 無論是CPU指令還是Gdb調試時讀寫內存或IO空間,最后都將要落到/armvirt.c/getword(), /armvirt.c/putword()這兩個函數(shù)身上. 在原始代碼中這兩個函數(shù)馬上就進行內存數(shù)組的讀寫了.而補丁代碼的流程如下: --getword()/putword() 可以看出最后幾個函數(shù)的選擇是由讀寫地址在相應的mem_bank_t結構中的讀寫函數(shù)指針決定的. c.設備同步 寫這篇文章的初衷是讓讀者能很快進入Armulator的移植和IO擴展的實際工作中去.所以這里有必要討論一下IO設備和CPU的同步問題.很顯然我們模擬的設備不能太快,也不能太慢.快了CPU正常的指令流將被堵塞,慢了就無法反映操作系統(tǒng)的實時性.也就是說設備的速度和指令流要有個比例關系,即要有一定的同步. Armulator 中有個很好的接口: ARMul_ScheduleEvent (ARMul_State * state, unsigned long delay, unsigned (*what) ()) in armvirt.c 它的目的就是注冊你的同步例程,并且每個時鐘周期即ARMul_Emulate32()將調用ARMul_ScheduleEvent()查看是否需要同步你的設備. 也許你在ARMul_Emulate32()中還發(fā)現(xiàn)了/sim/arm/armio.c/io_do_cycle(),沒錯它是AT91的timer和uart用來和指令流同步的函數(shù),但我并不贊成你象這樣把自己的同步例程直接放入指令執(zhí)行過程中,破壞代碼的結構性. a. 源文件描述
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
tcp/ip相關文章:tcp/ip是什么
評論