0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

先楫 HPM片上 Cache使用指南

先楫半導(dǎo)體HPMicro ? 2024-01-26 10:00 ? 次閱讀

賈 工

先楫資深FAE工程師

12年產(chǎn)品研發(fā)經(jīng)驗(yàn),具有變頻器、伺服等工業(yè)產(chǎn)品開發(fā)經(jīng)驗(yàn),也負(fù)責(zé)過激光投影顯示系統(tǒng)開發(fā)、AI應(yīng)用開發(fā)、PYQT、Linux驅(qū)動開發(fā)等工作。

概 述

高速緩存(Cache)主要是為了解決CPU運(yùn)算速度與內(nèi)存(Memory)讀寫速度不匹配的矛盾而存在, 是CPU與存儲設(shè)備之間的臨時存貯器,容量小,但是交換速度比內(nèi)存快。內(nèi)置高速緩存通常對CPU的性能提升具有較大作用。

CPU要讀取一個數(shù)據(jù)時,首先從Cache中查找,如果找到就立即讀取并送給CPU處理;如果沒有找到,就用相對慢的速度從內(nèi)存中讀取并送給CPU處理,同時把這個數(shù)據(jù)所在的數(shù)據(jù)塊調(diào)入Cache中,可以使得以后對整塊數(shù)據(jù)的讀取都從Cache中進(jìn)行,不必再調(diào)用內(nèi)存。

ab2fa59e-bbee-11ee-aa22-92fbcf53809c.png

這樣的讀取機(jī)制使CPU讀取Cache的命中率非常高(大多數(shù)CPU可達(dá)90%左右),也就是說CPU下一次要讀取的數(shù)據(jù)90%都在Cache中,只有大約10%需要從內(nèi)存讀取。HPM CPU訪問片上的Cache內(nèi)數(shù)據(jù)是零等待的,這大大節(jié)省了CPU直接讀取內(nèi)存數(shù)據(jù)的時間,使CPU讀取數(shù)據(jù)時基本無需等待??偟膩碚f,CPU讀取數(shù)據(jù)的順序是先Cache后存儲設(shè)備。

一、Cacheable Memory 相關(guān)概念

在訪問HPM片上ILM與DLM(Local Memory)時,芯片物理結(jié)構(gòu)決定了CPU不會使用Cache去緩存Local Memory的數(shù)據(jù)。訪問其它存儲設(shè)備如flash、sram、sdram等,則Cache可以發(fā)揮其緩存機(jī)制來加快訪問速度。在Cache生效的地址空間內(nèi),用戶可以設(shè)置Memory的物理存儲屬性來設(shè)置是否對指定的地址空間使用Cache。

ab3c8322-bbee-11ee-aa22-92fbcf53809c.png

PMA(Physical Memory Attributes)是指一段存儲地址空間的可讀寫、可執(zhí)行、可緩存等屬性。讀、寫、執(zhí)行等屬性容易理解,此處不贅述。下面介紹幾個其它屬性及相關(guān)的概念。(注意:HPM5300系列不支持PMA設(shè)置)

首先介紹一些Cache基本概念。

1. Cache Line/dirty/invalidate

Cache Line:一次最少緩存多少字節(jié)的數(shù)據(jù)是有要求的,通常以Cache Line為單位。HPM6000系列MCU Cache Line為64byte,HPM5300系列MCU Cache Line為32byte。在進(jìn)行PMA設(shè)置時,要求起始地址按Cache Line字節(jié)數(shù)對齊,大小為Cache Line大小的整數(shù)倍。聲明數(shù)組時最好也遵循此規(guī)則。

Dirty:表示某Cache Line的數(shù)據(jù)是否與Memory保持一致,如果只將數(shù)據(jù)寫入Cache而沒有寫入Memory,會將該Cache Line標(biāo)記為dirty。

Invalidate:將某地址范圍的Cache Line數(shù)據(jù)失效掉,當(dāng)Cache Line狀態(tài)被Invalidate時,不管讀取是否命中,CPU都會到Memory拿數(shù)據(jù)。

對Cache的標(biāo)準(zhǔn)操作包括 write-back,invalidate,flush。

Write-back表示把cache內(nèi)dirty的數(shù)據(jù)寫入Memory,invalidate表示忽略某地址范圍的Cache line,flush操作則先對某Cache Line 進(jìn)行write-back操作,再進(jìn)行invalidate操作。HPM SDK的hpm_l1c_drv.h文件提供了這3種操作的接口函數(shù)。

2. Bufferable

Bufferable是指MCU在寫入一片內(nèi)存區(qū)時,是否可使用Write buffer進(jìn)行加速。例如向sram內(nèi)寫入64個字節(jié):

1)不使用Bufferable:CPU等待64字節(jié)數(shù)據(jù)寫入完成后再去執(zhí)行其它指令;

2)使用Bufferable:CPU將64字節(jié)數(shù)據(jù)寫入Write buffer,不等Write buffer內(nèi)的數(shù)據(jù)寫入sram,CPU就去執(zhí)行其它指令;寫入動作則自動進(jìn)行直至完成。

3. Cacheable

Cacheable與 non-Cacheable,決定了CPU是否啟用緩存特性。如果啟用Cacheable特性,則HPM芯片上的內(nèi)存區(qū)域可以分區(qū)指定PMA,可選的屬性選項如下(詳細(xì)信息可參考先楫官方文檔HPM6200 UM 2.8章節(jié)):

Write-Back

Write-Back(與Write-Through互斥)是指向存儲設(shè)備內(nèi)寫數(shù)據(jù)命中時,CPU將數(shù)據(jù)寫入Cache,并不立馬向存儲設(shè)備寫入數(shù)據(jù),如下圖所示:數(shù)據(jù)先寫入到Cache內(nèi)(①),在Cache內(nèi)標(biāo)記該Cache Line為dirty,即表示該Cache Line內(nèi)容與Memory內(nèi)容不符;Cache內(nèi)數(shù)據(jù)寫入Memory(②),則在Cache Line被替換或手動執(zhí)行write-back操作或flush操作時(把dirty的數(shù)據(jù)寫入Memory)才執(zhí)行。

未命中時,則寫入Memory。是否寫入Cache 由xxx-Allocate決定。

ab411568-bbee-11ee-aa22-92fbcf53809c.png

Write-Through

Write-Through(與Write-Back互斥)是指向存儲設(shè)備內(nèi)寫數(shù)據(jù)時,無論命中與否,CPU都將數(shù)據(jù)寫入Memory。

命中時,數(shù)據(jù)同時寫入Cache 與Memory;

未命中時,數(shù)據(jù)寫入Memory,是否寫入Cache 由xxx-Allocate決定。

xxx-Allocate

xxx-Allocate則用于控制讀/寫未命中Cache時,是否要在Cache內(nèi)申請Cache Line用于緩存讀/寫的數(shù)據(jù)。例如:

Read-Allocate代表讀未命中時,CPU不只從Memory將數(shù)據(jù)讀入,還將數(shù)據(jù)在Cache放了一份,那么下次再讀的時候就不用去Memory讀了;

Write-Allocate代表寫未命中時,會在Cache內(nèi)分配Cache Line儲存寫入的數(shù)據(jù),那么下次讀的時候就可以從Cache讀了;具體是否寫入Memory取決于使用的是Write-Back還是Write-Through。

Non-Allocate和 Read-and-Write-Allocate就不再進(jìn)行解釋了。

/* Init noncachable memory */

externuint32_t__noncacheable_start__[];

externuint32_t__noncacheable_end__[];

start_addr = (uint32_t) __noncacheable_start__;

end_addr = (uint32_t) __noncacheable_end__;

length = end_addr - start_addr;

if(length > 0) {

/* Ensure the address and the length are power of 2 aligned */

assert((length & (length - 1U)) == 0U);

assert((start_addr & (length - 1U)) == 0U);

pmp_entry[index].pmp_addr= PMP_NAPOT_ADDR(start_addr, length);

pmp_entry[index].pmp_cfg.val= PMP_CFG(READ_EN, WRITE_EN, EXECUTE_EN, ADDR_MATCH_NAPOT, REG_UNLOCK);

pmp_entry[index].pma_addr= PMA_NAPOT_ADDR(start_addr, length);

pmp_entry[index].pma_cfg.val= PMA_CFG(ADDR_MATCH_NAPOT, MEM_TYPE_MEM_NON_CACHE_BUF, AMO_EN);

index++;

}

pmp_config(&pmp_entry[0], index);

以上代碼設(shè)置了__noncacheable_start__至__noncacheable_end__地址范圍內(nèi)的存儲區(qū)域PMA屬性為noncacheable,bufferable。

通過以上解釋,相信開發(fā)者可以看懂UM手冊內(nèi)的相關(guān)描述了,以HPM6200系列為例,User Manual v2.0 2.8章節(jié)的內(nèi)容對PMA有詳細(xì)描述。

二、HPM L1-Cache相關(guān)函數(shù)


HPM系列芯片L1-Cache分為 iCache與 dCache,指令緩存與數(shù)據(jù)緩存。開發(fā)者們經(jīng)常遇到的問題是開啟dCache導(dǎo)致的CPU拿到的數(shù)據(jù)與Memory內(nèi)數(shù)據(jù)不一致(Cache內(nèi)的數(shù)據(jù)與Memory不一致時,讀取命中Cache會發(fā)生這樣的結(jié)果)。因此,此處主要介紹 dCache相關(guān)函數(shù)。

打開hpm_l1c_drv.h文件即可看到先楫提供的Cache相關(guān)的函數(shù),部分如下:

*

* @brief D-cache disable

*/

voidl1c_dc_disable(void);

/*

* @brief D-cache enable

*/

voidl1c_dc_enable(void);

/*

* @brief D-cache invalidate by address

* @param[in] address Start address to be invalidated

* @param[in] size Size of memory to be invalidated

*/

voidl1c_dc_invalidate(uint32_taddress, uint32_tsize);

/*

* @brief D-cache writeback by address

* @param[in] address Start address to be writtenback

* @param[in] size Size of memory to be writtenback

*/

voidl1c_dc_writeback(uint32_taddress, uint32_tsize);

/*

* @brief D-cache invalidate and writeback by address

* @param[in] address Start address to be invalidated and writtenback

* @param[in] size Size of memory to be invalidted and writtenback

*/

voidl1c_dc_flush(uint32_taddress, uint32_tsize);

/*

* @brief D-cache fill and lock by address

* @param[in] address Start address to be filled and locked

* @param[in] size Size of memory to be filled and locked

*/

voidl1c_dc_fill_lock(uint32_taddress, uint32_tsize);

/*

* @brief Invalidate all icache and writeback all dcache

*/

voidl1c_fence_i(void);

/*

* @brief Invalidate all d-cache

*/

voidl1c_dc_invalidate_all(void);

/*

* @brief Writeback all d-cache

*/

voidl1c_dc_writeback_all(void);

/*

* @brief Flush all d-cache

*/

voidl1c_dc_flush_all(void);

l1c_dc_disable:關(guān)閉dCache。此函數(shù)特別有用,在debug時如果懷疑是Cache導(dǎo)致的問題,在main函數(shù)開始關(guān)閉dCache再次運(yùn)行即可排查是否是Cache導(dǎo)致的問題。注意,如果是用戶程序運(yùn)行過程中關(guān)閉dCache,需要在關(guān)閉前將執(zhí)行l(wèi)1c_dc_writeback_all,保證Cache數(shù)據(jù)寫入Memory。

l1c_dc_enable:開啟dCache。

l1c_dc_invalidate:將某地址范圍內(nèi)的Cache Line失效掉。無論某地址在Cache內(nèi)是否命中,CPU會從Memory內(nèi)拿數(shù)據(jù)。

l1c_dc_writeback:將Cache內(nèi)數(shù)據(jù)寫入某Memory地址。如果該地址在Cache內(nèi),則將該Cache Line寫入Memory,并清除dirty標(biāo)志。

l1c_dc_flush:該函數(shù)等于 l1c_dc_writeback + l1c_dc_invalidate,把數(shù)據(jù)寫入到Memory并標(biāo)記為invalidate,表示下次從Memory拿數(shù)據(jù)時不走Cache。

l1c_fence_i:將dCache內(nèi)的數(shù)據(jù)全部writeback,將iCache內(nèi)所有Cache Line invalidate。一般關(guān)閉Cache前會手動調(diào)用此函數(shù)。

l1c_dc_invalidate_all、l1c_dc_writeback_all、l1c_dc_flush_all:代表操作整個Cache中的Cache Line,具體含義不再贅述。

三、經(jīng)驗(yàn)分享

l1c_dc_writeback:一般非CPU的總線host,如DMA訪問某Memory地址前,通過l1c_dc_writeback將Cache內(nèi)的數(shù)據(jù)寫到Memory,保證DMA拿到的數(shù)據(jù)與CPU看到的數(shù)據(jù)是一致的。

例如I2C_DMA例程:

/* setup i2c dma tx */

#ifPLACE_BUFF_AT_CACHEABLE

if(l1c_dc_is_enabled()) {

/* cache writeback before DMA sent data */

l1c_dc_writeback((uint32_t)tx_buff, TEST_TRANSFER_DATA_IN_BYTE);

}

#endif

stat= i2c_tx_trigger_dma(TEST_I2C_DMA,

TEST_I2C_DMA_CH,

TEST_I2C,

core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)tx_buff),

TEST_TRANSFER_DATA_IN_BYTE);

if(stat!= status_success) {

printf("i2c tx trigger dma failed\n");

while(1) {

}

}

在DMA將tx_buff數(shù)據(jù)搬到I2C的發(fā)送寄存器之前,進(jìn)行了writeback。

l1c_dc_invalidate:一般CPU在讀取Memory數(shù)據(jù)時,如果該數(shù)據(jù)被其它總線host如DMA操作過(一般是DMA搬了某些數(shù)據(jù)過去),為了能讀到Memory中的數(shù)據(jù)而不是Cache中的數(shù)據(jù),要在讀取之前對Cache Line進(jìn)行invalidate處理(多數(shù)開發(fā)者遇到的都是這個問題)。

例如I2C_DMA例程:

/* setup i2c dma rx */

stat= i2c_rx_trigger_dma(TEST_I2C_DMA,

TEST_I2C_DMA_CH,

TEST_I2C,

core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)rx_buff),

TEST_TRANSFER_DATA_IN_BYTE);

i2c_master_start_dma_read(TEST_I2C, TEST_I2C_SLAVE_ADDRESS, TEST_TRANSFER_DATA_IN_BYTE);

i2c_handle_dma_transfer_complete(TEST_I2C);

#ifPLACE_BUFF_AT_CACHEABLE

if(l1c_dc_is_enabled()) {

/* cache invalidate after DMA receive data */

l1c_dc_invalidate((uint32_t)rx_buff, TEST_TRANSFER_DATA_IN_BYTE);

}

#endif

check_transfer_data();

在進(jìn)行check_transfer_data之前,先對數(shù)據(jù)進(jìn)行了l1c_dc_invalidate處理。

l1c_fence_i:一般在CPU關(guān)閉Cache之前,或程序跳轉(zhuǎn)之前(一般二級boot選擇好要執(zhí)行的固件進(jìn)行跳轉(zhuǎn)),為了保證所有dirty的Cache Line寫入到Memory中,會進(jìn)行l(wèi)1c_dc_writeback_all,然后等 l1c_dc_writeback_all執(zhí)行完畢后再跳轉(zhuǎn)。

例如tinyuf2例程:

voiduf2_board_app_jump(void)

{

fencei();

l1c_dc_disable();

l1c_ic_disable();

__asm("la a0, %0"::"i"(BOARD_FLASH_APP_START+ 4));

__asm("jr a0");

}

uf2_board_app_jump函數(shù)在跳轉(zhuǎn)前,執(zhí)行了fencei,本質(zhì)上就是l1c_fence_i。

另外,在執(zhí)行writeback操作期間中斷不可用,對實(shí)時性要求高的場景應(yīng)進(jìn)行合理規(guī)劃l1c_dc_writeback_all的使用。

四、文末小結(jié)

Cache能大幅提高程序運(yùn)行性能,但用不好Cache也會給開發(fā)者帶來各種“奇奇怪怪”的問題現(xiàn)象。在閱讀本文后,希望開發(fā)者對先楫的 L1-Cache有更深入的理解,使用先楫半導(dǎo)體高性能 MCU系列產(chǎn)品開發(fā)項目時,能更加得心應(yīng)手。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Cache
    +關(guān)注

    關(guān)注

    0

    文章

    129

    瀏覽量

    28344
  • HPM
    HPM
    +關(guān)注

    關(guān)注

    1

    文章

    23

    瀏覽量

    7747
  • 先楫半導(dǎo)體
    +關(guān)注

    關(guān)注

    10

    文章

    214

    瀏覽量

    2120
收藏 人收藏

    評論

    相關(guān)推薦

    HPMCache使用指南經(jīng)驗(yàn)分享

    高速緩存(Cache)主要是為了解決CPU運(yùn)算速度與內(nèi)存(Memory)讀寫速度不匹配的矛盾而存在, 是CPU與存儲設(shè)備之間的臨時存貯器,容量小,但是交換速度比內(nèi)存快。內(nèi)置高速緩存通常對CPU的性能提升具有較大作用。
    的頭像 發(fā)表于 01-22 16:07 ?1315次閱讀
    <b class='flag-5'>先</b><b class='flag-5'>楫</b><b class='flag-5'>HPM</b><b class='flag-5'>片</b><b class='flag-5'>上</b><b class='flag-5'>Cache</b><b class='flag-5'>使用指南</b>經(jīng)驗(yàn)分享

    基于HPM5300 RISC-V內(nèi)核MCU的HPM5361EVK開發(fā)板測評效果(二)

    HPM5361EVK是基于HPM5300系列高性能RISC-V內(nèi)核MCU的一款開發(fā)板。
    的頭像 發(fā)表于 03-12 10:30 ?2916次閱讀
    基于<b class='flag-5'>先</b><b class='flag-5'>楫</b><b class='flag-5'>HPM</b>5300 RISC-V內(nèi)核MCU的<b class='flag-5'>HPM</b>5361EVK開發(fā)板測評效果(二)

    HPM5361EVK開發(fā)板試用體驗(yàn)】認(rèn)識和了解HPM5361EVK開發(fā)板

    ,拆開第一眼看到HPM5361EVK開發(fā)板,黑色的多層主板主控芯片和其它元件排列整齊,做工非常精細(xì),元件布局合理,元件標(biāo)識清晰,提供的io接口和調(diào)試接口非常豐富。
    發(fā)表于 12-24 22:39

    HPM5361EVK開發(fā)板試用體驗(yàn)】HPM5361EVK開發(fā)板初體驗(yàn)

    收到HPM5361EVK開發(fā)板,被HPM5361EVK開發(fā)板的做工和電路板設(shè)計驚艷到了,
    發(fā)表于 12-24 22:58

    如何使用CodeViser調(diào)試HPM6750開發(fā)板?

    HPM6750EVK2是基于半導(dǎo)體的HPM6750高性能SOC的開發(fā)板,HPM6750是基于RISC-V的雙核處理器,主頻高達(dá)816M。
    發(fā)表于 03-21 16:35

    HPM6000系列微控制器的各類SRAM使用指南

    HPM6000系列微控制器SRAM使用指南
    發(fā)表于 06-01 06:19

    HPM6000系列微控制器閃存使用指南

    HPM6000系列MCUFlash使用指南
    發(fā)表于 06-01 06:20

    HPM6000系列微控制器閃存使用指南

    HPM6000系列MCUFlash使用指南
    發(fā)表于 06-02 08:54

    半導(dǎo)體HPM5361EVK開發(fā)板開發(fā)資料免費(fèi)下載

    HPM5300EVK 提供了一系列 HPM5300 微控制器外設(shè)的接口,包括一個 ADC 輸入 SMA 接口和一個標(biāo)準(zhǔn)的電機(jī)控制及傳感器接口。H
    發(fā)表于 10-20 11:21

    HPM5361EVK開發(fā)板試用體驗(yàn)】-- HPM5361初體驗(yàn)

    HPM5361EVK開發(fā)板試用體驗(yàn)】-- HPM5361初體驗(yàn)
    發(fā)表于 12-11 10:27

    HPM6000系列雙核MCU怎么玩?

    核產(chǎn)品,集成 2 個 RISC-V 處理器,其中HPM6700系列兩個核的最高主頻都可以達(dá)到816MHz。本文通過對HPM6000系列雙核的使用方法、工程編譯與調(diào)試、雙核通信方式和
    的頭像 發(fā)表于 05-10 14:25 ?1671次閱讀
    <b class='flag-5'>先</b><b class='flag-5'>楫</b><b class='flag-5'>HPM</b>6000系列雙核MCU怎么玩?

    HPM6300 新品量產(chǎn)上市

    中國上海(2022年7月19日)——業(yè)界領(lǐng)先高性能通用MCU廠商上海半導(dǎo)體宣布HPM6300系列新品HPM6340于2022年7月正式量產(chǎn)上市,以此拓寬
    的頭像 發(fā)表于 07-21 09:37 ?1487次閱讀
    <b class='flag-5'>先</b><b class='flag-5'>楫</b> <b class='flag-5'>HPM</b>6300 新品量產(chǎn)上市

    [HPM雜談]你想要了解的hpm_sdk開發(fā)都在這里系列 (二)

    一、概述在上一篇雜談文章《[HPM雜談]你想要了解的hpm_sdk開發(fā)都在這里系列(一)》,大概分析了
    的頭像 發(fā)表于 10-12 08:18 ?1697次閱讀
    [<b class='flag-5'>HPM</b>雜談]你想要了解的<b class='flag-5'>先</b><b class='flag-5'>楫</b><b class='flag-5'>hpm</b>_sdk開發(fā)都在這里系列 (二)

    半導(dǎo)體 hpm_sdk v1.5.0 正式發(fā)布

    半導(dǎo)體 hpm_sdk v1.5.0 正式發(fā)布
    的頭像 發(fā)表于 04-12 08:17 ?593次閱讀
    <b class='flag-5'>先</b><b class='flag-5'>楫</b>半導(dǎo)體 <b class='flag-5'>hpm</b>_sdk v1.5.0 正式發(fā)布

    半導(dǎo)體hpm_apps v1.6.0上線

    半導(dǎo)體hpm_apps v1.6.0上線
    的頭像 發(fā)表于 08-02 08:18 ?821次閱讀
    <b class='flag-5'>先</b><b class='flag-5'>楫</b>半導(dǎo)體<b class='flag-5'>hpm</b>_apps v1.6.0上線