精华内容
下载资源
问答
  • SPL

    2016-08-05 14:56:25
    SPL SPL是uboot第一阶段执行的代码. 主要负责搬移uboot第二阶段的代码到内存中运行. SPL是由固化在芯片内部的ROM引导的. 我们知道很多芯片厂商固化的ROM支持从nandflash, SDCARD等外部介质启动. 所谓启动, 就是从...

    SPL

    SPL是uboot第一阶段执行的代码. 主要负责搬移uboot第二阶段的代码到内存中运行. SPL是由固化在芯片内部的ROM引导的. 我们知道很多芯片厂商固化的ROM支持从nandflash, SDCARD等外部介质启动. 所谓启动, 就是从这些外部介质中搬移一段固定大小(4K/8K/16K等)的代码到内部RAM中运行. 这里搬移的就是SPL. 在最新版本的uboot中, 可以看到SPL也支持nandflash, SDCARD等多种启动方式.  当SPL本身被搬移到内部RAM中运行时, 它会从nandflash, SDCARD等外部介质中搬移uboot第二阶段的代码到外部内存中.

    SPL的文件组成

    当我们在uboot下执行make命令的时候, 它最核心的功能是执行Makefile中的all目标编译出相应的文件. 我们来看看这个all目标
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. all:        $(ALL-y) $(SUBDIR_EXAMPLES)  
    all依赖于$(ALL-y) 和 $(SUBDIR_EXAMPLES), 这里我只关注ALL-y, 如下:
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. # Always append ALL so that arch config.mk's can add custom ones  
    2. ALL-y += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map  
    3.   
    4. ALL-$(CONFIG_NAND_U_BOOT) += $(obj)u-boot-nand.bin  
    5. ALL-$(CONFIG_ONENAND_U_BOOT) += $(obj)u-boot-onenand.bin  
    6. ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin  
    7. ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.img  
    8. ALL-$(CONFIG_TPL) += $(obj)tpl/u-boot-tpl.bin  
    9. ALL-$(CONFIG_OF_SEPARATE) += $(obj)u-boot.dtb $(obj)u-boot-dtb.bin  
    10. ifneq ($(CONFIG_SPL_TARGET),)  
    11. ALL-$(CONFIG_SPL) += $(obj)$(subst ",,$(CONFIG_SPL_TARGET))  
    12. endif  
    13.   
    14. # enable combined SPL/u-boot/dtb rules for tegra  
    15. ifneq ($(CONFIG_TEGRA),)  
    16. ifeq ($(CONFIG_OF_SEPARATE),y)  
    17. ALL-y += $(obj)u-boot-dtb-tegra.bin  
    18. else  
    19. ALL-y += $(obj)u-boot-nodtb-tegra.bin  
    20. endif  
    21. endif  
    因为本节是讨论SPL, 所以我们只关注其中的一句ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
    这句话表明
    • 必须定义CONFIG_SPL才能编译出spl的bin: 一般在"include/configs/${CONFIG_NAME}.h"中定义
    • SPL的bin依赖于u-boot-spl.bin
    接着往下看
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. $(obj)spl/u-boot-spl.bin:   $(SUBDIR_TOOLS) depend  
    2.         $(MAKE) -C spl all  
    这里可以发现, u-boot-spl.bin依赖于 $(SUBDIR_TOOLS) depend
    • $(SUBDIR_TOOLS) : 暂不分析
    • depend: 参考附录中的depend
    • 进入spl目录, 执行make all
    接下来进入spl目录, 看看它的Makefile : 这里只分析与SPL相关的部分
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. CONFIG_SPL_BUILD := y  
    2. export CONFIG_SPL_BUILD  
    • export CONFIG_SPL_BUILD: 在接下来的编译中, 这个变量为y. 从后面的分析中可以看到, uboot的stage1, stage2阶段的代码用的是同一个Start.S, 只不过在Start.S中用#ifdef CONFIG_SPL_BUILD这种条件编译来区分. 类似的还有其他一些文件.
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(SRCTREE)/board/$(VENDOR)/common/Makefile),y,n)  
      1. 如果board/$(VENDOR)/common目录中有Makefile文件,则HAVE_VENDOR_COMMON_LIB为y否则为n  
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ifdef   CONFIG_SPL_START_S_PATH  
    2. START_PATH := $(subst ",,$(CONFIG_SPL_START_S_PATH))  
    3. else  
    4. START_PATH := $(CPUDIR)  
    5. endif  
    • 我们这里没有定义CONFIG_SPL_START_S_PATH, 所以START_PATH := $(CPUDIR)
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. START := $(START_PATH)/start.o  
    • 依赖start.o, 综合来看, 就是要把CPUDIR下的start.S编译进来.
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-y += arch/$(ARCH)/lib/lib$(ARCH).o  
    • 依赖lib$(ARCH).o, 具体来看, 就是依赖arch/arm/lib/libarm.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-y += $(CPUDIR)/lib$(CPU).o  
    • 依赖lib$(CPU).o, 具体来看, 就是依赖arch/arm/cpu/armv7/libarmv7.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ifdef SOC  
    2. LIBS-y += $(CPUDIR)/$(SOC)/lib$(SOC).o  
    3. endif  
    • 如果定义了SOC, 则依赖lib$(SOC).o, 具体来看, 就是依赖arch/arm/cpu/s5pc1xx/libs5pc1xx.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-y += board/$(BOARDDIR)/lib$(BOARD).o  
    • 依赖lib$(BOARD).o, 具体来看, 就是依赖board/samsung/tiny210/libtiny210.o
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. LIBS-$(HAVE_VENDOR_COMMON_LIB) += board/$(VENDOR)/common/lib$(VENDOR).o  
    • 如果HAVE_VENDOR_COMMON_LIB为y, 则依赖lib$(VENDOR).o, 具体来看, 就是依赖board/samsung/common/libsamsung.o
    [plain] view plaincopy
    1. LIBS-$(CONFIG_SPL_FRAMEWORK) += common/spl/libspl.o  
    2. LIBS-$(CONFIG_SPL_LIBCOMMON_SUPPORT) += common/libcommon.o  
    3. LIBS-$(CONFIG_SPL_LIBDISK_SUPPORT) += disk/libdisk.o  
    4. LIBS-$(CONFIG_SPL_I2C_SUPPORT) += drivers/i2c/libi2c.o  
    5. LIBS-$(CONFIG_SPL_GPIO_SUPPORT) += drivers/gpio/libgpio.o  
    6. LIBS-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/libmmc.o  
    7. LIBS-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/libserial.o  
    8. LIBS-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/libspi_flash.o  
    9. LIBS-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/libspi.o  
    10. LIBS-$(CONFIG_SPL_FAT_SUPPORT) += fs/fat/libfat.o  
    11. LIBS-$(CONFIG_SPL_LIBGENERIC_SUPPORT) += lib/libgeneric.o  
    12. LIBS-$(CONFIG_SPL_POWER_SUPPORT) += drivers/power/libpower.o \  
    13.     drivers/power/pmic/libpmic.o  
    14. LIBS-$(CONFIG_SPL_NAND_SUPPORT) += drivers/mtd/nand/libnand.o  
    15. LIBS-$(CONFIG_SPL_ONENAND_SUPPORT) += drivers/mtd/onenand/libonenand.o  
    16. LIBS-$(CONFIG_SPL_DMA_SUPPORT) += drivers/dma/libdma.o  
    17. LIBS-$(CONFIG_SPL_POST_MEM_SUPPORT) += post/drivers/memory.o  
    18. LIBS-$(CONFIG_SPL_NET_SUPPORT) += net/libnet.o  
    19. LIBS-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/libnet.o  
    20. LIBS-$(CONFIG_SPL_ETH_SUPPORT) += drivers/net/phy/libphy.o  
    21. LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/net/phy/libphy.o  
    22. LIBS-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o  
    23. LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o  
    24. LIBS-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/libwatchdog.o  
    • 根据具体配置, 选择相应的依赖关系
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ifeq ($(SOC),exynos)  
    2. LIBS-y += $(CPUDIR)/s5p-common/libs5p-common.o  
    3. endif  
    • 如果SOC为exynos, 则依赖libs5p-common.o, 我们这里的SOC为s5pc1xx, 所以不依赖
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. START := $(addprefix $(SPLTREE)/,$(START))  
    2. LIBS := $(addprefix $(SPLTREE)/,$(sort $(LIBS-y)))  
    • 给START和LIBS加上前缀, $(SPLTREE), 具体来看, 就是编译过程中生成的.o文件都会放到spl/目录下面
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. # Linker Script  
    2. ifdef CONFIG_SPL_LDSCRIPT  
    3. # need to strip off double quotes  
    4. LDSCRIPT := $(addprefix $(SRCTREE)/,$(subst ",,$(CONFIG_SPL_LDSCRIPT)))  
    5. endif  
    6.   
    7. ifeq ($(wildcard $(LDSCRIPT)),)  
    8.     LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds  
    9. endif  
    10. ifeq ($(wildcard $(LDSCRIPT)),)  
    11.     LDSCRIPT := $(TOPDIR)/$(CPUDIR)/u-boot-spl.lds  
    12. endif  
    13. ifeq ($(wildcard $(LDSCRIPT)),)  
    14.     LDSCRIPT := $(TOPDIR)/arch/$(ARCH)/cpu/u-boot-spl.lds  
    15. endif  
    16. ifeq ($(wildcard $(LDSCRIPT)),)  
    17. $(error could not find linker script)  
    18. endif  
    • 找到spl的链接配置文件, 具体来看, 用的是arch/arm/cpu下的u-boot-spl.lds
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ALL-y   += $(obj)$(SPL_BIN).bin  
    2.   
    3. ifdef CONFIG_SAMSUNG  
    4. ALL-y   += $(obj)$(BOARD)-spl.bin  
    5. endif  
    6.   
    7. all:    $(ALL-y)  
    8.   
    9. ifdef CONFIG_SAMSUNG  
    10. $(obj)$(BOARD)-spl.bin: $(obj)u-boot-spl.bin  
    11.     $(OBJTREE)/tools/mk$(BOARD)spl \  
    12.         $(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin  
    13. endif  
    14.   
    15. $(obj)$(SPL_BIN).bin:   $(obj)$(SPL_BIN)  
    16.     $(OBJCOPY) $(OBJCFLAGS) -O binary $< $@  
    17.   
    18. GEN_UBOOT = \  
    19.     cd $(obj) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $(__START) \  
    20.         --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \  
    21.         -Map $(SPL_BIN).map -o $(SPL_BIN)  
    22.   
    23. $(obj)$(SPL_BIN):   depend $(START) $(LIBS) $(obj)u-boot-spl.lds  
    24.     $(GEN_UBOOT)  
    25.   
    26. $(START):   depend  
    27.     $(MAKE) -C $(SRCTREE)/$(START_PATH) $@  
    28.   
    29. $(LIBS):    depend  
    30.     $(MAKE) -C $(SRCTREE)$(dir $(subst $(SPLTREE),,$@))  
    31.   
    32. $(obj)u-boot-spl.lds: $(LDSCRIPT) depend  
    33.     $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -I$(obj). -ansi -D__ASSEMBLY__ -P - < $< > $@  
    34.   
    35. depend: $(obj).depend  
    36. .PHONY: depend  
    • all: $(ALL-y), 还记得本篇上面说的, 进入到spl目录下之后干啥事吗? 没错, 执行make all, 其实执行的就是这里的all目标. 它依赖$(ALL-y). 具体的依赖关系就不赘述了, 顺藤摸瓜即可
    • ifdef CONFIG_SAMSUNG: 这个是针对Samsung平台的特殊之处. 
      • 利用tools/mk$(BOARD)spl这个工具, 将u-boot-spl.bin转为$(BOARD)-spl.bin
        • 转换的本质, 就是在u-boot-spl.bin前面加入head info.关于head info是什么, 可以参考文档S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf. 顺便可以理解一下samsung芯片的启动流程
      • tools/mk$(BOARD)spl这个工具是在tools/Makefile里面生成的.
    OK, 分析结束, 接下来, 就基于我们上面的分析开始分析代码了.

    SPL代码分析

    u-boot-spl.lds: 它的位置在上文中我们分析了
    • 根据u-boot-spl.lds中的规则, 我们知道CPUDIR/start.o被放在了最前面. 它所对应的文件就是arch/arm/cpu/armv7/start.S

    start.S

    下面我们看看start.S
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. .globl _start  
    2. _start: b   reset  
    3.     ldr pc, _undefined_instruction  
    4.     ldr pc, _software_interrupt  
    5.     ldr pc, _prefetch_abort  
    6.     ldr pc, _data_abort  
    7.     ldr pc, _not_used  
    8.     ldr pc, _irq  
    9.     ldr pc, _fiq  
    • _start是我们在lds里面指定的ENTRY(_start)
    • 首先会跳转到reset处
    • ldr  pc, _xxx定义的是中断向量表
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_SPL_BUILD  
    2. _undefined_instruction: .word _undefined_instruction  
    3. _software_interrupt:    .word _software_interrupt  
    4. _prefetch_abort:    .word _prefetch_abort  
    5. _data_abort:        .word _data_abort  
    6. _not_used:      .word _not_used  
    7. _irq:           .word _irq  
    8. _fiq:           .word _fiq  
    9. _pad:           .word 0x12345678 /* now 16*4=64 */  
    10. #else  
    11. _undefined_instruction: .word undefined_instruction  
    12. _software_interrupt:    .word software_interrupt  
    13. _prefetch_abort:    .word prefetch_abort  
    14. _data_abort:        .word data_abort  
    15. _not_used:      .word not_used  
    16. _irq:           .word irq  
    17. _fiq:           .word fiq  
    18. _pad:           .word 0x12345678 /* now 16*4=64 */  
    19. #endif  /* CONFIG_SPL_BUILD */  
    • 当CONFIG了SPL_BUILD之后, 一旦发生异常中断, 就会进入死循环. 所以我们的SPL里面不允许出发异常中断
    • 不过正常的uboot(即stage2阶段)还是可以处理异常中断的.

    reset

    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. /*  
    2.  * the actual reset code  
    3.  */  
    4.   
    5. reset:  
    6.     bl  save_boot_params  
    7.     /*  
    8.      * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,  
    9.      * except if in HYP mode already  
    10.      */  
    11.     mrs r0, cpsr  
    12.     and r1, r0, #0x1f       @ mask mode bits  
    13.     teq r1, #0x1a       @ test for HYP mode  
    14.     bicne   r0, r0, #0x1f       @ clear all mode bits  
    15.     orrne   r0, r0, #0x13       @ set SVC mode  
    16.     orr r0, r0, #0xc0       @ disable FIQ and IRQ  
    17.     msr cpsr,r0  
    18.   
    19.         /* ........ */  
    20.     /* the mask ROM code should have PLL and others stable */  
    21. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
    22.     bl  cpu_init_cp15  
    23.     bl  cpu_init_crit  
    24. #endif  
    25.   
    26.     bl  _main  
    当初次上电或者复位时, Uboot最新运行的就是这里的代码
    • bl save_boot_params: 如果没有重新定义save_boot_params,则使用<arch/arm/cpu/armv7/start.S>中的save_boot_params。其不做任何事情,直接返回
    • 禁止FIQ, IRQ; 设置CPU工作在SVC32模式
    • bl cpu_init_cp15: (I/D-Cache, MMU, TLBs),具体见下面代码中注释
    • bl    cpu_init_crit    :  主要是设置CPU的PLL, GPIO管脚复用, memory等. 具体见下面
    • bl    _main              :  跳转到<arch/arm/lib/crt0.S>中的_main. 具体见下面

    cpu_init_cp15

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. /*************************************************************************  
    2.  *  
    3.  * cpu_init_cp15  
    4.  *  
    5.  * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless  
    6.  * CONFIG_SYS_ICACHE_OFF is defined.  
    7.  *  
    8.  *************************************************************************/  
    9. ENTRY(cpu_init_cp15)  
    10.     /*  
    11.      * Invalidate L1 I/D  
    12.      */  
    13.     mov r0, #0          @ set up for MCR  
    14.     mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs  
    15.     mcr p15, 0, r0, c7, c5, 0   @ invalidate icache  
    16.     mcr p15, 0, r0, c7, c5, 6   @ invalidate BP array  
    17.     mcr     p15, 0, r0, c7, c10, 4  @ DSB  
    18.     mcr     p15, 0, r0, c7, c5, 4   @ ISB  
    19.   
    20.     /*  
    21.      * disable MMU stuff and caches  
    22.      */  
    23.     mrc p15, 0, r0, c1, c0, 0  
    24.     bic r0, r0, #0x00002000 @ clear bits 13 (--V-)  
    25.     bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)  
    26.     orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align  
    27.     orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB  
    28. #ifdef CONFIG_SYS_ICACHE_OFF  
    29.     bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache  
    30. #else  
    31.     orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache  
    32. #endif  
    33.     mcr p15, 0, r0, c1, c0, 0  
    34.   
    35. #ifdef CONFIG_ARM_ERRATA_716044  
    36.     mrc p15, 0, r0, c1, c0, 0   @ read system control register  
    37.     orr r0, r0, #1 << 11  @ set bit #11  
    38.     mcr p15, 0, r0, c1, c0, 0   @ write system control register  
    39. #endif  
    40.   
    41. #ifdef CONFIG_ARM_ERRATA_742230  
    42.     mrc p15, 0, r0, c15, c0, 1  @ read diagnostic register  
    43.     orr r0, r0, #1 << 4       @ set bit #4  
    44.     mcr p15, 0, r0, c15, c0, 1  @ write diagnostic register  
    45. #endif  
    46.   
    47. #ifdef CONFIG_ARM_ERRATA_743622  
    48.     mrc p15, 0, r0, c15, c0, 1  @ read diagnostic register  
    49.     orr r0, r0, #1 << 6       @ set bit #6  
    50.     mcr p15, 0, r0, c15, c0, 1  @ write diagnostic register  
    51. #endif  
    52.   
    53. #ifdef CONFIG_ARM_ERRATA_751472  
    54.     mrc p15, 0, r0, c15, c0, 1  @ read diagnostic register  
    55.     orr r0, r0, #1 << 11  @ set bit #11  
    56.     mcr p15, 0, r0, c15, c0, 1  @ write diagnostic register  
    57. #endif  
    58.   
    59.     mov pc, lr          @ back to my caller  
    60. ENDPROC(cpu_init_cp15)  

    cpu_init_crit

    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
    2. /*************************************************************************  
    3.  *  
    4.  * CPU_init_critical registers  
    5.  *  
    6.  * setup important registers  
    7.  * setup memory timing  
    8.  *  
    9.  *************************************************************************/  
    10. ENTRY(cpu_init_crit)  
    11.     /*  
    12.      * Jump to board specific initialization...  
    13.      * The Mask ROM will have already initialized  
    14.      * basic memory. Go here to bump up clock rate and handle  
    15.      * wake up conditions.  
    16.      */  
    17.     b   lowlevel_init       @ go setup pll,mux,memory  
    18. ENDPROC(cpu_init_crit)  
    19. #endif  
    • b lowlevel_init : 跳转到<arch/arm/cpu/armv7/lowlevel_init.S>中的lowlevel_init

    lowlevel_init.S

    lowlevel_init

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #include <asm-offsets.h>  
    2. #include <config.h>  
    3. #include <linux/linkage.h>  
    4.   
    5. ENTRY(lowlevel_init)  
    6.     /*  
    7.      * Setup a temporary stack  
    8.      */  
    9.     ldr sp, =CONFIG_SYS_INIT_SP_ADDR  
    10.     bic sp, sp, #7 /* 8-byte alignment for ABI compliance */  
    11. #ifdef CONFIG_SPL_BUILD  
    12.     ldr r9, =gdata  
    13. #else  
    14.     sub sp, #GD_SIZE  
    15.     bic sp, sp, #7  
    16.     mov r9, sp  
    17. #endif  
    18.     /*  
    19.      * Save the old lr(passed in ip) and the current lr to stack  
    20.      */  
    21.     push    {ip, lr}  
    22.   
    23.     /*  
    24.      * go setup pll, mux, memory  
    25.      */  
    26.     bl  s_init  
    27.     pop {ip, pc}  
    以前老版本的uboot, lowlevel_init一般都是在board/xxx下面的板级文件夹下面实现的. 现在直接放到CPUDIR下面了, 那它做了什么事情呢
    • 对stack pointer赋值成CONFIG_SYS_INIT_SP_ADDR
    • 确保sp是8字节对齐
    • 将gdata的地址存入到r9寄存器中
    • 跳转到 s_init: 这个s_init就需要芯片厂商或者我们自己在板级文件里面实现了. 它主要做的事情
      • setup pll, mux, memory
    我个人感觉, 新版本的uboot在CPUDIR下实现了一个lowlevel_init.S文件, 主要目标是初始化sp, 这样s_init就可以用C语言实现了. 而以前的老版本里面, s_init里面要做的事情都是用汇编做的.

    crt0.S

    _main

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. ENTRY(_main)  
    2.   
    3. /*  
    4.  * Set up initial C runtime environment and call board_init_f(0).  
    5.  */  
    6.   
    7. #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)  
    8.     ldr sp, =(CONFIG_SPL_STACK)  
    9. #else  
    10.     ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)  
    11. #endif  
    12.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
    13.     sub sp, #GD_SIZE    /* allocate one GD above SP */  
    14.     bic sp, sp, #7  /* 8-byte alignment for ABI compliance */  
    15.     mov r9, sp      /* GD is above SP */  
    16.     mov r0, #0  
    17.     bl  board_init_f  
    • 重新对SP赋值, 确认sp是8字对齐
    • 在栈顶保留一个global_data的大小, 这个global_data是uboot里面的一个全局数据, 很多地方都会用到. 俗称 gd_t
    • 确认更新后的sp是8字对齐
    • r9指向global_data, 后面别的地方想用global_data时候, 可以直接从r9里面获取地址.
    • r0赋值0
    • bl board_init_f: 跳转到board_init_f. 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在<arch/arm/lib/spl.c>. 

    arch/arm/lib/spl.c

    board_init_f

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. /*  
    2.  * In the context of SPL, board_init_f must ensure that any clocks/etc for  
    3.  * DDR are enabled, ensure that the stack pointer is valid, clear the BSS  
    4.  * and call board_init_f.  We provide this version by default but mark it  
    5.  * as __weak to allow for platforms to do this in their own way if needed.  
    6.  */  
    7. void __weak board_init_f(ulong dummy)  
    8. {  
    9.     /* Clear the BSS. */  
    10.     memset(__bss_start, 0, __bss_end - __bss_start);  
    11.   
    12.     /* Set global data pointer. */  
    13.     gd = &gdata;  
    14.   
    15.     board_init_r(NULL, 0);  
    16. }  
    • __weak: 表明该函数可以被重新定义
    • 对BSS段进行清零操作
    • gd = &gdata;
      • gd的定义在DECLARE_GLOBAL_DATA_PTR <arch/arm/include/asm/global_data.h>
        • #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r9")
          • 还记得r9这个寄存器吗, 在上面初始化过了
      • gdata的定义在本文件中: gd_t gdata __attribute__ ((section(".data")));  
        • 它是一个 gd_t 也就是global_data类型的变量
        • __attribute__表示这个变量会被放到".data"这个输入段中. 连接器会把输入段按照链接脚本(u-boot-spl.lds)里面指定的规则存放到输出段.
      • 为什么会有这个赋值操作, 不太明白...
    • board_init_r : 在编译SPL时, 分析Makefile可以看出, 该函数的实现是在<common/spl/spl.c>

    common/spl/spl.c

    board_init_r

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_SYS_SPL_MALLOC_START  
    2.     mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,  
    3.             CONFIG_SYS_SPL_MALLOC_SIZE);  
    4. #endif  
    • 如果定义了:CONFIG_SYS_SPL_MALLOC_START, 则进行memory的malloc池初始化. 以后调用malloc就在这个池子里面分配内存
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1. #ifndef CONFIG_PPC  
    2.     /*  
    3.      * timer_init() does not exist on PPC systems. The timer is initialized  
    4.      * and enabled (decrementer) in interrupt_init() here.  
    5.      */  
    6.     timer_init();  
    7. #endif  
    • 如果没有定义:CONFIG_PPC, 则进行timer的初始化. <arch/arm/cpu/armv7/s5p-common/timer.c>里面定义
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. #ifdef CONFIG_SPL_BOARD_INIT  
    2.     spl_board_init();  
    3. #endif  
    • SPL阶段, 如果还需要做什么初始化动作, 可以放在这里. 具体的实现可以在BOARDDIR下面.
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. boot_device = spl_boot_device();  
    2.     debug("boot device - %d\n", boot_device);  
    • 必须实现spl_boot_device, 返回是从哪个外部设备启动的(NAND/SDCARD/NOR...). 可以厂商或者自己在BOARDDIR下面实现
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
    1.     switch (boot_device) {  
    2. #ifdef CONFIG_SPL_RAM_DEVICE  
    3.     case BOOT_DEVICE_RAM:  
    4.         spl_ram_load_image();  
    5.         break;  
    6. #endif  
    7. #ifdef CONFIG_SPL_MMC_SUPPORT  
    8.     case BOOT_DEVICE_MMC1:  
    9.     case BOOT_DEVICE_MMC2:  
    10.     case BOOT_DEVICE_MMC2_2:  
    11.         spl_mmc_load_image();  
    12.         break;  
    13. #endif  
    14. #ifdef CONFIG_SPL_NAND_SUPPORT  
    15.     case BOOT_DEVICE_NAND:  
    16.         spl_nand_load_image();  
    17.         break;  
    18. #endif  
    19. #ifdef CONFIG_SPL_ONENAND_SUPPORT  
    20.     case BOOT_DEVICE_ONENAND:  
    21.         spl_onenand_load_image();  
    22.         break;  
    23. #endif  
    24. #ifdef CONFIG_SPL_NOR_SUPPORT  
    25.     case BOOT_DEVICE_NOR:  
    26.         spl_nor_load_image();  
    27.         break;  
    28. #endif  
    29. #ifdef CONFIG_SPL_YMODEM_SUPPORT  
    30.     case BOOT_DEVICE_UART:  
    31.         spl_ymodem_load_image();  
    32.         break;  
    33. #endif  
    34. #ifdef CONFIG_SPL_SPI_SUPPORT  
    35.     case BOOT_DEVICE_SPI:  
    36.         spl_spi_load_image();  
    37.         break;  
    38. #endif  
    39. #ifdef CONFIG_SPL_ETH_SUPPORT  
    40.     case BOOT_DEVICE_CPGMAC:  
    41. #ifdef CONFIG_SPL_ETH_DEVICE  
    42.         spl_net_load_image(CONFIG_SPL_ETH_DEVICE);  
    43. #else  
    44.         spl_net_load_image(NULL);  
    45. #endif  
    46.         break;  
    47. #endif  
    48. #ifdef CONFIG_SPL_USBETH_SUPPORT  
    49.     case BOOT_DEVICE_USBETH:  
    50.         spl_net_load_image("usb_ether");  
    51.         break;  
    52. #endif  
    53.     default:  
    54.         debug("SPL: Un-supported Boot Device\n");  
    55.         hang();  
    56.     }  
    • 将image从具体的外部设备中load到ram中. 这里暂时先不分析具体的load过程.
    [plain] view plain copy
     在CODE上查看代码片派生到我的代码片
    1.     switch (spl_image.os) {  
    2.     case IH_OS_U_BOOT:  
    3.         debug("Jumping to U-Boot\n");  
    4.         break;  
    5. #ifdef CONFIG_SPL_OS_BOOT  
    6.     case IH_OS_LINUX:  
    7.         debug("Jumping to Linux\n");  
    8.         spl_board_prepare_for_linux();  
    9.         jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);  
    10. #endif  
    11.     default:  
    12.         debug("Unsupported OS image.. Jumping nevertheless..\n");  
    13.     }  
    14.     jump_to_image_no_args(&spl_image);  
    • 判断image的类型
      • 如果是u-boot,则直接break, 去运行u-boot
      • 如果是Linux,则启动Linux
    至此,SPL结束它的生命,控制权交于u-boot或Linux

    在接下来的一篇中, 我们会分析当控制权交给u-boot之后, uboot的运行流程

    总结

    SPL移植注意点

    • s_init: C语言实现此函数, 必须的. 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面. 如果厂商没有提供, 我们可以在BOARDDIR下面实现. 主要完成以下功能
      • 设置CPU的PLL, GPIO管脚复用, memory等
    • spl_board_init: C语言实现, 可选的.  如果是厂商提供的, 一般在arch/arm/cpu/xxx下面. 如果厂商没有提供, 我们可以在BOARDDIR下面实现. 主要完成的功能自己决定
    • spl_boot_device: C语言实现, 必须的. 如果是厂商提供的, 一般在arch/arm/cpu/xxx下面. 如果厂商没有提供, 我们可以在BOARDDIR下面实现. 主要完成的功能,返回是从什么设备启动的(NAND/SDCARD/Nor ...). 像Atmel, Samsung的芯片, 都是有办法做这个事情的.
    展开全文
  • SPL data

    2020-12-27 02:18:59
    launching the SPL pipeline (or any other pipeline depending on SPL data) I get the following error: <pre><code> Running: aws --profile=default s3 sync s3://openfda-data-spl/data/ ./data/spl/s3_...
  • spl
  • SPL3-源码

    2021-03-31 00:17:38
    SPL3
  • Building spl

    2020-12-08 20:48:22
    <p>spl: version magic '2.6.18-194.17.1.el5 SMP mod_unload gcc-4.4' should be '2.6.18-194.17.1.el5 SMP mod_unload gcc-4.1'</p><p>该提问来源于开源项目:openzfs/spl</p></div>
  • 什么是spl autoload?spl autolaod机制是什么?SPL autoload机制的实现是通过将函数指针autoload_func指向自己实现的具有自动装载功能的函数来实现的...php SPL(Standard PHP Library) 主要用到的数据结构有:双向...

    9c98fe03383ffeca78ca12f3181f2137.png

    ...写PHP的autoLoad自动加载机制,但是目前的框架中用的却是SPL autoload机制。

    什么是spl autoload?spl autolaod机制是什么?

    SPL autoload机制的实现是通过将函数指针autoload_func指向自己实现的具有自动装载功能的函数来实现的...

    php SPL(Standard PHP Library) 主要用到的数据结构有:双向链表(SplDoublyLinkedLis),栈(SplStack),队列(SplQueue),堆(SplHeap),大根堆(SplMaxHeap),小根堆(SplMinHeap), 优先级队列(SplPriorityQueue),固定数组(SplFixedArray),对象存储(SplStorageObject)。

    SplDoublyLinkedList

    数据结构:(c代码参考PHP7.0.0)

    typedef struct _spl_ptr_llist_element {

    struct _spl_ptr_llist_element *prev;

    struct _spl_ptr_llist_element *next;

    int rc; // 引用次数

    void *data; // 数据类型

    } spl_ptr_llist_element;

    typedef struct _spl_ptr_llist {

    spl_ptr_llist_element *head;

    spl_ptr_llist_element *tail;

    spl_ptr_llist_dtor_func dtor; // 删除元素 引用-1

    spl_ptr_llist_ctor_func ctor; // 创建元素 引用+1

    int count; // 元素个数

    } spl_ptr_llist;

    struct _spl_dllist_object {

    zend_object std;

    spl_ptr_llist *llist;

    int traverse_position;

    spl_ptr_llist_element *traverse_pointer;

    zval *retval;

    int flags;

    zend_function *fptr_offset_get;

    zend_function *fptr_offset_set;

    zend_function *fptr_offset_has;

    zend_function *fptr_offset_del;

    zend_function *fptr_count;

    zend_class_entry *ce_get_iterator;

    HashTable *debug_info;

    };双向链表

    SplDoublyLinkedList implements Iterator , ArrayAccess , Countable {

    /* 方法 */

    public __construct ( void )

    public void add ( mixed $index , mixed $newval )

    public mixed bottom ( void )

    public int count ( void )

    public mixed current ( void )

    public int getIteratorMode ( void )

    public bool isEmpty ( void )

    public mixed key ( void )

    public void next ( void )

    public bool offsetExists ( mixed $index )

    public mixed offsetGet ( mixed $index )

    public void offsetSet ( mixed $index , mixed $newval )

    public void offsetUnset ( mixed $index )

    public mixed pop ( void )

    public void prev ( void )

    public void push ( mixed $value )

    public void rewind ( void )

    public string serialize ( void )

    public void setIteratorMode ( int $mode )

    public mixed shift ( void ) // 删除第一个元素

    public mixed top ( void )

    public void unserialize ( string $serialized )

    public void unshift ( mixed $value ) //将value插入的第一个元素,原来的第一个元素不删除

    public bool valid ( void )

    }

    需要注意的是:

    add 是5.5+版本添加的函数,其它都是5.3+

    从数据结构中可以看出,虽然许多函数中都包含有直接索引第index 个元素,如果不在范围则抛出OutOfRangeException异常,实际实现时时间复杂度为O(n)。

    具体函数详细可参考php官方手册

    以上就介绍了PHP SPL 数据结构笔记摘要,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

    ...写PHP的autoLoad自动加载机制,但是目前的框架中用的却是SPL autoload机制。

    什么是spl autoload?spl autolaod机制是什么?

    SPL autoload机制的实现是通过将函数指针autoload_func指向自己实现的具有自动装载功能的函数来实现的...

    PHP SPL标准库中提供了一些函数用来处理如自动加载、迭代器处理等。

    spl_autoload_extensions()添加spl_autoload()可加载的文件扩展名

    spl_autoload_register()注册函数到SPL __autoload函数栈中。

    代码如下:

    /*test1.

    php中spl_autoload详解,spl_autoload详解

    SPL有两个不同的函数 spl_autoload, spl_autoload_call,通过将autoload_func指向这两个不同的函数地址来实现不同的自动加载机制。

    spl_autoload 是SPL实现的默认的自动加载函数,

    spl_autoload_register(PHP 5 >= 5.1.2)spl_autoload_register — 注册__autoload()函数说明bool spl_autoload_register ([ callback $autoload_function ] )将函数注册到SPL

    在学习php的autoload的机制的时候,发现目前都使用了spl_autoload_register()函数来实现自动加载类,但在查阅资料的过程中,发现了spl_autload()这个函数,在php官方手册中,对该函数的解释是:

    __autoload()函数的...

    展开全文
  • 主要介绍了PHP SPL应用,结合实例形式分析了SPL非常重要却又不为人所熟知的功能与相关操作技巧,需要的朋友可以参考下
  • SPL fixes

    2020-12-02 08:10:26
    <div><ol><li>Restore CALLOUT_FLAG_ABSOLUTE in cv_timedwait_hires</li><li>Fix splat-condvar on Linux 4.7</li><li>Fix race in taskq_destroy and dynamic spawing</li></ol>该提问来源于...openzfs/spl</p></div>
  • PHP SPL

    2020-03-15 22:25:45
    SPL是用于解决典型问题(standard problems)的一组接口与类的集合。 数据结构 SplDoublyLinkedList SplStack SplQueue SplHeap SplMaxHeap SplMinHeap SplPriorityQueue SplFixedArray SplObjectStorage ...

    简介

    SPL是用于解决典型问题(standard problems)的一组接口与类的集合。

    数据结构

    SPL 提供了一套标准的数据结构。它们按底层实现进行分组, 通常定义了它们的一般应用领域。

    双向链表

    双链表 (DLL) 是一个链接到两个方向的节点列表。当底层结构是 DLL 时, 迭代器的操作、对两端的访问、节点的添加或删除都具有 O (1) 的开销。因此, 它为栈和队列提供了一个合适的实现。

    堆是遵循堆属性的树状结构: 每个节点都大于或等于其子级, 使用对堆全局的已实现的比较方法进行比较。

    数组

    数组是以连续方式存储数据的结构, 可通过索引进行访问。不要将它们与 php 数组混淆: php 数组实际上是按照有序的列表实现的。

    映射

    映射是一个数据拥有键值对。PHP 数组可以被看作是从整数/字符串到值的映射。SPL 提供了从对象到数据的映射。此映射也可用作对象集。

    展开全文
  • 初始SPL

    2017-11-29 15:48:40
     SPL是用于解决典型问题(standard problems)的一组接口与类的集合.  SPL,PHP 标准库(Standard PHP Library) ,从 PHP 5.0 起内置的组件和接口,且从 PHP5.3 已逐渐的成熟。SPL 在所有的 PHP5 开发环境中被内置...

    PHP SPL(PHP 标准库)

      一.什么是SPL?

        SPL是用于解决典型问题(standard problems)的一组接口与类的集合.

        SPL,PHP 标准库(Standard PHP Library) ,从 PHP 5.0 起内置的组件和接口,且从 PHP5.3 已逐渐的成熟。SPL 在所有的 PHP5 开发环境中被内置,同时无需任何设置。

      二.如何使用?

        SPL提供了一组标准数据结构:

        双向链表

        双链表是一种重要的线性存储结构,对于双链表中的每个节点,不仅仅存储自己的信息,还要保存前驱和后继节点的地址。

        PHP SPL中的SplDoublyLinkedList类提供了对双链表的操作。

        SplDoublyLinkedList类摘要如下:

    复制代码
     1 SplDoublyLinkedList implements Iterator  , ArrayAccess  , Countable  {
     2   
     3   public __construct ( void )
     4   public void add ( mixed $index , mixed $newval )
     5   //双链表的头部节点
     6   public mixed top ( void )
     7   //双链表的尾部节点
     8   public mixed bottom ( void )
     9   //双联表元素的个数
    10   public int count ( void )
    11   //检测双链表是否为空
    12   public bool isEmpty ( void )
    13   
    14   
    15   //当前节点索引
    16   public mixed key ( void )
    17   //移到上条记录
    18   public void prev ( void )
    19   //移到下条记录
    20   public void next ( void )
    21   //当前记录
    22   public mixed current ( void )
    23   //将指针指向迭代开始处
    24   public void rewind ( void )
    25   //检查双链表是否还有节点
    26   public bool valid ( void )
    27   
    28   //指定index处节点是否存在
    29   public bool offsetExists ( mixed $index )
    30   //获取指定index处节点值
    31   public mixed offsetGet ( mixed $index )
    32   //设置指定index处值
    33   public void offsetSet ( mixed $index , mixed $newval )
    34   //删除指定index处节点
    35   public void offsetUnset ( mixed $index )
    36   
    37   //从双链表的尾部弹出元素
    38   public mixed pop ( void )
    39   //添加元素到双链表的尾部
    40   public void push ( mixed $value )
    41   
    42   //序列化存储
    43   public string serialize ( void )
    44   //反序列化
    45   public void unserialize ( string $serialized )
    46   
    47   //设置迭代模式
    48   public void setIteratorMode ( int $mode )
    49   //获取迭代模式SplDoublyLinkedList::IT_MODE_LIFO (Stack style) SplDoublyLinkedList::IT_MODE_FIFO (Queue style)
    50   public int getIteratorMode ( void )
    51   
    52   //双链表的头部移除元素
    53   public mixed shift ( void )
    54   //双链表的头部添加元素
    55   public void unshift ( mixed $value )
    56   
    57 }
    复制代码

         

        使用起来也比较简单

    复制代码
     1 $list = new SplDoublyLinkedList();
     2 $list->push('a');
     3 $list->push('b');
     4 $list->push('c');
     5 $list->push('d');
     6 
     7 $list->unshift('top');
     8 $list->shift();
     9 
    10 $list->rewind();//rewind操作用于把节点指针指向Bottom所在的节点
    11 echo 'curren node:'.$list->current()."<br />";//获取当前节点
    12 
    13 $list->next();//指针指向下一个节点
    14 echo 'next node:'.$list->current()."<br />";
    15 
    16 $list->next();
    17 $list->next();
    18 $list->prev();//指针指向上一个节点
    19 echo 'next node:'.$list->current()."<br />";
    20 
    21 if($list->current())
    22     echo 'current node is valid<br />';
    23 else
    24     echo 'current node is invalid<br />';
    25 
    26 
    27 if($list->valid())//如果当前节点是有效节点,valid返回true
    28     echo "valid list<br />";
    29 else
    30     echo "invalid list <br />";
    31 
    32 
    33 var_dump(array(
    34     'pop' => $list->pop(),
    35     'count' => $list->count(),
    36     'isEmpty' => $list->isEmpty(),
    37     'bottom' => $list->bottom(),
    38     'top' => $list->top()
    39 ));
    40 
    41 $list->setIteratorMode(SplDoublyLinkedList::IT_MODE_FIFO);
    42 var_dump($list->getIteratorMode());
    43 
    44 for($list->rewind(); $list->valid(); $list->next()) {
    45     echo $list->current().PHP_EOL;
    46 }
    47 
    48 var_dump($a = $list->serialize());
    49 //print_r($list->unserialize($a));
    50 
    51 $list->offsetSet(0,'new one');
    52 $list->offsetUnset(0);
    53 var_dump(array(
    54     'offsetExists' => $list->offsetExists(4),
    55     'offsetGet' => $list->offsetGet(0),
    56 
    57 ));
    58 var_dump($list);
    59 
    60 //堆栈,先进后出
    61 $stack = new SplStack();//继承自SplDoublyLinkedList类
    62 
    63 $stack->push("a<br />");
    64 $stack->push("b<br />");
    65 
    66 echo $stack->pop();
    67 echo $stack->pop();
    68 echo $stack->offsetSet(0,'B');//堆栈的offset=0是Top所在的位置,offset=1是Top位置节点靠近bottom位置的相邻节点,以此类推
    69 $stack->rewind();//双向链表的rewind和堆栈的rewind相反,堆栈的rewind使得当前指针指向Top所在的位置,而双向链表调用之后指向bottom所在位置
    70 echo 'current:'.$stack->current().'<br />';
    71 
    72 $stack->next();//堆栈的next操作使指针指向靠近bottom位置的下一个节点,而双向链表是靠近top的下一个节点
    73 echo 'current:'.$stack->current().'<br />';
    74 echo '<br /><br />';
    75 
    76 //队列,先进先出
    77 $queue = new SplQueue();//继承自SplDoublyLinkedList类
    78 
    79 $queue->enqueue("a<br />");//插入一个节点到队列里面的Top位置
    80 $queue->enqueue("b<br />");
    81 
    82 $queue->offsetSet(0,'A');//堆栈的offset=0是Top所在的位置,offset=1是Top位置节点靠近bottom位置的相邻节点,以此类推
    83 
    84 echo $queue->dequeue();
    85 echo $queue->dequeue();
    86 
    87 echo "<br /><br />";
    复制代码

     

        堆

        堆(Heap)就是为了实现优先队列而设计的一种数据结构,它是通过构造二叉堆(二叉树的一种)实现。根节点最大的堆叫做最大堆或大根堆(SplMaxHeap),根节点最小的堆叫做最小堆或小根堆(SplMinHeap)。二叉堆还常用于排序(堆排序)。

        SplHeap类摘要如下:

    复制代码
     1 abstract SplHeap implements Iterator , Countable {
     2   /* 方法 */
     3   public __construct ( void )
     4   abstract protected int compare ( mixed $value1 , mixed $value2 )
     5   public int count ( void )
     6   public mixed current ( void )
     7   public mixed extract ( void )
     8   public void insert ( mixed $value )
     9   public bool isEmpty ( void )
    10   public mixed key ( void )
    11   public void next ( void )
    12   public void recoverFromCorruption ( void )
    13   public void rewind ( void )
    14   public mixed top ( void )
    15   public bool valid ( void )
    16 }
    复制代码

        显然它是一个抽象类,最大堆(SplMaxHeap)和最小堆(SplMinHeap)就是继承它实现的。最大堆和最小堆并没有额外的方法。

    SplHeap简单使用:

    复制代码
     1 //
     2 class MySplHeap extends SplHeap{
     3     //compare()方法用来比较两个元素的大小,绝对他们在堆中的位置
     4     public function compare( $value1, $value2 ) {
     5         return ( $value1 - $value2 );
     6     }
     7 }
     8 
     9 $obj = new MySplHeap();
    10 
    11 $obj->insert(0);
    12 $obj->insert(1);
    13 $obj->insert(2);
    14 $obj->insert(3);
    15 $obj->insert(4);
    16 
    17 echo $obj->top();//4
    18 echo $obj->count();//5
    19 
    20 foreach ($obj as $item) {
    21     echo $item."<br />";
    22 }
    复制代码

        

        队列

    优先队列也是非常实用的一种数据结构,可以通过加权对值进行排序,由于排序在php内部实现,业务代码中将精简不少而且更高效。通过SplPriorityQueue::setExtractFlags(int  $flag)设置提取方式可以提取数据(等同最大堆)、优先级、和两者都提取的方式。

        SplPriorityQueue类摘要如下:

    复制代码
     1 SplPriorityQueue implements Iterator , Countable {
     2   /* 方法 */
     3   public __construct ( void )
     4   public int compare ( mixed $priority1 , mixed $priority2 )
     5   public int count ( void )
     6   public mixed current ( void )
     7   public mixed extract ( void )
     8   public void insert ( mixed $value , mixed $priority )
     9   public bool isEmpty ( void )
    10   public mixed key ( void )
    11   public void next ( void )
    12   public void recoverFromCorruption ( void )
    13   public void rewind ( void )
    14   public void setExtractFlags ( int $flags )
    15   public mixed top ( void )
    16   public bool valid ( void )
    17 }
    复制代码

        简单使用:

    复制代码
     1 $pq = new SplPriorityQueue();
     2 
     3 $pq->insert('a', 10);
     4 $pq->insert('b', 1);
     5 $pq->insert('c', 8);
     6 
     7 echo $pq->count() .PHP_EOL; //3
     8 echo $pq->current() . PHP_EOL; //a
     9 
    10 /**
    11  * 设置元素出队模式
    12  * SplPriorityQueue::EXTR_DATA 仅提取值
    13  * SplPriorityQueue::EXTR_PRIORITY 仅提取优先级
    14  * SplPriorityQueue::EXTR_BOTH 提取数组包含值和优先级
    15  */
    16 $pq->setExtractFlags(SplPriorityQueue::EXTR_DATA);
    17 
    18 while($pq->valid()) {
    19     print_r($pq->current());  //a  c  b
    20     $pq->next();
    21 }
    复制代码

     

        阵列

    SplFixedArray主要是处理数组相关的主要功能,与普通php array不同的是,它是固定长度的,且以数字为键名的数组,优势就是比普通的数组处理更快。通常情况下SplFixedArray要比php array快上20%~30%,所以如果你是处理巨大数量的固定长度数组,还是强烈建议使用。

    SplFixedArray类摘要如下:

    复制代码
     1 SplFixedArray implements Iterator , ArrayAccess , Countable {
     2   /* 方法 */
     3   public __construct ([ int $size = 0 ] )
     4   public int count ( void )
     5   public mixed current ( void )
     6   public static SplFixedArray fromArray ( array $array [, bool $save_indexes = true ] )
     7   public int getSize ( void )
     8   public int key ( void )
     9   public void next ( void )
    10   public bool offsetExists ( int $index )
    11   public mixed offsetGet ( int $index )
    12   public void offsetSet ( int $index , mixed $newval )
    13   public void offsetUnset ( int $index )
    14   public void rewind ( void )
    15   public int setSize ( int $size )
    16   public array toArray ( void )
    17   public bool valid ( void )
    18   public void __wakeup ( void )
    19 }
    复制代码

    简单使用:

    复制代码
     1 $arr = new SplFixedArray(4);
     2 $arr[0] = 'php';
     3 $arr[1] = 1;
     4 $arr[3] = 'python';
     5 
     6 //遍历, $arr[2] 为null
     7 foreach($arr as $v) {
     8     echo $v . PHP_EOL;
     9 }
    10 
    11 //获取数组长度
    12 echo $arr->getSize(); //4
    13 
    14 //增加数组长度
    15 $arr->setSize(5);
    16 $arr[4] = 'new one';
    17 
    18 //捕获异常
    19 try{
    20     echo $arr[10];
    21 } catch (RuntimeException $e) {
    22     echo $e->getMessage();
    23 }
    复制代码

     

        映射

    用来存储一组对象的,特别是当你需要唯一标识对象的时候。

     

    PHP SPL SplObjectStorage类实现了Countable,Iterator,Serializable,ArrayAccess四个接口。可实现统计、迭代、序列化、数组式访问等功能。

    SplObjectStorage类摘要如下:

    复制代码
     1 SplObjectStorage implements Countable , Iterator , Serializable , ArrayAccess {
     2   /* 方法 */
     3   public void addAll ( SplObjectStorage $storage )
     4   public void attach ( object $object [, mixed $data = NULL ] )
     5   public bool contains ( object $object )
     6   public int count ( void )
     7   public object current ( void )
     8   public void detach ( object $object )
     9   public string getHash ( object $object )
    10   public mixed getInfo ( void )
    11   public int key ( void )
    12   public void next ( void )
    13   public bool offsetExists ( object $object )
    14   public mixed offsetGet ( object $object )
    15   public void offsetSet ( object $object [, mixed $data = NULL ] )
    16   public void offsetUnset ( object $object )
    17   public void removeAll ( SplObjectStorage $storage )
    18   public void removeAllExcept ( SplObjectStorage $storage )
    19   public void rewind ( void )
    20   public string serialize ( void )
    21   public void setInfo ( mixed $data )
    22   public void unserialize ( string $serialized )
    23   public bool valid ( void )
    24 }
    复制代码

        简单使用:

    复制代码
     1 class A {
     2     public $i;
     3     public function __construct($i) {
     4         $this->i = $i;
     5     }
     6 }
     7  
     8 $a1 = new A(1);
     9 $a2 = new A(2);
    10 $a3 = new A(3);
    11 $a4 = new A(4);
    12  
    13 $container = new SplObjectStorage();
    14  
    15 //SplObjectStorage::attach 添加对象到Storage中
    16 $container->attach($a1);
    17 $container->attach($a2);
    18 $container->attach($a3);
    19  
    20 //SplObjectStorage::detach 将对象从Storage中移除
    21 $container->detach($a2);
    22  
    23 //SplObjectStorage::contains用于检查对象是否存在Storage中
    24 var_dump($container->contains($a1)); //true
    25 var_dump($container->contains($a4)); //false
    26  
    27 //遍历
    28 $container->rewind();
    29 while($container->valid()) {
    30     var_dump($container->current());
    31     $container->next();
    32 }
    展开全文
  • spl初识

    2018-07-26 16:26:00
    spl初识" date: 2016-05-13 20:26:58 +0800 comments: true categories: 什么是SPL SPL是Standard PHP Library(PHP标准库)的缩写。 根据官方定义,它是"a collection of interfaces and classes that...
  • m trying to use spl_hostid kernel parameter, but it seems to be recognized only by zfs, while spl sets its own hostid, which is clear from the boot message. <p>There was some comment a year ago about ...
  • stm32SPL06实例

    2021-03-30 11:03:46
    stm32SPL06实例
  • php中的spl,PHP中SPL使用

    2021-04-30 06:44:00
    SPL包括以下内容1. 数据结构2. 迭代器3. 基础接口4. 异常4. SPL函数5. 文件处理#SPL数据结构虽然我们可以使用传统的变量类型来描述数据结构,例如用数组来描述堆栈(Strack)-- 然后使用对应的方式 pop 和 push...
  • Distribute spl tokens

    2020-12-01 18:56:46
    <ul><li>Add <code>distribute-spl-tokens</code> subcommand to <code>solana-tokens</code> that transfers SPL tokens to pre-existing, mint-matching Accounts.</li></ul> <p>Fixes #12315 </p><p>该提问来源于...
  • spl_parser XML SPL(结构化产品标签)格式的解析器 根据CCL获得许可的原始作品
  • spl06使用代码.zip

    2021-03-30 11:03:56
    spl06使用
  • spl基本命令

    2011-11-01 10:54:50
    spl基本命令spl基本命令spl基本命令spl基本命令spl基本命令spl基本命令spl基本命令
  • 1.SPL 是什么?SPL:standard php library php标准库,此 从php5.0起开始内置的组件和接口,在5.3以后逐渐成熟。因为内置在php5开发环境中,无需任何配置。根据官方定义,“a collection of interfaces and classes ...
  • PHP SPL相关

    2020-12-15 17:43:40
    什么是SPL 什么是Iterator SPL数据结构 SPL迭代器 SPL函数 SPL文件处理 各种类接口 1.1什么是SPL SPL是解决典型(standard porblems)问题的一组接口和类的集合。 1.2 什么是Iterator 它是SPL的核心理念,...
  • 在许多框架和MVC中都能够看到PHP SPL的身影, PHP SPL 在很多实际应用都占了很大的比重双向链表$obj=newSplDoublyLinkedList();$obj->push(1);$obj->push(2);$obj->push(3);$obj->unshift(10);//...
  • PHP SPL模块中自带一个观察者模式,观察者模式是一...在观察者模式中,被观察的叫subject,而负责观察的类叫做observe,为了表达这些内容,SPL提供了SplSubject和SplObserver接口。SplSubject接口;interface SplSub...
  • 标签:在许多框架和MVC中都能够看到PHP SPL的身影, PHP SPL 在很多实际应用都占了很大的比重双向链表$obj=newSplDoublyLinkedList();$obj->push(1);$obj->push(2);$obj->push(3);$obj->unshift(10);//...
  • 学生编程语言(SPL)编译并执行以PL / I子集编写的程序。 SPL是由David B. Wortman于1969年在斯坦福大学创建的,它是面向初学者的教学工具。 1970年,皇家墨尔本理工学院的Robin A. Vowels对编译器进行了修改,使其...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,033
精华内容 3,213
关键字:

spl