S5PV210之SDRAM初始化

本文使用的开发板是九鼎创展的X210 iNand版本。

 

一、查阅原理图中SDRAM相关部分

 


 

从以上原理图中可以得出以下信息:

(1)开发板上使用的SDRAM编码是K4T1G164QQ

(2)开发板上包括4片内存芯片,每片内存的数据总线都是16位的

(3)横向的两颗内存芯片是并联的(并联时地址总线的接法一样,但数据总线要加起来),这样连接相当于在逻辑上可以把这两颗内存芯片看成是一个32位的内存芯片

(4)每个内存端口都由3类总线构成:地址总线(Xm1_ADDR0~Xm1_ADDR13、Xm2_ADDR0~Xm2_ADDR13)+ 控制总线 + 数据总线(Xm1_DATA0~Xm1_DATA31、Xm2_DATA0~Xm2_DATA31)

 

二、查阅SDRAM数据手册

 

由上图可得出K4T1G164QQ的含义如下:

   K:三星内存

   4:DRAM

   T:DDR2 SDRAM

1G:1Gb(128MB)

 16:单芯片16位宽

   4:8 Banks

 

 

由上图可得出以下信息:

(1)S5PV210的内存端口信号中有BA0~BA2,接在内存芯片的BA0~BA2上,这些引脚用来选择Bank

(2)每个Bank内部有128Mb,通过Row Address(14位)+ Column Address(10位)的方式来综合寻址

(3)一共能寻址的范围是:2的24次方,也就是16MB(128Mb)的内存

 

三、查阅数据手册中内存映射相关部分

 

 

从上图可得出以下信息:

(1)S5PV210共有两个内存端口,分别是DRAM0和DRAM1

(2)DRAM0的内存地址范围是0x20000000~0x3FFFFFFF(512MB)

(3)DRAM1的内存地址范围是0x40000000~0x7FFFFFFF(1024MB)

 

由此,得出结论:

(1)S5PV210最多支持1.5GB的内存,如果给它更多的内存,CPU就无法识别

(2)S5PV210最多支持1.5GB的内存,但实际开发板上不一定有这么多。例如X210开发板就只有512MB的内存(DRAM0端口分布256MB,DRAM1端口分布256MB)

(3)X210开发板上内存的合法地址是0x20000000~0x2FFFFFFF(256MB)+ 0x40000000~0x4FFFFFFF(256MB)

 

综合以上信息,进一步得出结论:

(1)X210开发板共使用了4片内存,每片1Gb(128MB),共512MB

(2)DRAM0对应的引脚是Xm1_xxxx

(3)DRAM1对应的引脚是Xm2_xxxx

(4)从数据总线的位数可知,X210开发板用的是32位的内存

 

四、查阅数据手册中DDR2初始化相关部分

 


 

由上图可知:初始化DDR2共需27个步骤。

 

综合前文所述,初始化DRAM时分为2部分:第一部分初始化DRAM0,第二部分初始化DRAM1。

 

编码实现部分只实现DRAM0的初始化,DRAM1的初始化步骤相同。

 

五、代码实现

 

1、led.c

 

#define GPJ0CON	 0xE0200240
#define GPJ0DAT	 0xE0200244

#define rGPJ0CON *((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT *((volatile unsigned int *)GPJ0DAT)

void delay(void);

void led_blink(void) {
	rGPJ0CON = 0x11111111;
	
	while(1) {
		// led亮
		rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));
		// 延时
		delay();
		// led灭
		rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));
		// 延时
		delay();
	}
}

void delay(void) {
	volatile unsigned int i = 900000;		
	while (i--);							
}

 

2、link.lds

 

SECTIONS
{
	. = 0x20000000;
	
	.text : {
		start.o
		sdram_init.o
		* (.text)
	}
    		
	.data : {
		* (.data)
	}
	
	bss_start = .; 
	.bss : {
		* (.bss)
	}
	
	bss_end  = .;	
}

 

3、Makefie

 

led.bin: start.o led.o sdram_init.o
	arm-linux-ld -Tlink.lds -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	arm-linux-objdump -D led.elf > led_elf.dis
	gcc mkv210_image.c -o mkx210
	./mkx210 led.bin 210.bin
	
%.o : %.S
	arm-linux-gcc -o $@ $< -c -nostdlib

%.o : %.c
	arm-linux-gcc -o $@ $< -c -nostdlib

clean:
	rm *.o *.elf *.bin *.dis mkx210 -f

 

4、start.S

 

#define SVC_STACK	0xD0037D80

.global _start					
_start:
	ldr sp, =SVC_STACK

	// 初始化DDR
	bl sdram_asm_init
	
	// 重定位
	adr r0, _start  				
	ldr r1, =_start 	
	ldr r2, =bss_start	
	cmp r0, r1			
	beq clean_bss		

copy_loop:
	ldr r3, [r0], #4    
	str r3, [r1], #4	
	cmp r1, r2			
	bne copy_loop

clean_bss:
	ldr r0, =bss_start					
	ldr r1, =bss_end
	cmp r0, r1				
	beq run_on_dram			
	mov r2, #0
clear_loop:
	str r2, [r0], #4		
	cmp r0, r1				
	bne clear_loop

run_on_dram:	
	ldr pc, =led_blink				

	b .

 

5、sdram_init.S

 

#define DMC0_MEMCONTROL		0x00202400 	// MemControl	BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off

#define DMC0_MEMCONFIG_0	0x20F01323	// MemConfig0	256MB config, 8 banks, Mapping Method[12:15] 0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1	0x30F00312	// MemConfig1	默认值

#define DMC0_TIMINGA_REF	0x00000618	// TimingAref	7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW		0x28233287	// TimingRow	for @200MHz
#define DMC0_TIMING_DATA	0x23240304	// TimingData	CL=3
#define	DMC0_TIMING_PWR		0x09C80232	// TimingPower

.global sdram_asm_init
sdram_asm_init:	
	ldr	r0, =0xf1e00000
	ldr	r1, =0x0
	str	r1, [r0, #0x0]

	/* DMC0 Drive Strength (Setting 2X) */
	
	ldr	r0, =ELFIN_GPIO_BASE

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_0DRV_SR_OFFSET]		

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_1DRV_SR_OFFSET]

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_2DRV_SR_OFFSET]

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_3DRV_SR_OFFSET]

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_4DRV_SR_OFFSET]

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_5DRV_SR_OFFSET]

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_6DRV_SR_OFFSET]

	ldr	r1, =0x0000AAAA
	str	r1, [r0, #MP1_7DRV_SR_OFFSET]

	ldr	r1, =0x00002AAA
	str	r1, [r0, #MP1_8DRV_SR_OFFSET]
	
	/* DMC0 initialization at single Type */
	ldr	r0, =APB_DMC_0_BASE

	ldr	r1, =0x00101000	      @PhyControl0 DLL parameter setting, manual 0x00101000
	str	r1, [r0, #DMC_PHYCONTROL0]

	ldr	r1, =0x00000086	      @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case
	str	r1, [r0, #DMC_PHYCONTROL1]

	ldr	r1, =0x00101002				@PhyControl0 DLL on
	str	r1, [r0, #DMC_PHYCONTROL0]

	ldr	r1, =0x00101003				@PhyControl0 DLL start
	str	r1, [r0, #DMC_PHYCONTROL0]

find_lock_val:
	ldr	r1, [r0, #DMC_PHYSTATUS]	@Load Phystatus register value
	and	r2, r1, #0x7
	cmp	r2, #0x7					@Loop until DLL is locked
	bne	find_lock_val
	
	and	r1, #0x3fc0 
	mov	r2, r1, LSL #18
	orr	r2, r2, #0x100000
	orr	r2 ,r2, #0x1000	
		
	orr	r1, r2, #0x3				@Force Value locking
	str	r1, [r0, #DMC_PHYCONTROL0]
	
#if 0	/* Memory margin test 10.01.05 */
	orr	r1, r2, #0x1				@DLL off
	str	r1, [r0, #DMC_PHYCONTROL0]
#endif
	/* setting DDR2 */
	ldr	r1, =0x0FFF2010				@ConControl auto refresh off
	str	r1, [r0, #DMC_CONCONTROL]

	ldr	r1, =DMC0_MEMCONTROL		@MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
	str	r1, [r0, #DMC_MEMCONTROL]
	
	ldr	r1, =DMC0_MEMCONFIG_0		@MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
	str	r1, [r0, #DMC_MEMCONFIG0]

	ldr	r1, =DMC0_MEMCONFIG_1		@MemConfig1
	str	r1, [r0, #DMC_MEMCONFIG1]

	ldr	r1, =0xFF000000				@PrechConfig
	str	r1, [r0, #DMC_PRECHCONFIG]
	
	ldr	r1, =DMC0_TIMINGA_REF		@TimingAref	7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
	str	r1, [r0, #DMC_TIMINGAREF]
	
	ldr	r1, =DMC0_TIMING_ROW		@TimingRow	for @200MHz
	str	r1, [r0, #DMC_TIMINGROW]

	ldr	r1, =DMC0_TIMING_DATA		@TimingData	CL=3
	str	r1, [r0, #DMC_TIMINGDATA]
	
	ldr	r1, =DMC0_TIMING_PWR		@TimingPower
	str	r1, [r0, #DMC_TIMINGPOWER]

	ldr	r1, =0x07000000				@DirectCmd	chip0 Deselect
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x01000000				@DirectCmd	chip0 PALL
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00020000				@DirectCmd	chip0 EMRS2
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00030000				@DirectCmd	chip0 EMRS3
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00010400				@DirectCmd	chip0 EMRS1 (MEM DLL on, DQS# disable)
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00000542				@DirectCmd	chip0 MRS (MEM DLL reset) CL=4, BL=4
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x01000000				@DirectCmd	chip0 PALL
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x05000000				@DirectCmd	chip0 REFA
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x05000000				@DirectCmd	chip0 REFA
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00000442				@DirectCmd	chip0 MRS (MEM DLL unreset)
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00010780				@DirectCmd	chip0 EMRS1 (OCD default)
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x00010400				@DirectCmd	chip0 EMRS1 (OCD exit)
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x07100000				@DirectCmd	chip1 Deselect
	str	r1, [r0, #DMC_DIRECTCMD]

	ldr	r1, =0x01100000				@DirectCmd	chip1 PALL
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x00120000				@DirectCmd	chip1 EMRS2
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x00130000				@DirectCmd	chip1 EMRS3
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x00110400				@DirectCmd	chip1 EMRS1 (MEM DLL on, DQS# disable)
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x00100542				@DirectCmd	chip1 MRS (MEM DLL reset) CL=4, BL=4
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x01100000				@DirectCmd	chip1 PALL
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x05100000				@DirectCmd	chip1 REFA
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x05100000				@DirectCmd	chip1 REFA
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x00100442				@DirectCmd	chip1 MRS (MEM DLL unreset)
	str	r1, [r0, #DMC_DIRECTCMD]
	
	ldr	r1, =0x00110780				@DirectCmd	chip1 EMRS1 (OCD default)
	str	r1, [r0, #DMC_DIRECTCMD]
		
	ldr	r1, =0x00110400				@DirectCmd	chip1 EMRS1 (OCD exit)
	str	r1, [r0, #DMC_DIRECTCMD]
		
	ldr	r1, =0x0FF02030				@ConControl	auto refresh on
	str	r1, [r0, #DMC_CONCONTROL]
		
	ldr	r1, =0xFFFF00FF				@PwrdnConfig
	str	r1, [r0, #DMC_PWRDNCONFIG]
		
	ldr	r1, =0x00202400				@MemControl	BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
	str	r1, [r0, #DMC_MEMCONTROL]

	mov pc, lr

 

acm实用小技巧

在acm题目中经常会有十分麻烦的问题,有时候这些问题可以用一些已有的方法进行解决,不需要自己写算法。所以我在这里记录下来,也是作为学习笔记。

一、memset  头文件  cstring

   这个函数可以用来初始化,例如: 

   int x[100];

   memset(x,0,sizeof(x));

二、c++中string类的用法

   getline(istream &in,string &s);用来把一行的内容写入s中

   find(char *c, int pos = 0);从pos开始查找字符c在当前字符串的位置,返回值为字符c的位置,若找不到,返回值为 string::npos

   insert(int pos, const char *s);从pos位置插入字符串s

   erase(int pos = 0, int n = npos);删除pos开始的n个字符,返回修改后的字符串

三、sort 函数 头文件 algorithm

   sort可以对任意对象进行排序

   在数组中,用sort(a,a+n)调用

   在vector中,用sort(v.begin(),v.end())调用

四、set 集合 头文件 set

   set中元素已从小到大排好序,且集合中相同元素最多只出现一次

五、map 映射 头文件 map

   map就是从键(key)到值(value)的映射,且重载了[]运算符,

   可以用 map<string,int> name_id 来表示名字到id的映射

   可以用 name_id[“mzh”]=25 这样的方式赋值

六、栈、队列和优先队列

   栈:符合 后进先出 规则的数据结构 有push和pop两种操作 头文件 stack

   队列:符合 先进先出 的公平队列 头文件 queue 用push和pop进行入队和出队操作

七、随机生成

   cstdlib 中的 rand 函数可以生成一个[0,RAND_MAX]闭区间内的均匀随机整数

   可以用rank()%n 产生一个 [0,n-1]内的随机整数

   需要随机数的程序在最开始时要执行一次 srand(time(NULL)),目的是初始化“随机数种子”,而不可以多次调用

八、断言

   assert 宏

   用法是 assert(表达式) 当表达式为假时强行终止程序,并给出错误提示。

九、用stringstream完成数据转换 头文件 sstream

   stringstream可以用来把string类型的字符串转换成int

   例如:string s(“12345”);

int x=1;    //x=1

stringstream ss(s);

ss>>x;      //x=12345

   也可以

        string s(“12345”);

int x=1;    //x=1

stringstream ss;

        ss<<s;

ss>>x;      //x=12345

   还可以用str()的方法:

        typename x=5.222;

        cin>>x;

        stringstream ss;

        ss<<x;

        string s;

        s=ss.str(); //s=”5.222″

   这样就可以将多种数值转换成字符串

转】函数调用堆栈

转】函数调用 堆栈

#include <stdio.h>

long test(int a,int b)

{

      a = a + 3;

      b = b + 5;

     return a + b;

}

int main(int argc, char* argv[])

{

     printf(“%d”,test(10,90));

    return 0;

}

先来看一个概貌

16:   int main(int argc, char* argv[])

17:    {

00401070   push         ebp

00401071   mov          ebp,esp

00401073   sub          esp,40h

00401076   push         ebx

00401077   push         esi

00401078   push         edi

00401079   lea          edi,[ebp-40h]

0040107C   mov          ecx,10h

00401081   mov          eax,0CCCCCCCCh

00401086   rep stos     dword ptr [edi]

18:        printf(“%d”,test(10,90));

00401088   push         5Ah

0040108A   push         0Ah

0040108C   call         @ILT+0(test) (00401005)

00401091   add          esp,8

00401094   push         eax

00401095   push         offset string “%d” (0042201c)

0040109A   call         printf (004010d0)

0040109F   add          esp,8

19:        return 0;

004010A2   xor          eax,eax

20:    }

下面来解释一下

开始进入Main函数 esp=0x12FF84   ebp=0x12FFC0

完成椭圆形框起来的部分

00401070   push        ebp     ebp的值入栈,保存现场(调用现场,从test函数看,如红线所示,即保存的0x12FF80用于从test函数堆栈返回到main函数)

00401071   mov         ebp,esp     此时ebp=0x12FF80 此时ebp就是“当前函数堆栈”的基址 以便访问堆栈中的信息;还有就是从当前函数栈顶返回到栈底

00401073   sub      esp,40h  

函数使用的堆栈,默认64个字节,堆栈上就是16个横条(密集线部分)此时esp=0x12FF40

在上图中,上面密集线是test函数堆栈空间,下面是Main的堆栈空间     (补充,其实这个就叫做 Stack Frame)

00401076   push        ebx

00401077   push        esi

00401078   push        edi    入栈

00401079   lea         edi,[ebp-40h]

0040107C   mov         ecx,10h

00401081   mov         eax,0CCCCCCCCh

00401086   rep stos    dword ptr [edi]     

初始化用于该函数的栈空间为0XCCCCCCCC 即从0x12FF40~0x12FF80所有的值均为0xCCCCCCCC

18:       printf(“%d”,test(10,90));

00401088   push        5Ah    参数入栈 从右至左 先90 后10

0040108A   push        0Ah

0040108C   call        @ILT+0(test) (00401005)  

函数调用,转向eip 00401005

注意,此时仍入栈,入栈的是call test 指令下一条指令的地址00401091    下一条指令是add esp,8

@ILT+0( test@@YAJHH@Z):

00401005   jmp         test (00401020)  

即转向被调函数test



1. 如果函数调用方式是__stdcall 不同之处在于

main函数call 后面没有了 add esp, 8

test函数最后一句 是 ret 8   (由test函数清栈, ret 8意思是执行ret后,esp+8)

2. 运行过程中0x12FF28 保存了指令地址 00401091是怎么保存的?

栈每个空间保存4个字节(粒度4字节) 例如下一个栈空间0x12FF2C保存参数10

因此

0x12FF28 0x12FF29 0x12FF2A 0x12FF2B  

91              10            40           00      

little-endian 认为其读的第一个字节为最小的那位上的数

3. char a[] = “abcde”

对局部字符数组变量(栈变量)赋值,是利用寄存器从全局数据内存区把字符串“abcde”拷贝到栈内存中的

4. int szNum[5] = { 1, 2, 3, 4, 5 }; 栈中是如何分布的?

      00401798   mov         dword ptr [ebp-14h],1

      0040179F   mov         dword ptr [ebp-10h],2

      004017A6   mov         dword ptr [ebp-0Ch],3

      004017AD   mov         dword ptr [ebp-8],4

      004017B4   mov         dword ptr [ebp-4],5

可以看出来 是从右边开始入栈,所以是 5 4 3 2 1 入栈

int *ptrA = (int*)(&szNum+1);

int *ptrB = (int*)((int)szNum + 1);

std::cout<< ptrA[-1] << *ptrB << std::endl;

结果如何?

28:       int *ptrA = (int*)(&szNum+1);

004017BB   lea         eax,[ebp]

004017BE   mov         dword ptr [ebp-18h],eax

&szNum是指向数组指针;加1是加一个数组宽度;&szNum+1指向移动5个int单位之后的那个地方, 就是把EBP的地址赋给指针

ptrA[-1]是回退一个int*宽度,即ebp-4

29:       int *ptrB = (int*)((int)szNum + 1);

004017C1   lea         ecx,[ebp-13h]

004017C4   mov         dword ptr [ebp-1Ch],ecx

如果上面是指针算术,那这里就是地址算术,只是首地址+1个字节的offset,即ebp-13h给指针

实际保存是这样的

01               00            00       00            02            00       00       00

ebp-14h      ebp-13h                       ebp-10h

注意是int*类型的,最后获得的是 00 00 00 02

由于Little-endian, 实际上逻辑数是02000000   转换为十进制数就为33554432

最后输出533554432

8:     long test(int a,int b)

9:     {

00401020   push         ebp

00401021   mov          ebp,esp          

00401023   sub          esp,40h

00401026   push         ebx

00401027   push         esi

00401028   push         edi

00401029   lea          edi,[ebp-40h]

0040102C   mov          ecx,10h

00401031   mov          eax,0CCCCCCCCh

00401036   rep stos     dword ptr [edi]       //这些和上面一样

10:         a = a + 3;                                   

00401038   mov          eax,dword ptr [ebp+8]     //ebp=0x12FF24 加8 [0x12FF30]即取到了参数10

0040103B   add          eax,3

0040103E   mov          dword ptr [ebp+8],eax

11:         b = b + 5;

00401041   mov          ecx,dword ptr [ebp+0Ch]

00401044   add          ecx,5

00401047   mov          dword ptr [ebp+0Ch],ecx

12:         return a + b;

0040104A   mov          eax,dword ptr [ebp+8]

0040104D   add          eax,dword ptr [ebp+0Ch] //最后的结果保存在eax, 结果得以返回

13:    }

00401050   pop          edi                

00401051   pop          esi

00401052   pop          ebx

00401053   mov          esp,ebp      //esp指向0x12FF24, test函数的堆栈空间被放弃,从当前函数栈顶返回到栈底

00401055   pop          ebp            //此时ebp=0x12FF80, 恢复现场 esp=0x12FF28

00401056   ret                           ret负责栈顶0x12FF28之值00401091弹出到指令寄存器中,esp=0x12FF30

因为win32汇编一般用eax返回结果 所以如果最终结果不是在eax里面的话 还要把它放到eax

注意,从被调函数返回时,是弹出EBP,恢复堆栈到函数调用前的地址,弹出返回地址到EIP以继续执行程序。

从test函数返回,执行

00401091   add         esp,8      

清栈,清除两个压栈的参数10 90 调用者main负责

(所谓__cdecl调用由调用者负责恢复栈,调用者负责清理的只是入栈的参数,test函数自己的堆栈空间自己返回时自己已经清除,靠!一直理解错)

00401094   push        eax          入栈,计算结果108入栈,即printf函数的参数之一入栈

00401095   push        offset string “%d” (0042201c)     入栈,参数 “%d” 当然其实是%d的地址

0040109A   call        printf (004010d0)      函数调用 printf(“%d”,108) 因为printf函数时

0040109F   add         esp,8       清栈,清除参数 (“%d”, 108)

19:       return 0;          

004010A2   xor         eax,eax     eax清零

20:   }

main函数执行完毕 此时esp=0x12FF34   ebp=0x12FF80

004010A4   pop         edi

004010A5   pop         esi

004010A6   pop         ebx

004010A7   add         esp,40h    //为啥不用mov esp, ebp  是为了下面的比较

004010AA   cmp         ebp,esp   //比较,若不同则调用chkesp抛出异常

004010AC   call        __chkesp (00401150)  

004010B1   mov         esp,ebp  

004010B3   pop         ebp          //ESP=0X12FF84 EBP=0x12FFC0 尘归尘 土归土 一切都恢复最初的平静了

004010B4   ret

原文地址:http://www.cnblogs.com/dylanwind/archive/2008/12/08/1349822.html

NSData,NSImage,NSDictionary,NSString,NSInteger,Float,NSURL等等互相转换

一:NSString和NSURL 转换

 

 
  1. //NSString->NSURL  
  2. NSString *urlString=[@“http://www.google.com” stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];  
  3. NSURL *url=[NSURL URLWithString:urlString];   
  4. //NSURL->NSString   
  5. NSString *urlString=[[url absoluteString] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];  

 

二:NSString和NSData转换(即可作json串互相转换)

 

 
  1. //NSData-> NSString  
  2. NSString *testString = [[NSString alloc] initWithData:testData encoding:NSUTF8StringEncoding];  
  3. //NSString->NSData  
  4. NSString *aString = @“我是NSString”;  
  5. NSData *testData = [testString dataUsingEncoding: NSUTF8StringEncoding];  

 

三:NSData和NSImage转换

 

  1. //NSData->UIImage  
  2. UIImage *testImage = [UIImage imageWithData: imageData];  
  3. //UIImage->NSData  
  4. NSData *imageData = UIImagePNGRepresentation(testImage)  
  5. //或者  
  6. NSData *imageData = UIImageJPEGRepresentation(testImage,1.0)  

 

四:NSData和NSDictionary转换

 

 

  1. //NSData–>NSDictionary  
  2. NSDictionary *testDict = [NSJSONSerialization JSONObjectWithData:testData options:NSJSONReadingMutableContainers error:nil]  
  3. //或者  
  4. NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:testData];    
  5. NSDictionary *myDictionary = [[unarchiver decodeObjectForKey:@“Some Key Value”] retain];    
  6. [unarchiver finishDecoding];  
  7. //NSDictionay –> NSData  
  8. NSMutableData *data = [[NSMutableData alloc] init];    
  9. NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];    
  10. [archiver encodeObject:params forKey:@“Some Key Value”];    
  11. [archiver finishEncoding];  

 

五:NSDictionary和JSON转换

 

 
  1. //NSDictionary -> JSON:  //这个方法是SBJson类库里的,需要导入SBJson.h  
  2. NSString *jsonStr=[dict JSONRepresentation];  
  3. //建议(特别是http取回来的jsonStr转换如下)  
  4. //JSON->NSDictionary:  
  5. NSData *jsonData = [testJsonStr dataUsingEncoding:NSUTF8StringEncoding];  
  6. NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil]  

 

 

//摘录其他同学的

NSData 与 Byte
NSData-> Byte数组
NSString *testString = @”1234567890″;
NSData *testData = [testString dataUsingEncoding: NSUTF8StringEncoding];
Byte *testByte = (Byte *)[testData bytes];
for(int i=0;i<[testData length];i++)
printf(“testByte = %d\n”,testByte[i]);

Byte数组-> NSData
Byte byte[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
NSData *adata = [[NSData alloc] initWithBytes:byte length:24];

Byte数组->16进制数
Byte *bytes = (Byte *)[aData bytes];
NSString *hexStr=@””;
for(int i=0;i<[encryData length];i++)
{
NSString *newHexStr = [NSString stringWithFormat:@”%x”,bytes[i]&0xff]; ///16进制数
if([newHexStr length]==1)
hexStr = [NSString stringWithFormat:@”%@0%@”,hexStr,newHexStr];
else
hexStr = [NSString stringWithFormat:@”%@%@”,hexStr,newHexStr];
}
NSLog(@”bytes 的16进制数为:%@”,hexStr);

16进制数->Byte数组
///// 将16进制数据转化成Byte 数组
NSString *hexString = @”3e435fab9c34891f”; //16进制字符串
int j=0;
Byte bytes[128]; 

 

 ///3ds key的Byte 数组, 128位
for(int i=0;i<[hexString length];i++)
{
int int_ch;  /// 两位16进制数转化后的10进制数
 
unichar hex_char1 = [hexString characterAtIndex:i]; ////两位16进制数中的第一位(高位*16)
int int_ch1;
if(hex_char1 >= ‘0’ && hex_char1 <=’9′)
int_ch1 = (hex_char1-48)*16;   //// 0 的Ascll – 48
else if(hex_char1 >= ‘A’ && hex_char1 <=’F’)
int_ch1 = (hex_char1-55)*16; //// A 的Ascll – 65
else
int_ch1 = (hex_char1-87)*16; //// a 的Ascll – 97
i++;
 
unichar hex_char2 = [hexString characterAtIndex:i]; ///两位16进制数中的第二位(低位)
int int_ch2;
if(hex_char2 >= ‘0’ && hex_char2 <=’9′)
int_ch2 = (hex_char2-48); //// 0 的Ascll – 48
else if(hex_char1 >= ‘A’ && hex_char1 <=’F’)
int_ch2 = hex_char2-55; //// A 的Ascll – 65
else
int_ch2 = hex_char2-87; //// a 的Ascll – 97
 
int_ch = int_ch1+int_ch2;
NSLog(@”int_ch=%d”,int_ch);
bytes[j] = int_ch;  ///将转化后的数放入Byte数组里
j++;
}
NSData *newData = [[NSData alloc] initWithBytes:bytes length:128];
NSLog(@”newData=%@”,newData);

java封装继承多态等

       最近一段时间看了很多的视频却忘记总结了,现在只能想到什么写什么了,希望能起到一个回忆巩固的作用。

    1、final关键字

      译为:最终的

         final修饰的数据类型的量都是不能改变的

        final修饰的类是不能被继承的

        final修饰的方法在子类中是不能被重写的

package cn.bjsxt.oop.testFinal;


public /*final*/ class Animal {    //final修饰类则说明,这个类不能被继承!
	
	public /*final*/ void run(){   //final加到方法前面,意味着该方法不能被子类重写!
		System.out.println("跑跑!");
	}

}


class Bird  extends Animal {
	
	public void run(){
		super.run();
		System.out.println("我是一个小小小小鸟,飞呀飞不高");
	}
	
}

package cn.bjsxt.oop.testFinal;

public class TestFinal {
	public static void main(String[] args) {
		final int MAX_VALUE= 200;    //常量。
		double d = Math.PI;
	}
}

 

 

2、隐式参数this

java类里面的方法都有两个隐藏的参数分别是super和this,分别表示直接父类和自己类的对象。默认就加入进去了,不需要手动添加

 

package cn.bjsxt.oop.testThis;

public class Student {
	 String name;
	 int id;   
	 
	 public  Student(String name,int id){
		 this(name);   //通过this调用其他构造方法,必须位于第一句! Constructor call must be the first statement in a constructor
		 this.name = name;
		 this.id = id;
	 }
	 
//本来是这样	 public Student(String name,Student this,Object super){
		 this.name = name;
	 }
	 public Student(){
		 System.out.println("构造一个对象");
	 }
	 
	 public void setName(String name){
		 this.name = name;
	 }
	 
	 
	 public void study(){
		 this.name=  "张三";
		 System.out.println(name+"在學習");
	 }
	 
	 public void sayHello(String sname){
		 System.out.println(name+"向"+sname+"說:你好!");
	 }
	
}



 3、Object类,Object是所有类的父类,默认就继承这个类

 

package cn.bjsxt.oop.testObject;

//不重写Object类的toString方法时,我们打印对象会
直接输出hash码,重写之后就返回这个字符串
public class Mobile {
	public String toString(){
		return "我是一部移动电话";
	}
}
package cn.bjsxt.oop.testObject;

public class TestObject {
	public static void main(String[] args) {
		Object obj = new Object();
		Object obj2 = new Object();
		System.out.println(obj.toString());
		System.out.println(obj2.toString());
		System.out.println(obj==obj2);
		System.out.println(obj.equals(obj2)); 
		
		
		Mobile m = new Mobile();
		System.out.println(m.toString()); 
		
	}
}

 输出:java.lang.Object@64ea66
java.lang.Object@158f9d3
false
false

我是一部移动电话

 

静态

 

package cn.bjsxt.oop.testStatic;

public class Student {
	 String name;
	 int id;   
	 
	 static  int  ss;
	 
	 public static void printSS(){
		 System.out.println(ss);
	 }
	 

	 public void study(){
		 printSS();
		 System.out.println(name+"在學習");
	 }
	 
	 public void sayHello(String sname){
		 System.out.println(name+"向"+sname+"說:你好!");
	 }
	
}



package cn.bjsxt.oop.testStatic;

public class Test {
	public static void main(String[] args) {
		Student.ss = 323;
		Student.printSS();
		
		Student s1 = new Student();
		
	}
}

 

静态代码块

package cn.bjsxt.oop.staticInitBlock;

public class Parent001 /*extends Object*/ {
	static int aa;
	static {
		System.out.println(" 静态初始化Parent001");
		aa=200;
	}
}

package cn.bjsxt.oop.staticInitBlock;

public class TestStaticInitBlock extends Parent001 {
	
	static int a ;
	
	static {
		System.out.println("静态初始化TestStaticInitBlock!");
		a = 100;
	}
	
	
	public static void main(String[] args) {
		
	}
}

  静态初始化Parent001
静态初始化TestStaticInitBlock!

 

封装encapsulation,记忆capsul,胶囊

比如把属性设为私有,同时提供共有的方法访问或者设置属性值

 

继承与组合

继承:isa

package cn.bjsxt.oop.inherit;

/**
 * 测试继承
 * @author dell
 *
 */
public class Animal /*extends Object*/ {
	String eye;
	
	public void run(){
		System.out.println("跑跑!");
	}
	public void eat(){
		System.out.println("吃吃!");
	}
	public void sleep(){
		System.out.println("zzzzz");
	}
	
	public  Animal(){
		super();
		System.out.println("创建一个动物!");
	}
	
}

class Mammal extends Animal {
	
	public void taisheng(){
		System.out.println("我是胎生");
	}
	
}

class Bird  extends Animal {
	public void run(){
		super.run();
		System.out.println("我是一个小小小小鸟,飞呀飞不高");
	}
	
	public void eggSheng(){
		System.out.println("卵生");
	}
	
	public Bird(){
		super();
		System.out.println("建一个鸟对象");
	}
	
}

 

 

组合:hasa

package cn.bjsxt.oop.inherit;

/**
 * 测试组合
 * @author dell
 *
 */
public class Animal2 {
	String eye;
	
	public void run(){
		System.out.println("跑跑!");
	}
	public void eat(){
		System.out.println("吃吃!");
	}
	public void sleep(){
		System.out.println("zzzzz");
	}
	
	public  Animal2(){
		super();
		System.out.println("创建一个动物!");
	}
	
	public static void main(String[] args) {
		Bird2 b = new Bird2();
		b.run();
		b.animal2.eat();
	}
	
}

class Mammal2  {
	Animal2 animal2=new Animal2();
	public void taisheng(){
		System.out.println("我是胎生");
	}
	
}

class Bird2  {
	Animal2 animal2=new Animal2();
	
	public void run(){
		animal2.run();
		System.out.println("我是一个小小小小鸟,飞呀飞不高");
	}
	
	public void eggSheng(){
		System.out.println("卵生");
	}
	
	public Bird2(){
		super();
		System.out.println("建一个鸟对象");
	}
	
}

 

 

继承时带来的强制类型转换,和基本数据类型一样,引用数据类型也会有类型的转化

package cn.bjsxt.oop.polymorphism;

public class Animal {
	String str;
	public void voice(){
		System.out.println("普通动物叫声!");
	}
}

class Cat extends Animal {
	public void voice(){
		System.out.println("喵喵喵");
	}
	public void catchMouse(){
		System.out.println("抓老鼠");
	}
}

class Dog extends Animal {
	public void voice(){
		System.out.println("汪汪汪");
	}
	
	public void seeDoor(){
		System.out.println("看门!");
	}
	
}

class Tiger extends Animal {
	public void voice(){
		System.out.println("哇哇哇");
	}

	
}

class Pig extends Animal {
	public void voice(){
		System.out.println("哼哼哼");
	}
}

 动物都会发声,重写voice方法,不同的动物有不同的发声方法。有的动物还有自己父类所不具备的方法,猫会抓老鼠,狗会看门。

 

package cn.itcast_04;

public class Test {
	
	public static void testAnimalVoice(Animal c){
		c.voice();
		if(c instanceof Cat){
			((Cat) c).catchMouse();
		}
	}
	
	 
	public static void testAnimalVoice(Dog c){
		c.voice();
	}
	
	public static void testAnimalVoice(Pig c){
		c.voice();
	} 
 
	public static void main(String[] args) {
		//父类的引用指向子类的对象
              Animal a = new Cat();
                //强制类型转化,低到高
		Cat a2 = (Cat)a;
                //a是Cat实例的引用,会调用捉老鼠的方法
		testAnimalVoice(a);

                / /完成了强制类型转化
      	        a2.catchMouse();

 		Animal b = new Dog();
 		Animal c = new Tiger();
 		testAnimalVoice(b);
 	testAnimalVoice(c);
		
	}
}

 要考虑编译(eclipse不带有红叉报错)和运行阶段的错误(不抛出异常,比如ClassCastException)

代码改成:

 Animal a = new Animal();
                //强制类型转化,低到高
Cat a2 = (Cat)a;
则:抛出

cn.itcast_04.Animal cannot be cast to cn.itcast_04.Cat。

父类不可以强制转换为子类,因为子类有的方法父类可能没有

 

 

 

 

 

长连接和短连接,单工、半双工和全双工

所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持

短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,一般银行都使用短连接

比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。

其实长连接是相对于通常的短连接而说的,也就是长时间保持客户端与服务端的连接状态。

长连接与短连接的操作过程

通常的短连接操作步骤是:

连接→数据传输→关闭连接;

而长连接通常就是:

连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)→……→关闭连接;

这就要求长连接在没有数据通信时,定时发送数据包(心跳),以维持连接状态,短连接在没有数据传输时直接关闭就行了

什么时候用长连接,短连接?

长连接多用于操作频繁,点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接,&nbsp;如果用短连接频繁的通信会造成socket错误,而且频繁的socket&nbsp;创建也是对资源的浪费。

而像WEB网站的http服务一般都用短链接,因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好。

总之,长连接和短连接的选择要视情况而定。

发送接收方式

1、异步

报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况:

(1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收

(2)异步单工:接收和发送是用两个不同的程序来完成。

2、同步

报文发送和接收是同步进行,既报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过该时间发送方不再等待读返回报文,直接通知超时返回。

在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。

单工、半双工和全双工

根据通信双方的分工和信号传输方向可将通信分为三种方式:单工、半双工与全双工。

在计算机网络中主要采用双工方式,其中:局域网采用半双工方式,城域网和广域网采用全双年方式。 

1 单工(Simplex)方式:通信双方设备中发送器与接收器分工明确,只能在由发送器向接收器的单一固定方向上传送数据。采用单工通信的典型发送设备如早期计算机的读卡器,典型的接收设备如打印机。

2.半双工(Half Duplex)方式:通信双方设备既是发送器,也是接收器,两台设备可以相互传送数据,但某一时刻则只能向一个方向传送数据。例如,步话机是半双工设备,因为在一个时刻只能有一方说话。

3. 全双工(Full Duplex)方式:通信双方设备既是发送器,也是接收器,两台设备可以同时在两个方向上传送数据。例如,电话是全双工设备,因为双方可同时说话。

C++指针(我所了解的)

不知何原因,最近老是静不下心来学习,也不知什么原因,突然之间,就很想学一下C/C++(我想:”在我很有兴趣去学习一个东西时候,这不是一件坏事吧”,不过我还是以Java为主),因为很早之前,在我还没有接触过Java时,那时,我对选择学习Java还是C/C++有一个,有一个什么呢?就是学那个好,那时,Java相当的流行,而C/C++又比较难学,特别是C++中的指针,很多人说,相当的复杂,所以我最终选择自学Java.

   这两天,学了指针,感觉并不是像传说的触不可及(但是它确实有点挠,因为指针吗,经常对一个变量指来指去),我觉得,这要规功于我学习了Java,理解了面向对象的含义,如果你理解了什么是对象,如何运用,并了解了引用传递,我认为学习指针,不是难事(如果我说的不对,不要见笑),因为对象也是存在内存的地址中,而引用传递,始终是指向那个内存地址。

   上我的第一个C++程序(在这里要先感谢贺老师无私奉献的知识)

#include <iostream>

using namespace std;

int mainyw();

int main()

{

cout  << “指针运算 ”  << endl;

int a, b;

int *pointer_1, *pointer_2;  //指向整形变量的指针变量

pointer_1 = &a;  //取a变量的地址

pointer_2 = &b;

*pointer_1 = 100;

*pointer_2 = 10;

cout << a << ” ” << b << endl;

cout << *pointer_1 << ” ” << *pointer_2 << endl;

        mainyw();

return 0;

}

int mainyw()

{

int a, b, *p1, *p2, *p;

cin >> a >> b;

p1 = &a;

p2 = &b;

if (a<b)

{

p = p1; p1 = p2; p2 = p;

}

cout << “a=” << a << ” b=” << b << endl;

cout << “max=” << *p1 << ” min=” << *p2 << endl;

return 0;

}

在mian方法中pointer_1 取了a变量的地址,然后,pointer_1指针赋值为100,这时pointer_1指向的地址就是a变量指向的地址,所以,

输出的结果a=100,b=10, pointer_1 =100,pointer_2 =10.

尽管ab没有再赋值,但数据发生变化,原因就地址的作用,所以如果a修改为90,指针变量pointer_1 也是90

#include <iostream>

using namespace std;

int main()

{

cout  << “指针运算 ”  << endl;

int a, b;

int *pointer_1, *pointer_2;  //指向整形变量的指针变量

pointer_1 = &a;  //取a变量的地址

pointer_2 = &b;

*pointer_1 = 100;

*pointer_2 = 10;

cout << a << ” ” << b << endl;

cout << *pointer_1 << ” ” << *pointer_2 << endl;

cout  << “修改a变量 ”  << endl;

a=90;

cout << a << ” ” << b << endl;

cout << *pointer_1 << ” ” << *pointer_2 << endl;

return 0;

}

我们知道,一个函数最多就是返回一个值(数,数组或集合,对象),而现在的myswap函数可以改变传入的两个数的内存地址,

把两个数的内存地址互换,就是a变成b,b变成a,这是不是相当于返回了多个数的效果呢?

#include <iostream>

using namespace std;

void myswap(int *p1, int *p2)

{

int t;

t=*p1;

*p1=*p2;  //这里把地址进行互换

*p2=t;

}

int main()

{

int *point1,*point2,a,b;

cout  << “输入两个数,比较大小 ”  << endl;

cin>>a>>b;

cout<<“a=”<<a<<“,b=”<<b<<endl;

point1=&a;

point2=&b;

if (a<b){

             myswap(point1, point2);

}

cout<<“a=”<<a<<“,b=”<<b<<endl;

    cout<<*point1<<“,”<<*point2<<endl;

}

我最初输入的是2,5,a=2,b=5;myswap函数中把两个数的地址进行互换,这时,指针发生了变化,假如a的地址是x000xf,b的地址是x004xf,

point1 指针原来指向是地址x000xf,现在,是指向了x004xf,而point2指向了x000xf,相应的a.b的值也发生了变化,因为地址改变了,所以,指针传递给myswap的形参,就是引用传递。

可见,指针也是一种多少奇妙的事物,它会让你编程世界多一份意外的风景(如果你运用好的话)

  • 大小: 7 KB
  • 大小: 8.6 KB
  • 大小: 8.5 KB