Arm_linux_启动分析_第1页
Arm_linux_启动分析_第2页
Arm_linux_启动分析_第3页
Arm_linux_启动分析_第4页
Arm_linux_启动分析_第5页
已阅读5页,还剩50页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Arm linux 启动分析(1王利明 walimi 宋振宇zhenyusong 2003-3-201.概述:在内核运行之前需要系统引导程序(Bootloader完成加载内核和一些辅助性的工作,然后跳转到内核代码的起始地址并执行。本文先分析了Bootloader 的初始化工作,接着从内核镜像的起始地址进行分析。整个arm linux 内核的启动可分为三个阶段:第一阶段主要是进行cpu 和体系结构的检查、cpu 本身的初始化以及页表的建立等;第二阶段主要是对系统中的一些基础设施进行初始化;最后则是更高层次的初始化,如根设备和外部设备的初始化。第一阶段的初始化是从内核入口(ENTRY(stext开

2、始到start_kernel 前结束。这一阶段的代码在/arch/arm/head_armv.S 中。 2.Bootloader 2.1简介 本处介绍主要来自内核源代码下的Documentation/arm/Booting 文件,适合于arm linux 2.4.18-rmk6及以上版本。Bootloader 主要作用是初始化一些必要的设备,然后调用内核,同时传递参数给内核。主要完成如下工作:1. 建立和初始化RAM 。 2. 初始化一个串口。 3. 4.建立内核的5. 调用内核镜像。 2.2功能详细介绍 1.建立和初始化RAM 。 要求:必须功能:探测所有的RAM 位置和大小,并对RAM 进

3、行初始化。 2.初始化一个串口。要求:可选,建议功能:Bootloader 应该初始化并启动一个串口。这可以让内核的串口驱动自动探测哪个串口作为内核的控制台。另外也可以通过给内核传递“console=”参数完成此工作。 3.检测机器的系统结构。要求:必须功能:Bootloader 应该通过某种方法探测机器类型,最后传递给内核一个MACH_TYPE_xxx 值, 这些值参看4要求:必须功能:Bootloader 必须创建和初始化内核的tagged list 。一个合法的tagged list 开始于ATAG_CORE 并结束于ATAG_NONE 。ATAG_CORE tag 可以为空。一个空的A

4、TAG_CORE tag 的size 字段设为“2”(0x00000002。ATAG_NONE 的size 字段必须设为“0”。tagged list 以及根文件系统 +-+base - | ATAG_CORE | |+-+ | ATAG_MEM | | increasing address+-+ | ATAG_NONE | |+-+ vtagged list应该放在内核解压时和initrd的”bootp”程序都不会覆盖的内存区域。建议放在RAM的起始的16K大小的地方。5.调用内核镜像。要求:必须功能:可以从flash调用内核,也可以从系统RAM中调用内核。对于后者需要注意,内核使用内核镜像

5、以下的16K内存作为页表,建议把内核起始放在RAM的32K处。无论是哪种方法, Instruction cache may be on or off. 2.3 Skyeye相应说明因为Skyeye完成,如r1的设置等。3.Head_armv.S分析3.1 说明这个文件是arch/arm/kernel/head-armv.S,用汇编代码完成,是内核最先执行的一个文件。这一段汇编代码的主要作用,是检查cpu id,architecture number,初始化页表、cpu、bbs等操作,并跳到start_kernel函数。它在执行前,处理器的状态应满足:r0 - should be 0r1 - u

6、nique architecture numberMMU - offI-cache - on or offD-cache off3.2 流程3.3 代码详细注释(略去一些条件编译的代码-/* We place the page tables 16K below TEXTA DDR. Therefore, we must make sure* that TEXTADDR is correctly set. Currently, we expect the least significant* short to be 0x8000, but we could probably relax this

7、 restriction to* TEXTA DDR PA GE_OFFSET + 0x4000* Note that swapper_pg_dir is the virtual address of the page tables, and* pgtbl gives us a position-independent reference to these tables. We can* do this because stext = TEXTADDR* swapper_pg_dir, pgtbl and krnladr are all closely related.*/#if (TEXTA

8、DDR & 0xffff != 0x8000#error TEXTADDR must start at 0xXXXX8000#endif.globl SYMBOL_NAME(swapper_pg_dir.equ SYMBOL_NAME(swapper_pg_dir, TEXTADDR - 0x4000.macro pgtbl, reg, rambaseadr reg, stextsub reg, reg, #0x4000.endm/* Since the page table is closely related to the kernel start address, we* can con

9、vert the page table base address to the base address of the section* containing both.*/.macro krnladr, rd, pgtable, rambasebic rd, pgtable, #0x000ff000.endm/* Kernel startup entry point.* The rules are:* r0 - should be 0* r1 - unique architecture number* MMU - off* I-cache - on or off* D-cache - off

10、* See linux/arch/arm/tools/mach-types for the complete list of numbers* for r1.*/.section .text.init,#alloc,#execinstr.type stext, #functionENTRY(stext /内核入口点mov r12, r0 /r0=0,r12=0mov r0, #F_BIT | I_BIT | MODE_SVC make sure svc mode/程序状态,禁止FIQ、IRQ,设定Supervisor模式。0b11010011 msr cpsr_c, r0 and all ir

11、qs disabled/置当前程序状态寄存器bl _lookup_processor_type/跳转到判断cpu类型,查找运行的cpu的id值,和/此linux编译支持的id值,是否有相等teq r10, #0 invalid processor?/没有则跳到_errormoveq r0, #p yes, error pbeq _errorbl _lookup_architecture_type/跳转到判断体系类型,看r1寄存器的/architecture number值是否支持。teq r7, #0 invalid architecture? /不支持,跳到出错moveq r0, #a ye

12、s, error abeq _errorbl _create_page_tables/创建核心页表adr lr, _ret return address/lr=0xc0028054add pc, r10, #12 initialise processor/r10:pointer to processor structure/(_arm720_proc_info/r10+12:_arm720_setup;见/_arm720_proc_info(proc-arm720.S_arm720_setup: mov r0, #0mcr p15, 0, r0, c7, c7, 0 invalidate ca

13、chesmcr p15, 0, r0, c8, c7, 0 flush TLB (v4mcr p15, 0, r4, c2, c0 load page table pointer/cp15寄存器1(ttb=0xc0024000mov r0, #0x1f Domains 0, 1 = clientmcr p15, 0, r0, c3, c0 load domain access registermrc p15, 0, r0, c1, c0 get control register /r0=0x70bic r0, r0, #0x0e00 .V. .R S BLDP WCAM /bit11:9=0

14、r0=0x00000070orr r0, r0, #0x2100 . . .111 . (old/r0=0x00002170orr r0, r0, #0x003d .1. .01 .11 1101 (new /r0=0x0000217d其中S LDPWC M位置1。(详见cp15寄存器1说明mov pc, lr _ret (head-armv.S (return control reg.type _switch_data, %object_switch_data: .long _mmap_switched.long S YMBOL_NAME(_bss_start.long S YMBOL_NA

15、ME(_end.long S YMBOL_NAME(processor_id.long S YMBOL_NAME(_machine_arch_type.long S YMBOL_NAME(cr_alignment.long S YMBOL_NAME(init_task_union+8192.type _ret, %function_ret: ldr lr, _switch_datamcr p15, 0, r0, c1, c0/更新控制寄存器cp15寄存器1=0x0000217dmov r0, r0mov r0, r0mov r0, r0mov pc, lr/_switch_data/* Thi

16、s code follows on after the page* table switch and jump above.* r0 = processor control register* r1 = machine ID* r9 = processor ID*/.align 5_mmap_switched:/把sp指针指向init_task_union+8192(include/linux/sched.h处,即第/一个进程的task_struct和系统堆栈的地址;清空BSS段;保存processor ID/和machine type,到全局变量processor_id和_machine_a

17、rch_type,这些值/以后要用到;r0为A置位的control register 值,r2为A清空的/control register 值,即对齐检查(Alignment fault checking位,并保/存到cr_alignment,和cr_no_alignment(在文件entry-armv.S中。最/后跳转到start_kernel(init/main.cadr r3, _switch_data + 4 /_bss_startldmia r3, r4, r5, r6, r7, r8, sp r2 = compat/r2=0xc0000000 sp = stack pointer/

18、r4=0xc00c04e0;_bss_start/r5=0xc00e02a8;_end/r6=0xc00c0934;processor_id/r7=0xc00c0930;_machine_arch_type/r8=0xc00bcb88;cr_alignment/sp=0xc00bc000; (init_task_union+8192mov fp, #0 Clear BSS (and zero fp1: cmp r4, r5strcc fp, r4,#4bcc 1bstr r9, r6 Save processor IDstr r1, r7 Save machine type#ifdef CON

19、FIG_ALIGNMENT_TRAPorr r0, r0, #2 .A.#endifbic r2, r0, #2 Clear A bit/r0=0x217dstmia r8, r0, r2 Save control register valuesb SYMBOL_NAME(start_kernel/跳转到start_kernel/* Setup the initial page tables. We only setup the barest* amount which are required to get the kernel running, which* generally means

20、 mapping in the kernel code.* We only map in 4MB of RAM, which should be sufficient in* all cases.* r5 = physical address of start of RAM* r6 = physical IO address* r7 = byte offset into page tables for IO* r8 = page table flags*/_create_page_tables:pgtbl r4, r5 page table address/调用宏pgtbl,r4=0xc002

21、4000:页表基址/* Clear the 16K level 1 swapper page table*/mov r0, r4/r0=0xc0024000mov r3, #0add r2, r0, #0x4000/r2=0xc00280001: str r3, r0, #4str r3, r0, #4str r3, r0, #4str r3, r0, #4teq r0, r2bne 1b /将地址0xc00240000xc0028000清0/* Create identity mapping for first MB of kernel to* cater for the MMU enabl

22、e. This identity mapping* will be removed by paging_init(*/krnladr r2, r4, r5 start of kernel/r2=0xc0000000;r4=0xc0024000 add r3, r8, r2 flags + kernel base/flags,r8=0xc1e;r3=0xc0000c1e str r3, r4, r2, lsr #18 identity mapping/addr:0xc0027000;value:0xc0000c1e /* Now setup the pagetables for our kern

23、el direct* mapped region. We round TEXTADDR down to the* nearest megabyte boundary.*/add r0, r4, #(TEXTADDR & 0xff000000 18 start of kernel/r0=0xc0027000 bic r2, r3, #0x00f00000 /r2=0xc0000c1estr r2, r0 PA GE_OFFSET + 0MBadd r0, r0, #(TEXTADDR & 0x00f00000 18str r3, r0, #4 KERNEL + 0MBadd r3, r3, #1

24、 20str r3, r0, #4 KERNEL + 1MBadd r3, r3, #1 20str r3, r0, #4 KERNEL + 2MBadd r3, r3, #1 18 round down/r0=0xc0027000and r2, r5, #0xfe000000 round down/r2=0xc0000000add r3, r8, r2 flags + rambase/r3=0xc0000c1estr r3, r0bic r8, r8, #0x0c turn off cacheable/r8=0xc12 and bufferable bitsmov pc, lr* Read

25、processor ID register (CP#15, CR0, and look up in the linker-built* supported processor list. Note that we cant use the absolute addresses* for the _proc_info lists since we arent running with the MMU on* (and therefore, we are not in the correct address space. We have to* calculate the offset.* Ret

26、urns:* r5, r6, r7 corrupted* r8 = page table flags* r9 = processor ID* r10 = pointer to processor structure*/_lookup_processor_type:/判断cpu类型adr r5, 2f /取标号2的地址ldmia r5, r7, r9, r10 /r7:_proc_info_end;r9:_proc_info_begin;r10:r5sub r5, r5, r10 convert addresses /r5=0?add r7, r7, r5 to our address spac

27、eadd r10, r9, r5 /r10:_proc_info_beginmrc p15, 0, r9, c0, c0 get processor id /读取cp15寄存器0中cpu id至r9。在此版本是0x418072001: ldmia r10, r5, r6, r8 value, mask, mmuflags /读取arm linux中cpu信息/ r5,id:0x41807200;r6,mask:/0xffffff00;r8,mmuflags即一级描/述符:0xc1eand r6, r6, r9 mask wanted bits /屏蔽cpu id的低8位teq r5, r6 /

28、寄存器0的cpu id与arm linux中cpu id比较moveq pc, lr /相同则返回add r10, r10, #36 sizeof(proc_info_list/否则寻找下一块proc_infocmp r10, r7blt 1bmov r10, #0 unknown processor /没有匹配信息,r10=0mov pc, lr/* Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.ch for* more information about the _proc_info and _arch_info s

29、tructures.*/2: .long _proc_info_end.long _proc_info_begin.long 2b.long _arch_info_begin.long _arch_info_end* Lookup machine architecture in the linker-build list of architectures.* Note that we cant use the absolute addresses for the _arch_info* lists since we arent running with the MMU on (and ther

30、efore, we are* not in the correct address space. We have to calculate the offset.* r1 = machine architecture number* Returns:* r2, r3, r4 corrupted* r5 = physical start address of RAM* r6 = physical address of IO* r7 = byte offset into page tables for IO*/_lookup_architecture_type:/判断体系类型adr r4, 2b/

31、取上面标号2的地址ldmia r4, r2, r3, r5, r6, r7 throw away r2, r3/r5:r4;r6:_arch_info_begin;r7:_arch_info_end sub r5, r4, r5 convert addresses/r5=0add r4, r6, r5 to our address space/r4:_arch_info_begin;add r7, r7, r51: ldr r5, r4 get machine typeteq r5, r1/r1是machine type 号,此为91beq 2fadd r4, r4, #SIZEOF_MA C

32、HINE_DESC/不匹配,查找下一个arch_infocmp r4, r7blt 1bmov r7, #0 unknown architecturemov pc, lr2: ldmib r4, r5, r6, r7 found, get results/r5,ram物理起始地址:0xc0000000;r6,io地址:0x8000000;r7,io在页表的偏移:0x3fc0 mov pc, lr /返回首先,porting linux的时候要规划内存影像,如小弟的系统有64m SDRAM,地址从0x 0800 0000 -0x0bff ffff,32m flash,地址从0x0c00 0000

33、-0x0dff ffff.规划如下:bootloader, linux kernel, rootdisk放在flash里。具体从0x0c00 0000开始的第一个1M放bootloader,0x0c10 0000开始的2m放linux kernel,从0x0c30 0000开始都给rootdisk。启动:首先,启动后arm920T将地址0x0c00 0000映射到0(可通过跳线设置,实际上从0x0c00 0000启动,进入我们的bootloader,但由于flash速度慢,所以bootloader前面有一小段程序把bootloader拷贝到SDRAM 中的0x0AFE0100,再从0x 080

34、0 0000 运行bootloader,我们叫这段小程序为flashloader, flashloader必须要首先初始化SDRAM,不然往那放那些东东:.equ SOURCE, 0x0C000100 bootloader的存放地址.equ TARGET, 0x0AFE0100 目标地址.equ SDCTL0, 0x221000 SDRAM控制器寄存器/ size is stored in location 0x0C0000FC.global _start_start: /入口点/;*/;* Init SDRAM/;*/ ;*/ ;* SDRAM/ ;*LDR r1, =SDCTL0 / ;

35、Set Precharge CommandLDR r3, =0x92120200/ldr r3,=0x92120251STR r3, r1/ ; Issue Precharge All CommadLDR r3, =0x8200000LDR r2, r3/ ; Set AutoRefresh CommandLDR r3, =0xA2120200STR r3, r1/ ; Issue AutoRefresh CommandLDR r3, =0x8000000LDR r2, r3LDR r2, r3LDR r2, r3LDR r2, r3LDR r2, r3LDR r2, r3LDR r2, r3

36、LDR r2, r3/ ; Set Mode RegisterLDR r3, =0xB2120200STR r3, r1/ ; Issue Mode Register CommandLDR r3, =0x08111800 /; Mode Register value LDR r2, r3/ ; Set Norm al ModeLDR r3, =0x82124200STR r3, r1/;* /;* End of SDRAM and SyncFlash Init */;* / copy code from FLASH to SRAM_CopyCodes:ldr r0,=SOURCEldr r1,

37、=TARGETsub r3,r0,#4ldr r2,r3_CopyLoop:ldr r3,r0str r3,r1add r0,r0,#4add r1,r1,#4sub r2,r2,#4teq r2,#0beq _EndCopyb _CopyLoop_EndCopy:ldr r0,=TARGETmov pc,r0上回书说到flashloader把bootloader load到0x0AFE0100,然回跳了过去,其实0x0AFE0100 就是烧在flash 0x0C000100中的真正的bootloader:bootloader 有几个文件组成,先是START.s,也是唯一的一个汇编程序,其余的

38、都是C写成的,START.s主要初始化堆栈:_start:ldr r1,=StackInitldr sp,r1b m ain/此处我们跳到了C代码的main函数,当C代码执行完后,还要调用/下面的JumpToKernel0x跳到LINXU kernel运行.equ StackInitvalue, _end_data+0x1000 / 4K _end_data在连结脚本中指定StackInit:.long StackInitvalue.global JumpToKernelJumpToKernel:/ jump to the copy code (get the argum ents right

39、mov pc, r0.global JumpToKernel0x/ r0 = jump address/ r1-r4 = arguments to use (these get shiftedJumpToKernel0x:/ jump to the copy code (get the argum ents rightmov r8, r0mov r0, r1mov r1, r2mov r2, r3mov r3, r4mov pc, r8.section .data.boot.section .bss.boot下面让我们看看bootloader的c代码干了些什么。main函数比较长,让我们分段慢

40、慢看。int m ain(U32 *pSource, *pDestin, count;U8 countDown, bootOption;U32 delayCount;U32 fileSize, i;char c;char *pCm dLine;char *pMem;init(; /初始化FLASH控制器和CPU时钟EUARTinit(; /串口初始化EUARTputString(nnDBMX1 Linux Bootloader ver 0.2.0n;EUARTputString(Copyright (C 2002 Motorola Ltd.nn;EUARTputString(U8 *cmdLi

41、ne;EUARTputString(nn;EUARTputString(Press any key for alternate boot-up options . ;小弟的bootloader主要干这么几件事:init(; 初始化硬件,打印一些信息和提供一些操作选项:0. Program bootloader image1. Program kernel image2. Program root-disk image3. Download kernel and boot from RAM4. Download kernel and boot with ver 0.1.x bootloader

42、format5. Boot a ver0.1.x kernel6. Boot with a different command line也就是说,可以在bootloader里选择重新下载kernel,rootdisk并写入flash,下载的方法是用usb连接,10m的rootdisk也就刷的一下。关于usb下载的讨论请参看先前的贴子“为arm开发平台增加usb下载接口“。如果不选,直接回车,就开始把整个linux的内核拷贝到SDRAM中运行。列位看官,可能有人要问,在flashloader中不是已经初始化过sdram控制器了吗?怎么init(; 中还要初始化呢,各位有所不知,小弟用的是sync

43、flash,可以直接使用sdram控制器的接口,切记:在flash中运行的代码是不能初始化连接flash的sdram控制器的,不然绝对死掉了。所以,当程序在flash中运行的时候,去初始化sdram,而现在在sdram中运行,可放心大胆地初始化flash了,主要是设定字宽,行列延时,因为缺省都是最大的。另外,如果列位看官的cpu有足够的片内ram,完全可以先把bootloader放在片内ram,干完一切后再跳到LINUX,小弟着也是不得已而为之啊。如果直接输入回车,进入kernel拷贝工作:EUARTputString(Copying kernel from Flash to RAM .n;c

44、ount = 0x200000; / 2 MbytespSource = (U32 *0x0C100000;pDestin = (U32 *0x08008000;do*(pDestin+ = *(pSource+;count -= 4; while (count 0;EUARTputString(Booting kernel .nn;这一段没有什么可说的,运行完后kernel就在0x08008000了,至于为什么要空出0x8000的一段,主要是放kelnel的一些全局数据结构,如内核页表,arm的页目录要有16k大。我们知道,linux内核启动的时候可以传入参数,如在PC上,如果使用LILO,

45、当出现LILO:,我们可以输入root=/dev/hda1.或mem=128M等指定文件系统的设备或内存大小,在嵌入式系统上,参数的传入是要靠bootloader完成的,pMem = (char *0x083FF000; /参数字符串的目标存放地址pCmdLine = (char *&c m dLine; /定义的静态字符串while (*(pMem+=*(pCmdLine+ != 0;/拷贝JumpToKernel(void *0x8008000, 0x083FF000 ;/跳转到内核return (0;JumpToKernel在前文中的start.S定义过:JumpToKernel:/ j

46、ump to the copy code (get the argum ents rightmov pc, r0.global JumpToKernel0x/ r0 = jump address/ r1 = arguments to use (these get shifted由于arm-GCC的c参数调用的顺序是从左到右R0开始,所以R0是KERNKEL的地址,r1是参数字符串的地址:到此为止,为linux引导做的准备工作就结束了,下一回我们就正式进入linux的代码。好,从本节开始,我们走过了bootloader的漫长征途,开始进入linux的内核:说实话,linux宝典的确高深莫测,洋人

47、花了十几年修炼,各种内功心法层处不穷。有些地方反复推敲也领悟不了其中奥妙,炼不到第九重啊。linux的入口是一段汇编代码,用于基本的硬件设置和建立临时页表,对于ARM LINUX是linux/arch/arm/kernle/head-arm v.S, 走!#if defined(CONFIG_MX1mov r1, #MACH_TYPE_MX1#endif这第一句话好像就让人看不懂,好像葵花宝典开头的八个字:欲练神功。那来的MACH_TYPE_MX1?其实,在head-arm v.S中的一项重要工作就是设置内核的临时页表,不然mmu开起来也玩不转,但是内核怎么知道如何映射内存呢?linux的内核

48、将映射到虚地址0xCxxx xxxx处,但他怎么知道把哪一片ram 映射过去呢?因为不通的系统有不通的内存影像,所以,LINUX约定,内核代码开始的时候,R1放的是系统目标平台的代号,对于一些常见的,标准的平台,内核已经提供了支持,只要在编译的时候选中就行了,例如对X86平台,内核是从物理地址1M开始映射的。如果老兄是自己攒的平台,只好麻烦你自己写了。小弟拿人钱财,与人消灾,用的是摩托的MX1,只好自己写了,定义了#MACH_TYPE_MX1,当然,还要写一个描述平台的数据结构:MACHINE_START(MX1ADS, Motorola MX1ADSMAINTAINER(SPS Motoro

49、laBOOT_MEM(0x08000000, 0x00200000, 0xf0200000FIXUP(mx1ads_fixupMAPIO(mx1ads_map_ioINITIRQ(mx1ads_init_irqMACHINE_END看起来怪怪的,但现在大家只要知道他定义了基本的内存映象:RAM从0x08000000开始, i/o空间从0x00200000开始,i/o空间映射到虚拟地址空间0xf0200000开始处。摩托的芯片i/o和内存是统一编址的。其他的项,在下面的初始化过程中会逐个介绍到。好了好了,再看下面的指令:mov r0, #F_BIT | I_BIT | MODE_SVC m ak

50、e sure svc m ode /设置为SVC模式,允许中断和快速中断/此处设定系统的工作状态,arm有7种状态/每种状态有自己的堆栈msr cpsr_c, r0 and all irqs diabledbl _lookup_processor_type/定义处理器相关信息,如value, m ask, mmuflags,/放在段中/_lookup_processor_type 取得这些信息,在下面/_lookup_architecture_type 中用这一段是查询处理器的种类,大家知道arm有arm7, arm9等类型,如何区分呢?在arm协处理器中有一个只读寄存器,存

51、放处理器相关信息。_lookup_processor_type将返回如下的结构:_arm920_proc_info:.long 0x41009200 /CPU id.long 0xff00fff0 /cpu mask.long 0x00000c1e mmuflagsb _arm920_setup.long cpu_arch_name.long cpu_elf_name.long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT.long cpu_arm920_info.long arm920_processor_functions第一项是CPU id,将与协处理器中读出

52、的id作比较,其余的都是与处理器相关的信息,到下面初始化的过程中自然会用到。查询到了处理器类型和系统的内存映像后就要进入初始化过程中比较关键的一步了,开始设置mmu,但首先要设置一个临时的内核页表,映射4m的内存,这在初始化过程中是足够了:/r5=0800 0000 ram起始地址r6=0020 0000 io地址,r7=f020 0000 虚ioteq r7, #0 invalid architecture?moveq r0, #a yes, error abeq _errorbl _create_page_tables其中_create_page_tables为:_create_page_tables:pgtbl r4/r4=0800 4000 临时页表的起始地址/r5=0800 0000, ram的起始地址/r6=0020 0000, i/o寄存器空间的起始地址/r7=0000 3

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论