weiqi7777

关于地址加1的问题

0
阅读(3849)

在学习S3C6410 MMU的地址映射的时候,竟然被地址加1的问题给卡住了。

先贴源代码


void create_page_table(void)
{
    unsigned long *ttb = (unsigned long *)0x50000000;
    unsigned long vaddr, paddr;
    vaddr = 0x50000000;
    paddr = 0x50000000;
    while (vaddr < 0x54000000)
    {
		*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000);       
		vaddr += 0x100000;
                paddr += 0x100000;
    }
}

这里ttb是第一级表的首地址,为外部内存的首地址,S3C6410为0x50000000。然后建立一个映射表。

在while第一次循环的时候,vaddr>>20 为0x500,就相当于往0x50000500写入后面的数据,执行第二次的时候,vaddr>>20为0x501,就相当于往0x50000501写入后面的数据。等等,问题来了,arm对地址要求是4字节对齐的,怎么会有0x50000501这个地址了。

肯定是什么地方出现问题,但是代码是没有问题的,看来就是自己理解的问题。

最后,在别人的帮助下,才发现问题的所在。

原来地址加1和数据加1是不一样的。地址加1,要看是什么数据类型,不同的数据类型加的值不一样,对于int而言,地址加1就相当于地址加4。而数据加1就是单纯的数据加1。

这里ttb是unsigned long的指针,是占4个字节的。所以ttb在加1的时候,其实是会加4的,而加常数n的话,其实是会加n*4的。

循环第一次,vaddr >> 20的值为0x500,因为是和指针ttb相加,所以这个值要先乘以4在和ttb相加。0x500 * 4 = 0x1400。然后再和ttb相加,这个时候加的结果为0x50001400。这才是真正的地址,也是往这个地址写值的。循环第二次,vaddr >> 20的值0x501,因为是和指针ttb相加,所以这个值也先要先乘以4在和ttb相加。0x501 * 4 = 0x1404,在和ttb相加,这个时候加的结果为0x50001404。这个也才是真正的地址,也是往这个地址写值的。这样下来,写的地址才是4字节对齐的。

看来自己的C语言功底还不行啊。

用VS仿真了看看。

int main(void)
{
	unsigned long *ttb = (unsigned long *)0x50000000;
	unsigned long *address;
	unsigned long vaddr = 0x50000000;
	unsigned long paddr = 0x50000000;
	while (vaddr < 0x54000000)
	{
		address = ttb + (vaddr >> 20);
		vaddr += 0x100000;
		paddr += 0x100000;
	}
}

调试结果

循环第一次

clip_image001

看出ttb + (vaddr >> 20)的值是0x50001400

循环第二次

clip_image003

看出ttb + (vaddr >> 20)的值是0x50001404

循环第三次

clip_image004

看出ttb + (vaddr >> 20)的值是0x50001404

以前,学C语言的时候,书上说地址加常数的话,要看地址的类型,然后再把常数乘以类型的字节数在和地址相加,也没有注意这个细节。这个在这里可就遇到问题了。

所以说,地址和常数相加的时候,要看地址的数据类型是什么,然后再将乘数乘以类型的字节数,最后在和地址相加。