在解析內存映射章節之前,先明確以下幾個定義說明
物理地址: CPU地址總線上發出的地址,即CPU進行地址空間尋址的地址(作用:用於cpu地址空間尋址).
物理內存: 主板上的物理內存條所提供的內存空間定義為物理內存(嵌入式中一般指DRAM的空間), 它屬於物理地址的一部分, 也就是說每個物理內存單元的實際地址就是物理地址
IO內存: 對外設寄存器的編址方式, 將物理地址的一部分划分出來用作IO地址空間(在這里指, 一類CPU(如Power PC、ARM等)把這些外設寄存器看做是內存的一部分、寄存器參與內存統一編址,通過一般的內存指令來訪問這些外設寄存器,稱為“I/O內存”), 比如imx6dl中gpio寄存器(0x209c000-0x20b7fff), MMDC寄存器(0x21b0000-0x21b3fff)(這里MMDC是DDR控制器)等等都看成IO內存
虛擬地址: 應用程序看到的內存空間定義為虛擬地址空間, 其地址就叫做虛擬地址. 虛擬地址是硬件MMU與軟件內存管理結合的產物,方便更高效率的使用RAM. 即需要MMU(內存管理單元)的支持.
注意: 不管是在linux還是windows下編程,程序所操作地址都是虛擬地址。
這里以imx6dl芯片為例, imx6dl系統內存映射如下圖
從圖中可知系統內存映射共4G: 0x00000000 - 0xFFFFFFFF, 即CPU可尋址范圍為0 - 4G, 也就是說物理地址為0 - 4G
物理內存范圍是0x10000000 - 0xFFFFFFFF共3G, 即理論上可外接3G內存DDR, 實際接多大看具體應用, 比如外接了1G內存DDR
IO內存比如GPIO的寄存器范圍是0x2090000 - 0x20B7FFF, I2C, SPI, IPU等等IO內存
這里着重分析下物理內存, 即CPU是如何尋址DDR的, 以下是項目中系統外接了1GB的DDR, 注意下面第一張是CPU內部的DDR控制器, 第二張是DDR(NT5CC256M16DP有DRAM_A14 pin腳, 但是原理圖中用的NT5CC128M16DP封裝, 所以少了DRAM_A14 pin腳, 實際PCB中DRAM_A14也連接上了DDR控制器, 只是原理圖的封裝沒畫出來)
由此可知, DDR控制器外接了兩片DDR, DDR型號為NT5CC256M16DP, 硬件連接如下:
第一片16bit DDR3的BA0,BA1,BA2連接CPU DDR控制器的BA0, BA1, BA2
第二片16bit DDR3 的BA0,BA1,BA2連接CPU DDR控制器的BA0, BA1, BA2
第一片16bit DDR3的A0~A14連接CPU DDR控制器的A0~A14
第二片16bit DDR3的A0~A14連接CPU DDR控制器的A0~A14
第一片16bit DDR3的D0~D15連接CPU DDR控制器的D0~D15
第二片16bit DDR3的D0~D15連接CPU的D16~D31
由型號可知一片DDR大小為:4Gbit, 分析如下
有8個banks ---> 3根bank地址線, BA0, BA1, BA2 ---> 8 = 2^3
從datasheet分析有15bit row行地址, 10bit coloumn列地址, 所以每個bank有32M(2^15*2^10)個單元格(基本存儲單位), 即每個bank有32M個地址可尋, 且每個單元格占16bit
所以一片DDR共有32M * 8 = 256M個地址可尋
所以一片DDR總大小為32M * 16bit * 8 = 4Gbit
由型號可知一片DDR大小為:4Gbit, 分析如下
bank地址線是3bit所以單個16bit DDR3內部有8個bank(BA0, BA1, BA2 ---> 8 = 2^3)
行地址(row)A0~A14共15bit說明每個bank有2^15行
列地址(column)A0~A9共10bit說明每個bank有2^10列
每個bank有32M(2^15*2^10)個單元格(基本存儲單位), 也就是每個bank有32M個地址可尋, 每個bank大小是2^15 * 2^10 * 16bit = 32M * 16bit = 64MB
所以一片DDR共有32M * 8 = 256M個地址可尋
所以單個16bit DDR3芯片容量總大小是32M * 16bit * 8 = 4Gbit
從前面的連線可知兩塊16bit DDR3的BA0~BA2和A0~A13是並行連接到內存控制器,所以內存控制器認為只有一塊內存,訪問的時候按照BA0~BA2和A0~A13給出地址。兩塊16bit DDR3都收到了該地址,給出的反應是要么將給定地址上的2個字節讀到數據線上,要么是將數據線上的兩個字節寫入到指定的地址。
此時內存控制器認為自己成功的訪問的了一塊32bit的內存,
所以內存控制器每給出一個地址,將訪問4個字節的數據,讀取/寫入。這4字節數據對應到內存控制器的D0~D31,又分別被連接到兩片DDR3芯片的D0~D15,這樣32bit就被拆成了兩個16bit分別去訪問單個DDR3芯片的基本存儲單元。 所以說這種接法只能4字節(32位)訪問(Only 32-bit access is supported), 與GPIO內存映射一樣的, 就是說內存訪問地址只能+4, 比如GPIO內存地址是0x209c000 -> 0x209c004 -> 0x209c008... 地址只能4字節增加. 這里這種DDR接法也限定了訪問內存地址只能4字節增加
注意:盡管每個DDR3芯片識別的地址只有256M(由上面可知2^15 * 2^10 * 8= 256M)個,但由於內存控制器每訪問一個內存地址,將訪問4個字節數據,所以對於內存控制器來說,能訪問的內存大小仍是1GB,只不過在內存控制器將地址傳給DDR3芯片時,低兩位被忽略,也就是說DDR3芯片識別的地址只有256M個。
比如內存控制器訪問地址0x00000000,0x00000001,0x00000002,0x00000003,但對DDR3來說,都是訪問地址0x00000000
我們可以通過以下命令獲取到內存映射表(其實就是對應用戶應用手冊中的memory map章節):
cat /proc/iomem
00110000-00111fff : /soc/dma-apbh@00110000
00120000-00128fff : 120000.hdmi_core
00905000-0091ffff : /soc/sram@00905000
02008000-0200bfff : /soc/aips-bus@02000000/spba-bus@02000000/ecspi@02008000
0200c000-0200ffff : /soc/aips-bus@02000000/spba-bus@02000000/ecspi@0200c000
02020000-02023fff : /soc/aips-bus@02000000/spba-bus@02000000/serial@02020000
02080000-02083fff : /soc/aips-bus@02000000/pwm@02080000
02084000-02087fff : /soc/aips-bus@02000000/pwm@02084000
02088000-0208bfff : /soc/aips-bus@02000000/pwm@02088000
0208c000-0208ffff : /soc/aips-bus@02000000/pwm@0208c000
02090000-02093fff : /soc/aips-bus@02000000/can@02090000
0209c000-0209ffff : /soc/aips-bus@02000000/gpio@0209c000
020a0000-020a3fff : /soc/aips-bus@02000000/gpio@020a0000
020a4000-020a7fff : /soc/aips-bus@02000000/gpio@020a4000
020a8000-020abfff : /soc/aips-bus@02000000/gpio@020a8000
020ac000-020affff : /soc/aips-bus@02000000/gpio@020ac000
020b0000-020b3fff : /soc/aips-bus@02000000/gpio@020b0000
020b4000-020b7fff : /soc/aips-bus@02000000/gpio@020b4000
020c0000-020c3fff : /soc/aips-bus@02000000/wdog@020c0000
020c9000-020c9fff : /soc/aips-bus@02000000/usbphy@020c9000
020ca000-020cafff : /soc/aips-bus@02000000/usbphy@020ca000
020cc034-020cc08b : /soc/aips-bus@02000000/snvs@020cc000/snvs-rtc-lp@34
020e0000-020e3fff : /soc/aips-bus@02000000/iomuxc@020e0000
020ec000-020effff : 20ec000.sdma
020f0000-020f3fff : /soc/aips-bus@02000000/pxp@020f0000
02184000-021841ff : /soc/aips-bus@02100000/usb@02184000
02184000-021841ff : /soc/aips-bus@02100000/usb@02184000
02184200-021843ff : /soc/aips-bus@02100000/usb@02184200
02184200-021843ff : /soc/aips-bus@02100000/usb@02184200
02184800-021849ff : /soc/aips-bus@02100000/usbmisc@02184800
02188000-0218bfff : /soc/aips-bus@02100000/ethernet@02188000
02198000-0219bfff : mmc2
0219c000-0219ffff : mmc3
021a0000-021a3fff : /soc/aips-bus@02100000/i2c@021a0000
021a4000-021a7fff : /soc/aips-bus@02100000/i2c@021a4000
021a8000-021abfff : /soc/aips-bus@02100000/i2c@021a8000
021b8000-021bbfff : /soc/aips-bus@02100000/weim@021b8000
021bc000-021bffff : /soc/aips-bus@02100000/ocotp-fuse@021bc000
021d8000-021dbfff : /soc/aips-bus@02100000/audmux@021d8000
021e4000-021e7fff : /soc/aips-bus@02100000/vdoa@021e4000
021ec000-021effff : /soc/aips-bus@02100000/serial@021ec000
021f4000-021f7fff : /soc/aips-bus@02100000/serial@021f4000
02400000-027fffff : 2400000.ipu
10000000-4fffffff : System RAM
10008000-1088e217 : Kernel code
108e2000-1099e69b : Kernel data
“System RAM” 就是物理內存(DRAM)的空間, 0x10000000 - 0x4fffffff共1GB(就是實際DRAM接了1GB的內存條)
另注意: 市面上說的手機內存有兩種含義, 一種是系統內存RAM, 一種是存儲內存ROM, 手機的運行速度跟系統內存RAM大小有關, 而系統存放文件大小跟存儲內存ROM有關. 還有系統 內存理論大小跟CPU處理器地址線位寬有關, 比如32位的處理器, 它的理論系統內存可達到4G, 64位的處理器, 他的理論系統內存可達到2^64bit(足夠大). 還有就是說手機系統內存4G, 其實手機運行內存肯定不足4G, 因為系統會占用一部分內存(比如外設會占用IO內存), 而真正划分給運行內存的大小(即外接DDR的大小)會小於4G. 因為應用程序代碼是運行在DDR上的,所以真正影響手機速度的是運行內存大小.