1. 前言
總線設(shè)計中經(jīng)常會發(fā)生死鎖,關(guān)鍵死鎖場景還不一定好發(fā)現(xiàn),而且也不好依賴激勵去打出來,很多時候要靠正向分析去發(fā)現(xiàn)。本文分享一個AXI總線中比較容易發(fā)生死鎖的場景。
2. 死鎖場景
如圖1所示,有一個2-to-2的AXI總線,上面接兩個AXI master,下面接兩個AXI slave。AXI master1依次發(fā)起A1和A2寫操作,其中A1是去訪問AXI slave2,A2是去訪問AXI slave1。AXI master2依次發(fā)起B(yǎng)1和B2寫操作,其中B1是去訪問AXI slave1,B2是去訪問AXI slave2。AXI slave1口上接收到的寫順序是先A2后B1,AXI slave2口上接收到的寫順序是先B2后A1。
圖1 2-to-2 AXI總線
假設(shè)Write buffer1深度為8,Write buffer2深度也為8,也就是它們各自可以存儲8個beat的write data。A1和B1的burst length為9,也就是A1和B1分別會發(fā)送10 beat的write data。
我們從AXI slave和AXI master口來看:
A2先于B1到達(dá),根據(jù)AXI協(xié)議(write address和write data順序要一致),因此A2的write data必須先于B1發(fā)送給AXI slave1。
A2的write data會依賴于A1的write data被總線全部接收,但是因為Write buffer1深度只有8,只能暫時接收8個beat A1的write data。
A1在Write buffer1中的write data要發(fā)送到AXI slave2口上,必須要等B2的write data全部發(fā)送完到AXI slave2上。
B2的write data會依賴于B1的write data被總線全部接收,但是因為Write buffer1深度只有8,只能暫時接收8個beat B1的write data。
B1的write data必須等A2的write data發(fā)送完之后,才能發(fā)送到AXI slave1口。
因此,一個死鎖場景就發(fā)生了,如圖2所示,①依賴于②,②依賴于③,③依賴于④,④依賴于①,一個環(huán)形資源依賴(①→②→③→④→①)產(chǎn)生了。這個死鎖產(chǎn)生的本質(zhì)是:
AXI協(xié)議規(guī)定AXI write和AXI data的順序必須要一致;
Write buffer深度不夠;
圖2 2-to-2 AXI總線死鎖示意圖
3. 解決辦法
這個死鎖比較常見,也比較好解決,可以通過以下幾種方式:
把SLV1或SLV2的outstanding能力限制為1,這樣會對總線的performance影響很大;如果限制SLV1為1,那么A2就不會出現(xiàn)在AXI slave1口上了,B1就可以正常完成,進(jìn)而B2和A1也可以完成,打斷了死鎖鏈條。
把Write buffer的深度加大,使它們至少能各自容納A1和B1的全部write data beat,這樣會使總線的面積增大很多;Write buffer1把A1的write data全部接收之后,就可以轉(zhuǎn)發(fā)A2的write data給AXI slave1口,因此A2就可以正常完成了,進(jìn)而B1、B2和A1也可以完成,打斷了死鎖鏈條
在總線內(nèi)部做hazard的檢查,如果發(fā)現(xiàn)有任何未完成的寫操作到不同的接口,那么就先把當(dāng)前的write操作擋住不往下發(fā),這個方法的應(yīng)用比較多??偩€在收到A2時發(fā)現(xiàn)A1已經(jīng)發(fā)給AXI slave2口,但A2是打算發(fā)給AXI slave1口,因此總線就先把A2擋在內(nèi)部,暫時不發(fā)給AXI slave1口。等A1結(jié)束后,再把A2發(fā)給AXI slave1口;對B1和B2的處理也類似,從而打斷了死鎖鏈條。