Compare commits

..

3 Commits

Author SHA1 Message Date
yeximing f6057a282c
Add reset for all fixture (#141)
* Revise smoke test for adjusting reset

* Add reset for fixture
2025-07-01 19:19:47 +08:00
CharlesJunic 0c723d86f7
update itlb env (#138)
* update itlb env

* Update itlb_wrapper.py
2025-06-16 13:20:11 +08:00
Knight of Thunder a30b9eae7c
add -t option to the picker command in ftq_top script to allow repeated directory creation (#137) 2025-06-07 18:18:00 +08:00
21 changed files with 616 additions and 511 deletions

View File

@ -18,7 +18,7 @@ weight: 13
```bash ```bash
git clone https://github.com/XS-MLVP/UnityChipForXiangShan.git git clone https://github.com/XS-MLVP/UnityChipForXiangShan.git
cd UnityChipForXiangShan cd UnityChipForXiangShan
pip3 install -r requirements.txt # 安装python依赖例如 toffee pip3 install -r requirements.txt # 安装 python 依赖(例如 toffee
``` ```
#### 下载RTL代码 #### 下载RTL代码
@ -26,10 +26,10 @@ pip3 install -r requirements.txt # 安装python依赖例如 toffee
默认从仓库[https://github.com/XS-MLVP/UnityChipXiangShanRTLs](https://github.com/XS-MLVP/UnityChipXiangShanRTLs)中下载。用户也可以自行按照XiangShan文档编译生成RTL。 默认从仓库[https://github.com/XS-MLVP/UnityChipXiangShanRTLs](https://github.com/XS-MLVP/UnityChipXiangShanRTLs)中下载。用户也可以自行按照XiangShan文档编译生成RTL。
```bash ```bash
make rtl # 该命下载最新的rtl代码并解压至rtl目录并创建软连 make rtl # 该命令下载最新的 rtl 代码,解压至 rtl 目录,并创建软链
``` ```
可以用以下命令指定下载的rtl版本 可以用以下命令指定下载的 rtl 版本:
```bash ```bash
make rtl args="rtl.version=\'openxiangshan-kmh-fad7803d-24120901\'" make rtl args="rtl.version=\'openxiangshan-kmh-fad7803d-24120901\'"
@ -37,7 +37,7 @@ make rtl args="rtl.version=\'openxiangshan-kmh-fad7803d-24120901\'"
所有RTL下载包请在[UnityChipXiangShanRTLs](https://github.com/XS-MLVP/UnityChipXiangShanRTLs)中查看。 所有RTL下载包请在[UnityChipXiangShanRTLs](https://github.com/XS-MLVP/UnityChipXiangShanRTLs)中查看。
RTL压缩包的命名规范为`名称-微架构-Git标记-日期编号.tar.gz`,例如`openxiangshan-kmh-97e37a2237-24092701.tar.gz`。在使用时仓库代码会过滤掉git标记和后缀例如通过 cfg.rtl.version 访问到的版本号为:`openxiangshan-kmh-24092701`。压缩包内的目录结构为: RTL压缩包的命名规范为`名称-微架构-Git标记-日期编号.tar.gz`,例如`openxiangshan-kmh-97e37a2237-24092701.tar.gz`。在使用时,仓库代码会过滤掉 git 标记和后缀,例如通过 cfg.rtl.version 访问到的版本号为:`openxiangshan-kmh-24092701`。压缩包内的目录结构为:
```bash ```bash
openxiangshan-kmh-97e37a2237-24092701.tar.gz openxiangshan-kmh-97e37a2237-24092701.tar.gz

View File

@ -42,7 +42,7 @@ def get_metadata():
"dut_name": "frontend_instruncache", "dut_name": "frontend_instruncache",
"dut_dir": "InstrUncache", "dut_dir": "InstrUncache",
"test_targets": [ "test_targets": [
"ut_frontend/instruncache/classical_version", "ut_frontend/instruncache/classic_version",
"ut_frontend/instruncache/toffee_version", "ut_frontend/instruncache/toffee_version",
"ut_frontend/instruncache", "ut_frontend/instruncache",
"ut_frontend" "ut_frontend"

View File

@ -3,3 +3,4 @@ ICacheMainPipe:
- "wire _toMSHRArbiter_io_in_0_valid_T_4" - "wire _toMSHRArbiter_io_in_0_valid_T_4"
- "wire _toMSHRArbiter_io_in_1_valid_T_4" - "wire _toMSHRArbiter_io_in_1_valid_T_4"
- "reg s2_valid" - "reg s2_valid"
- "wire s0_fire"

View File

@ -13,6 +13,10 @@ async def ctrlunit_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock") dut.InitClock("clock")
start_clock(dut) start_clock(dut)
ctrlunit_env = CtrlUnitEnv(dut) ctrlunit_env = CtrlUnitEnv(dut)
ctrlunit_env.dut.reset.value = 1
ctrlunit_env.dut.Step(10)
ctrlunit_env.dut.reset.value = 0
ctrlunit_env.dut.Step(10)
yield ctrlunit_env yield ctrlunit_env
cur_loop = asyncio.get_event_loop() cur_loop = asyncio.get_event_loop()

View File

@ -13,6 +13,10 @@ async def icache_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock") dut.InitClock("clock")
start_clock(dut) start_clock(dut)
icache_env = ICacheEnv(dut) icache_env = ICacheEnv(dut)
icache_env.dut.reset.value = 1
icache_env.dut.Step(10)
icache_env.dut.reset.value = 0
icache_env.dut.Step(10)
yield icache_env yield icache_env
cur_loop = asyncio.get_event_loop() cur_loop = asyncio.get_event_loop()

View File

@ -8,21 +8,6 @@ class IPrefetchPipeAgent(Agent):
super().__init__(bundle) super().__init__(bundle)
self.bundle = bundle self.bundle = bundle
async def set_s1_flush(self):
self.bundle.reset.value = 1
await self.bundle.step()
self.bundle.reset.value = 0
await self.bundle.step()
print(
"\nBefore setting, s1_flush is: ",
self.bundle.IPrefetchPipe._s1._flush.value,
)
self.bundle.io._flush.value = 1
await self.bundle.step()
print(
"After setting, s1_flush is: ", self.bundle.IPrefetchPipe._s1._flush.value
)
async def receive_prefetch(self): async def receive_prefetch(self):

View File

@ -14,6 +14,10 @@ async def iprefetchpipe_env(toffee_request: toffee_test.ToffeeRequest):
start_clock(dut) start_clock(dut)
iprefetchpipe_env = IPrefetchPipeEnv(dut) iprefetchpipe_env = IPrefetchPipeEnv(dut)
toffee_request.add_cov_groups([get_cover_group_of_receive_prefetch_quest(dut)]) toffee_request.add_cov_groups([get_cover_group_of_receive_prefetch_quest(dut)])
iprefetchpipe_env.dut.reset.value = 1
iprefetchpipe_env.dut.Step(10)
iprefetchpipe_env.dut.reset.value = 0
iprefetchpipe_env.dut.Step(10)
yield iprefetchpipe_env yield iprefetchpipe_env
cur = asyncio.get_event_loop() cur = asyncio.get_event_loop()

View File

@ -3,10 +3,6 @@ from ..env import IPrefetchPipeEnv
import toffee_test import toffee_test
#@toffee_test.testcase
#async def test_smoke(iprefetchpipe_env: IPrefetchPipeEnv):
# await iprefetchpipe_env.agent.set_s1_flush()
@toffee_test.testcase @toffee_test.testcase
async def test_receive_prefetch(iprefetchpipe_env: IPrefetchPipeEnv): async def test_receive_prefetch(iprefetchpipe_env: IPrefetchPipeEnv):

View File

@ -13,7 +13,10 @@ def check_prefetch_is_soft_prefetch(dut: DUTIPrefetchPipe) -> bool:
return dut.IPrefetchPipe_s1_isSoftPrefetch.value == dut.io_req_bits_isSoftPrefetch.value return dut.IPrefetchPipe_s1_isSoftPrefetch.value == dut.io_req_bits_isSoftPrefetch.value
def check_prefetch_double_line(dut: DUTIPrefetchPipe) -> bool: def check_prefetch_double_line(dut: DUTIPrefetchPipe) -> bool:
return dut.IPrefetchPipe_s1_doubleline.value == int((bin(dut.io_req_bits_startAddr.value)[2:])[-6]) if dut.io_req_bits_startAddr.value:
return dut.IPrefetchPipe_s1_doubleline.value == int((bin(dut.io_req_bits_startAddr.value)[2:])[-6])
else:
return False
def check_prefetch_ftq_idx_flag(dut: DUTIPrefetchPipe) -> bool: def check_prefetch_ftq_idx_flag(dut: DUTIPrefetchPipe) -> bool:
return dut.IPrefetchPipe_s1_req_ftqIdx_flag.value == dut.io_req_bits_ftqIdx_flag.value return dut.IPrefetchPipe_s1_req_ftqIdx_flag.value == dut.io_req_bits_ftqIdx_flag.value

View File

@ -8,25 +8,17 @@ class ICacheMainPipeAgent(Agent):
bundle.set_all(0) bundle.set_all(0)
self.bundle = bundle self.bundle = bundle
async def set_flush(self): async def flush_s0_fire(self):
print( # set s0_fire
f"\nBefore setting: \n \ self.bundle.io._dataArray._toIData._3._ready.value = 1
s2_fire is: {self.bundle.ICacheMainPipe_s2._fire.value}\n \ self.bundle.io._wayLookupRead._valid.value = 1
_toMSHRArbiter_io_in_0_valid is: {self.bundle.ICacheMainPipe__toMSHRArbiter_io_in._0._valid_T._4.value}\n \ self.bundle.io._fetch._req._valid.value = 1
_toMSHRArbiter_io_in_1_valid is: {self.bundle.ICacheMainPipe__toMSHRArbiter_io_in._1._valid_T._4.value}\n \ await self.bundle.step()
s2_valid is: {self.bundle.ICacheMainPipe_s2._valid.value}\n \
" print( f"\nBefore setting: s0_fire is: ",self.bundle.ICacheMainPipe._s0_fire.value)
)
self.bundle.io._flush.value = 1 self.bundle.io._flush.value = 1
await self.bundle.step() await self.bundle.step()
print( print( f"After setting: s0_fire is: ",self.bundle.ICacheMainPipe._s0_fire.value)
f"After setting: \n \
s2_fire is: {self.bundle.ICacheMainPipe_s2._fire.value}\n \
_toMSHRArbiter_io_in_0_valid is: {self.bundle.ICacheMainPipe__toMSHRArbiter_io_in._0._valid_T._4.value}\n \
_toMSHRArbiter_io_in_1_valid is: {self.bundle.ICacheMainPipe__toMSHRArbiter_io_in._1._valid_T._4.value}\n \
s2_valid is: {self.bundle.ICacheMainPipe_s2._valid.value}\n \
"
)

View File

@ -1,282 +1,231 @@
from toffee import Bundle, Signals, Signal from toffee import Bundle, Signals, Signal
class _0Bundle(Bundle): class _0Bundle(Bundle):
_4 = Signal() _fire, _valid = Signals(2)
class _1Bundle(Bundle): class _1Bundle(Bundle):
_valid_T = _0Bundle.from_prefix("_valid_T") _s2 = _0Bundle.from_prefix("_s2")
_s0_fire = Signal()
class _2Bundle(Bundle): class _2Bundle(Bundle):
_0 = _1Bundle.from_prefix("_0") _4 = Signal()
_1 = _1Bundle.from_prefix("_1")
class _3Bundle(Bundle): class _3Bundle(Bundle):
_fire, _valid = Signals(2) _valid_T = _2Bundle.from_prefix("_valid_T")
class _4Bundle(Bundle): class _4Bundle(Bundle):
_6, _7, _3, _5, _4, _1, _2, _0 = Signals(8) _1 = _3Bundle.from_prefix("_1")
_0 = _3Bundle.from_prefix("_0")
class _5Bundle(Bundle): class _5Bundle(Bundle):
_datas = _4Bundle.from_prefix("_datas") _1, _7, _3, _4, _6, _2, _5, _0 = Signals(8)
_codes = _4Bundle.from_prefix("_codes")
class _6Bundle(Bundle): class _6Bundle(Bundle):
_1, _0 = Signals(2) _datas = _5Bundle.from_prefix("_datas")
_codes = _5Bundle.from_prefix("_codes")
class _7Bundle(Bundle): class _7Bundle(Bundle):
_1, _0, _2, _3 = Signals(4) _1, _0 = Signals(2)
class _8Bundle(Bundle): class _8Bundle(Bundle):
_1 = _7Bundle.from_prefix("_1") _1, _2, _3, _0 = Signals(4)
_0 = _7Bundle.from_prefix("_0")
class _9Bundle(Bundle): class _9Bundle(Bundle):
_waymask = _8Bundle.from_prefix("_waymask") _0 = _8Bundle.from_prefix("_0")
_vSetIdx = _6Bundle.from_prefix("_vSetIdx") _1 = _8Bundle.from_prefix("_1")
_blkOffset = Signal()
class _10Bundle(Bundle): class _10Bundle(Bundle):
_bits = _9Bundle.from_prefix("_bits") _waymask = _9Bundle.from_prefix("_waymask")
_valid = Signal() _vSetIdx = _7Bundle.from_prefix("_vSetIdx")
_blkOffset = Signal()
class _11Bundle(Bundle): class _11Bundle(Bundle):
_bits_vSetIdx = _6Bundle.from_prefix("_bits_vSetIdx") _bits = _10Bundle.from_prefix("_bits")
_valid = Signal() _valid = Signal()
class _12Bundle(Bundle): class _12Bundle(Bundle):
_bits_vSetIdx = _6Bundle.from_prefix("_bits_vSetIdx") _bits_vSetIdx = _7Bundle.from_prefix("_bits_vSetIdx")
_ready, _valid = Signals(2) _valid = Signal()
class _13Bundle(Bundle): class _13Bundle(Bundle):
_3 = _12Bundle.from_prefix("_3") _bits_vSetIdx = _7Bundle.from_prefix("_bits_vSetIdx")
_1 = _11Bundle.from_prefix("_1") _valid, _ready = Signals(2)
_2 = _11Bundle.from_prefix("_2")
_0 = _10Bundle.from_prefix("_0")
class _14Bundle(Bundle): class _14Bundle(Bundle):
_fromIData = _5Bundle.from_prefix("_fromIData") _3 = _13Bundle.from_prefix("_3")
_toIData = _13Bundle.from_prefix("_toIData") _1 = _12Bundle.from_prefix("_1")
_2 = _12Bundle.from_prefix("_2")
_0 = _11Bundle.from_prefix("_0")
class _15Bundle(Bundle): class _15Bundle(Bundle):
_report_to_beu, _paddr = Signals(2) _toIData = _14Bundle.from_prefix("_toIData")
_fromIData = _6Bundle.from_prefix("_fromIData")
class _16Bundle(Bundle): class _16Bundle(Bundle):
_bits = _15Bundle.from_prefix("_bits") _paddr, _report_to_beu = Signals(2)
_valid = Signal()
class _17Bundle(Bundle): class _17Bundle(Bundle):
_0 = _16Bundle.from_prefix("_0") _bits = _16Bundle.from_prefix("_bits")
_1 = _16Bundle.from_prefix("_1") _valid = Signal()
class _18Bundle(Bundle): class _18Bundle(Bundle):
_startAddr, _nextlineStart = Signals(2) _0 = _17Bundle.from_prefix("_0")
_1 = _17Bundle.from_prefix("_1")
class _19Bundle(Bundle): class _19Bundle(Bundle):
_1 = _18Bundle.from_prefix("_1") _nextlineStart, _startAddr = Signals(2)
_3 = _18Bundle.from_prefix("_3")
_0 = _18Bundle.from_prefix("_0")
_4 = _18Bundle.from_prefix("_4")
_2 = _18Bundle.from_prefix("_2")
class _20Bundle(Bundle): class _20Bundle(Bundle):
_3, _4, _1, _2, _0 = Signals(5) _0 = _19Bundle.from_prefix("_0")
_1 = _19Bundle.from_prefix("_1")
_4 = _19Bundle.from_prefix("_4")
_2 = _19Bundle.from_prefix("_2")
_3 = _19Bundle.from_prefix("_3")
class _21Bundle(Bundle): class _21Bundle(Bundle):
_readValid = _20Bundle.from_prefix("_readValid") _1, _3, _4, _2, _0 = Signals(5)
_pcMemRead = _19Bundle.from_prefix("_pcMemRead")
_backendException = Signal()
class _22Bundle(Bundle): class _22Bundle(Bundle):
_bits = _21Bundle.from_prefix("_bits") _pcMemRead = _20Bundle.from_prefix("_pcMemRead")
_ready, _valid = Signals(2) _readValid = _21Bundle.from_prefix("_readValid")
_backendException = Signal()
class _23Bundle(Bundle): class _23Bundle(Bundle):
_0 = Signal() _bits = _22Bundle.from_prefix("_bits")
_valid, _ready = Signals(2)
class _24Bundle(Bundle): class _24Bundle(Bundle):
_exception = _6Bundle.from_prefix("_exception") _0 = Signal()
_itlb_pbmt = _6Bundle.from_prefix("_itlb_pbmt")
_vaddr = _6Bundle.from_prefix("_vaddr")
_pmp_mmio = _6Bundle.from_prefix("_pmp_mmio")
_paddr = _23Bundle.from_prefix("_paddr")
_data, _doubleline, _gpaddr, _backendException, _isForVSnonLeafPTE = Signals(5)
class _25Bundle(Bundle): class _25Bundle(Bundle):
_bits = _24Bundle.from_prefix("_bits") _vaddr = _7Bundle.from_prefix("_vaddr")
_valid = Signal() _itlb_pbmt = _7Bundle.from_prefix("_itlb_pbmt")
_exception = _7Bundle.from_prefix("_exception")
_pmp_mmio = _7Bundle.from_prefix("_pmp_mmio")
_paddr = _24Bundle.from_prefix("_paddr")
_data, _doubleline, _isForVSnonLeafPTE, _gpaddr, _backendException = Signals(5)
class _26Bundle(Bundle): class _26Bundle(Bundle):
_resp = _25Bundle.from_prefix("_resp") _bits = _25Bundle.from_prefix("_bits")
_req = _22Bundle.from_prefix("_req") _valid = Signal()
_topdownIcacheMiss, _topdownItlbMiss = Signals(2)
class _27Bundle(Bundle): class _27Bundle(Bundle):
_virIdx, _waymask = Signals(2) _resp = _26Bundle.from_prefix("_resp")
_req = _23Bundle.from_prefix("_req")
_topdownIcacheMiss, _topdownItlbMiss = Signals(2)
class _28Bundle(Bundle): class _28Bundle(Bundle):
_bits = _27Bundle.from_prefix("_bits") _waymask, _virIdx = Signals(2)
_valid = Signal()
class _29Bundle(Bundle): class _29Bundle(Bundle):
_0 = _28Bundle.from_prefix("_0") _bits = _28Bundle.from_prefix("_bits")
_1 = _28Bundle.from_prefix("_1") _valid = Signal()
class _30Bundle(Bundle): class _30Bundle(Bundle):
_blkPaddr, _vSetIdx = Signals(2) _1 = _29Bundle.from_prefix("_1")
_0 = _29Bundle.from_prefix("_0")
class _31Bundle(Bundle): class _31Bundle(Bundle):
_bits = _30Bundle.from_prefix("_bits") _blkPaddr, _vSetIdx = Signals(2)
_valid, _ready = Signals(2)
class _32Bundle(Bundle): class _32Bundle(Bundle):
_corrupt, _blkPaddr, _vSetIdx, _data = Signals(4) _bits = _31Bundle.from_prefix("_bits")
_valid, _ready = Signals(2)
class _33Bundle(Bundle): class _33Bundle(Bundle):
_bits = _32Bundle.from_prefix("_bits") _data, _blkPaddr, _vSetIdx, _corrupt = Signals(4)
_valid = Signal()
class _34Bundle(Bundle): class _34Bundle(Bundle):
_resp = _33Bundle.from_prefix("_resp") _bits = _33Bundle.from_prefix("_bits")
_req = _31Bundle.from_prefix("_req") _valid = Signal()
class _35Bundle(Bundle): class _35Bundle(Bundle):
_1 = Signal() _resp = _34Bundle.from_prefix("_resp")
_req = _32Bundle.from_prefix("_req")
class _36Bundle(Bundle): class _36Bundle(Bundle):
_miss = _35Bundle.from_prefix("_miss") _1 = Signal()
_hit = _35Bundle.from_prefix("_hit")
_except = _35Bundle.from_prefix("_except")
class _37Bundle(Bundle): class _37Bundle(Bundle):
_0 = _36Bundle.from_prefix("_0") _hit = _36Bundle.from_prefix("_hit")
_except = _36Bundle.from_prefix("_except")
_miss = _36Bundle.from_prefix("_miss")
class _38Bundle(Bundle): class _38Bundle(Bundle):
_hit, _miss = Signals(2) _0 = _37Bundle.from_prefix("_0")
class _39Bundle(Bundle): class _39Bundle(Bundle):
_0 = _38Bundle.from_prefix("_0") _miss, _hit = Signals(2)
class _40Bundle(Bundle): class _40Bundle(Bundle):
_except = _23Bundle.from_prefix("_except") _0 = _39Bundle.from_prefix("_0")
_miss = _37Bundle.from_prefix("_miss")
_bank_hit = _6Bundle.from_prefix("_bank_hit")
_only = _39Bundle.from_prefix("_only")
_hit = Signal()
class _41Bundle(Bundle): class _41Bundle(Bundle):
_mmio, _instr = Signals(2) _bank_hit = _7Bundle.from_prefix("_bank_hit")
_miss = _38Bundle.from_prefix("_miss")
_except = _24Bundle.from_prefix("_except")
_only = _40Bundle.from_prefix("_only")
_hit = Signal()
class _42Bundle(Bundle): class _42Bundle(Bundle):
_resp = _41Bundle.from_prefix("_resp") _instr, _mmio = Signals(2)
_req_bits_addr = Signal()
class _43Bundle(Bundle): class _43Bundle(Bundle):
_0 = _42Bundle.from_prefix("_0") _resp = _42Bundle.from_prefix("_resp")
_1 = _42Bundle.from_prefix("_1") _req_bits_addr = Signal()
class _44Bundle(Bundle): class _44Bundle(Bundle):
_way, _vSetIdx = Signals(2) _1 = _43Bundle.from_prefix("_1")
_0 = _43Bundle.from_prefix("_0")
class _45Bundle(Bundle): class _45Bundle(Bundle):
_bits = _44Bundle.from_prefix("_bits") _way, _vSetIdx = Signals(2)
_valid = Signal()
class _46Bundle(Bundle): class _46Bundle(Bundle):
_0 = _45Bundle.from_prefix("_0") _bits = _45Bundle.from_prefix("_bits")
_1 = _45Bundle.from_prefix("_1") _valid = Signal()
class _47Bundle(Bundle): class _47Bundle(Bundle):
_pbmt = _6Bundle.from_prefix("_pbmt") _0 = _46Bundle.from_prefix("_0")
_exception = _6Bundle.from_prefix("_exception") _1 = _46Bundle.from_prefix("_1")
class _48Bundle(Bundle): class _48Bundle(Bundle):
_waymask = _6Bundle.from_prefix("_waymask") _pbmt = _7Bundle.from_prefix("_pbmt")
_ptag = _6Bundle.from_prefix("_ptag") _exception = _7Bundle.from_prefix("_exception")
_vSetIdx = _6Bundle.from_prefix("_vSetIdx")
_meta_codes = _6Bundle.from_prefix("_meta_codes")
_itlb = _47Bundle.from_prefix("_itlb")
class _49Bundle(Bundle): class _49Bundle(Bundle):
_gpaddr, _isForVSnonLeafPTE = Signals(2) _ptag = _7Bundle.from_prefix("_ptag")
_meta_codes = _7Bundle.from_prefix("_meta_codes")
_waymask = _7Bundle.from_prefix("_waymask")
_vSetIdx = _7Bundle.from_prefix("_vSetIdx")
_itlb = _48Bundle.from_prefix("_itlb")
class _50Bundle(Bundle): class _50Bundle(Bundle):
_entry = _48Bundle.from_prefix("_entry") _isForVSnonLeafPTE, _gpaddr = Signals(2)
_gpf = _49Bundle.from_prefix("_gpf")
class _51Bundle(Bundle): class _51Bundle(Bundle):
_bits = _50Bundle.from_prefix("_bits") _entry = _49Bundle.from_prefix("_entry")
_ready, _valid = Signals(2) _gpf = _50Bundle.from_prefix("_gpf")
class _52Bundle(Bundle): class _52Bundle(Bundle):
_dataArray = _14Bundle.from_prefix("_dataArray") _bits = _51Bundle.from_prefix("_bits")
_pmp = _43Bundle.from_prefix("_pmp") _valid, _ready = Signals(2)
_mshr = _34Bundle.from_prefix("_mshr")
_wayLookupRead = _51Bundle.from_prefix("_wayLookupRead")
_perfInfo = _40Bundle.from_prefix("_perfInfo")
_errors = _17Bundle.from_prefix("_errors")
_fetch = _26Bundle.from_prefix("_fetch")
_metaArrayFlush = _29Bundle.from_prefix("_metaArrayFlush")
_touch = _46Bundle.from_prefix("_touch")
_flush, _respStall, _ecc_enable, _hartId = Signals(4)
class _53Bundle(Bundle):
_perfInfo = _41Bundle.from_prefix("_perfInfo")
_pmp = _44Bundle.from_prefix("_pmp")
_errors = _18Bundle.from_prefix("_errors")
_metaArrayFlush = _30Bundle.from_prefix("_metaArrayFlush")
_wayLookupRead = _52Bundle.from_prefix("_wayLookupRead")
_dataArray = _15Bundle.from_prefix("_dataArray")
_mshr = _35Bundle.from_prefix("_mshr")
_fetch = _27Bundle.from_prefix("_fetch")
_touch = _47Bundle.from_prefix("_touch")
_hartId, _flush, _ecc_enable, _respStall = Signals(4)
class ICacheMainPipeBundle(Bundle): class ICacheMainPipeBundle(Bundle):
ICacheMainPipe_s2 = _3Bundle.from_prefix("ICacheMainPipe_s2") ICacheMainPipe = _1Bundle.from_prefix("ICacheMainPipe")
io = _52Bundle.from_prefix("io") ICacheMainPipe__toMSHRArbiter_io_in = _4Bundle.from_prefix("ICacheMainPipe__toMSHRArbiter_io_in")
ICacheMainPipe__toMSHRArbiter_io_in = _2Bundle.from_prefix( io = _53Bundle.from_prefix("io")
"ICacheMainPipe__toMSHRArbiter_io_in" reset, clock = Signals(2)
)
clock, reset = Signals(2)

View File

@ -4,4 +4,4 @@ import toffee_test
@toffee_test.testcase @toffee_test.testcase
async def test_smoke(icachemainpipe_env: ICacheMainPipeEnv): async def test_smoke(icachemainpipe_env: ICacheMainPipeEnv):
await icachemainpipe_env.agent.set_flush() await icachemainpipe_env.agent.flush_s0_fire()

View File

@ -13,6 +13,10 @@ async def icachemainpipe_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock") dut.InitClock("clock")
start_clock(dut) start_clock(dut)
icachemainpipe_env = ICacheMainPipeEnv(dut) icachemainpipe_env = ICacheMainPipeEnv(dut)
icachemainpipe_env.dut.reset.value = 1
icachemainpipe_env.dut.Step(10)
icachemainpipe_env.dut.reset.value = 0
icachemainpipe_env.dut.Step(10)
yield icachemainpipe_env yield icachemainpipe_env
cur_loop = asyncio.get_event_loop() cur_loop = asyncio.get_event_loop()

View File

@ -13,6 +13,10 @@ async def icachemissunit_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock") dut.InitClock("clock")
start_clock(dut) start_clock(dut)
icachemissunit_env = ICacheMissUnitEnv(dut) icachemissunit_env = ICacheMissUnitEnv(dut)
icachemissunit_env.dut.reset.value = 1
icachemissunit_env.dut.Step(10)
icachemissunit_env.dut.reset.value = 0
icachemissunit_env.dut.Step(10)
yield icachemissunit_env yield icachemissunit_env
cur_loop = asyncio.get_event_loop() cur_loop = asyncio.get_event_loop()

View File

@ -1,34 +1,6 @@
from toffee import Agent from toffee import Agent
from ..bundle import WayLookupBundle from ..bundle import WayLookupBundle
class ReadBitsData:
WayLookup_readPtr_value_before_flush: int
WayLookup_readPtr_value_after_flush: int
WayLookup_readPtr_flag_before_flush: bool
WayLookup_readPtr_flag_after_flush: bool
WayLookup_writePtr_value_before_flush: int
WayLookup_writePtr_value_after_flush: int
WayLookup_writePtr_flag_before_flush: bool
WayLookup_writePtr_flag_after_flush: bool
flush: int
def __str__(self):
return (
f"\n"
f"WayLookup_readPtr_value_before_flush: {self.WayLookup_readPtr_value_before_flush}\n"
f"WayLookup_readPtr_value_after_flush: {self.WayLookup_readPtr_value_after_flush}\n"
f"WayLookup_readPtr_flag_before_flush: {self.WayLookup_readPtr_flag_before_flush}\n"
f"WayLookup_readPtr_flag_after_flush: {self.WayLookup_readPtr_flag_after_flush}\n"
f"WayLookup_writePtr_value_before_flush: {self.WayLookup_writePtr_value_before_flush}\n"
f"WayLookup_writePtr_value_after_flush: {self.WayLookup_writePtr_value_after_flush}\n"
f"WayLookup_writePtr_flag_before_flush: {self.WayLookup_writePtr_flag_before_flush}\n"
f"WayLookup_writePtr_flag_after_flush: {self.WayLookup_writePtr_flag_after_flush}\n"
f"flush: {self.flush}\n"
)
class WayLookupAgent(Agent): class WayLookupAgent(Agent):
def __init__(self, bundle: WayLookupBundle): def __init__(self, bundle: WayLookupBundle):
@ -36,38 +8,30 @@ class WayLookupAgent(Agent):
bundle.set_all(0) bundle.set_all(0)
self.bundle = bundle self.bundle = bundle
async def flush(self) -> ReadBitsData: async def flush_write_ptr(self):
ret = ReadBitsData() # set io_write_fireio.write.ready is already 1
self.bundle.io._write._valid.value = 1
ret.WayLookup_readPtr_value_before_flush = ( await self.bundle.step()
self.bundle.WayLookup._readPtr._value.value
) # set write_ptr by writting entry
ret.WayLookup_readPtr_flag_before_flush = ( self.bundle.io._write._bits._entry._vSetIdx._0.value = 0
self.bundle.WayLookup._readPtr._flag.value self.bundle.io._write._bits._entry._vSetIdx._1.value = 1
) self.bundle.io._write._bits._entry._waymask._0.value = 0
ret.WayLookup_writePtr_value_before_flush = ( self.bundle.io._write._bits._entry._waymask._1.value = 1
self.bundle.WayLookup._writePtr._value.value self.bundle.io._write._bits._entry._ptag._0.value = 0
) self.bundle.io._write._bits._entry._ptag._1.value = 1
ret.WayLookup_writePtr_flag_before_flush = ( self.bundle.io._write._bits._entry._itlb._exception._0.value = 0
self.bundle.WayLookup._writePtr._flag.value self.bundle.io._write._bits._entry._itlb._exception._1.value = 1
) self.bundle.io._write._bits._entry._meta_codes._0.value = 0
self.bundle.io._write._bits._entry._meta_codes._1.value = 1
await self.bundle.step()
print("Before flush, write_ptr is: ", self.bundle.WayLookup._writePtr._value.value)
# flush
self.bundle.io._flush.value = 1 self.bundle.io._flush.value = 1
await self.bundle.step() await self.bundle.step()
ret.WayLookup_readPtr_value_after_flush = ( # print
self.bundle.WayLookup._readPtr._value.value print("After flush, write_ptr is: ", self.bundle.WayLookup._writePtr._value.value)
) await self.bundle.step()
ret.WayLookup_readPtr_flag_after_flush = (
self.bundle.WayLookup._readPtr._flag.value
)
ret.WayLookup_writePtr_value_after_flush = (
self.bundle.WayLookup._writePtr._value.value
)
ret.WayLookup_writePtr_flag_after_flush = (
self.bundle.WayLookup._writePtr._flag.value
)
ret.flush = self.bundle.io._flush.value
return ret

View File

@ -13,6 +13,10 @@ async def waylookup_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock") dut.InitClock("clock")
start_clock(dut) start_clock(dut)
waylookup_env = WayLookupEnv(dut) waylookup_env = WayLookupEnv(dut)
waylookup_env.dut.reset.value = 1
waylookup_env.dut.Step(10)
waylookup_env.dut.reset.value = 0
waylookup_env.dut.Step(10)
yield waylookup_env yield waylookup_env
cur_loop = asyncio.get_event_loop() cur_loop = asyncio.get_event_loop()

View File

@ -5,5 +5,4 @@ import toffee_test
@toffee_test.testcase @toffee_test.testcase
async def test_smoke(waylookup_env: WayLookupEnv): async def test_smoke(waylookup_env: WayLookupEnv):
await waylookup_env.agent.flush_write_ptr()
print(await waylookup_env.agent.flush())

View File

@ -1,248 +1,304 @@
# **Translation Lookaside Buffer (TLB)** # **Translation Lookaside Buffer (TLB)**
## 一、TLB.sv 接口说明 ## 一、TLB IO 信号总表
### 基本控制信号 ### 1. 全局控制信号
1. **`clock`**: 时钟信号,驱动 TLB 的时序逻辑。 | 信号名 | 方向 | 位宽 | 描述 |
2. **`reset`**: 复位信号,用于重置 TLB 的状态。 |---------------|---------|------|-----------------------------|
| clock | `input` | 1 | 时钟信号,驱动 TLB 的时序逻辑 |
| reset | `input` | 1 | 复位信号,用于重置 TLB 的状态 |
| io_hartId | `input` | 6 | 硬件线程ID |
### 刷新SFENCE接口信号 ### 2. SFENCE 指令接口信号
这些信号与 TLB 的刷新操作相关,当页表被修改时,这些信号用于通知 TLB 刷新其内容。 | 信号名 | 方向 | 位宽 | 描述 |
|---------------------------------|---------|------|--------------------------------------|
| io_sfence_valid | `input` | 1 | SFENCE操作有效信号 |
| io_sfence_bits_rs1 | `input` | 1 | 指示是否使用寄存器rs1的值地址 |
| io_sfence_bits_rs2 | `input` | 1 | 指示是否使用寄存器rs2的值ASID |
| io_sfence_bits_addr | `input` | 50 | SFENCE操作指定要刷新的虚拟地址用于选择性刷新特定地址的 TLB 条目 |
| io_sfence_bits_id | `input` | 16 | SFENCE操作指定要刷新的ASID用于选择性刷新特定地址空间的 TLB 条目 |
| io_sfence_bits_flushPipe | `input` | 1 | 指示当前 SFENCE 操作是否刷新流水线 |
| io_sfence_bits_hv | `input` | 1 | 是否在Hypervisor模式下执行SFENCE |
| io_sfence_bits_hg | `input` | 1 | 是否在Hypervisor guest模式下执行SFENCE |
3. **`io_sfence_valid`**: 表示 SFENCE 操作的有效性。 ### 3. CSR 寄存器输入
4. **`io_sfence_bits_rs1`**: 表示 SFENCE 操作是否使用寄存器 rs1 的值。
5. **`io_sfence_bits_rs2`**: 表示 SFENCE 操作是否使用寄存器 rs2 的值。
6. **`io_sfence_bits_addr`**: SFENCE 操作指定的地址,用于选择性刷新特定地址的 TLB 条目。
7. **`io_sfence_bits_id`**: 标识符,用于区分不同的刷新操作。
8. **`io_sfence_bits_flushPipe`**: 请求刷新整个管道Pipeline
9. **`io_sfence_bits_hv`**: 代表是否是 Hypervisor 模式下的 SFENCE 操作。
10. **`io_sfence_bits_hg`**: 代表是否是 Guest 模式下的 SFENCE 操作。
### 控制与状态寄存器CSR接口信号 | 信号名 | 方向 | 位宽 | 描述 |
|---------------------------------|---------|------|-----------------------------------|
| io_csr_satp_mode | `input` | 4 | SATP寄存器模式位 |
| io_csr_satp_asid | `input` | 16 | SATP寄存器ASID |
| io_csr_satp_ppn | `input` | 44 | SATP寄存器PPN |
| io_csr_satp_changed | `input` | 1 | SATP寄存器是否发生变化 |
| io_csr_vsatp_mode | `input` | 4 | VSATP寄存器模式位虚拟化 |
| io_csr_vsatp_asid | `input` | 16 | VSATP寄存器ASID |
| io_csr_vsatp_ppn | `input` | 44 | VSATP寄存器PPN |
| io_csr_vsatp_changed | `input` | 1 | VSATP寄存器是否发生变化 |
| io_csr_hgatp_mode | `input` | 4 | HGATP寄存器模式位虚拟化 |
| io_csr_hgatp_vmid | `input` | 16 | HGATP寄存器VMID |
| io_csr_hgatp_ppn | `input` | 44 | HGATP寄存器PPN |
| io_csr_hgatp_changed | `input` | 1 | HGATP寄存器是否发生变化 |
| io_csr_priv_virt | `input` | 1 | 虚拟化使能信号 |
| io_csr_priv_imode | `input` | 2 | 当前特权模式00U, 01S, 11M |
这些信号与 TLB 的控制与状态寄存器CSR配置相关。 ### 4. 请求与响应接口Requestor 0
11. **`io_csr_satp_mode`**: SATP 寄存器的模式字段如裸模式、Sv32、Sv39 等)。 | 信号名 | 方向 | 位宽 | 描述 |
12. **`io_csr_satp_asid`**: 当前 SATP 寄存器的 ASID地址空间标识符 |--------------------------------------------|----------|------|--------------------------------|
13. **`io_csr_satp_changed`**: 指示 SATP 寄存器的值是否已更改。 | io_requestor_0_req_valid | `input` | 1 | 请求0有效 |
14. **`io_csr_vsatp_mode`**: VSATP 寄存器的模式字段。 | io_requestor_0_req_bits_vaddr | `input` | 50 | 请求0的虚拟地址 |
15. **`io_csr_vsatp_asid`**: VSATP 寄存器的 ASID。 | io_requestor_0_resp_bits_paddr_0 | `output` | 48 | 响应0的物理地址 |
16. **`io_csr_vsatp_changed`**: 指示 VSATP 寄存器的值是否已更改。 | io_requestor_0_resp_bits_gpaddr_0 | `output` | 64 | 响应0的虚拟化物理地址 |
17. **`io_csr_hgatp_mode`**: HGATP 寄存器的模式字段。 | io_requestor_0_resp_bits_pbmt_0 | `output` | 2 | 响应0的物理内存保护类型 |
18. **`io_csr_hgatp_vmid`**: HGATP 寄存器的 VMID虚拟机标识符 | io_requestor_0_resp_bits_miss | `output` | 1 | 响应0是否TLB缺失 |
19. **`io_csr_hgatp_changed`**: 指示 HGATP 寄存器的值是否已更改。 | io_requestor_0_resp_bits_isForVSnonLeafPTE | `output` | 1 | 响应0是否为虚拟机非叶子PTE |
20. **`io_csr_priv_virt`**: 是否在虚拟模式下运行。 | io_requestor_0_resp_bits_excp_0_gpf_instr | `output` | 1 | 指令0的虚拟化缺页异常 |
21. **`io_csr_priv_imode`**: 指令模式的特权级(如用户态、内核态等)。 | io_requestor_0_resp_bits_excp_0_pf_instr | `output` | 1 | 指令0的缺页异常 |
| io_requestor_0_resp_bits_excp_0_af_instr | `output` | 1 | 指令0的访问权限异常 |
### 请求者Requestor接口信号 ### 5. 请求与响应接口Requestor 1
这些信号用于与处理器或其他模块之间的请求与响应操作。 | 信号名 | 方向 | 位宽 | 描述 |
|--------------------------------------------|----------|------|---------------------------------|
| io_requestor_1_req_valid | `input` | 1 | 请求1有效 |
| io_requestor_1_req_bits_vaddr | `input` | 50 | 请求1的虚拟地址 |
| io_requestor_1_resp_bits_paddr_0 | `output` | 48 | 响应1的物理地址 |
| io_requestor_1_resp_bits_gpaddr_0 | `output` | 64 | 响应1的虚拟化物理地址 |
| io_requestor_1_resp_bits_pbmt_0 | `output` | 2 | 响应1的物理内存保护类型 |
| io_requestor_1_resp_bits_miss | `output` | 1 | 响应1是否TLB缺失 |
| io_requestor_1_resp_bits_isForVSnonLeafPTE | `output` | 1 | 响应1是否为虚拟机非叶子PTE |
| io_requestor_1_resp_bits_excp_0_gpf_instr | `output` | 1 | 数据访问0的虚拟化缺页异常 |
| io_requestor_1_resp_bits_excp_0_pf_instr | `output` | 1 | 数据访问0的缺页异常 |
| io_requestor_1_resp_bits_excp_0_af_instr | `output` | 1 | 数据访问0的访问权限异常 |
#### Requestor 0 信号 ### 6. 请求与响应接口Requestor 2
22. **`io_requestor_0_req_valid`**: 请求者 0 的请求有效信号。 | 信号名 | 方向 | 位宽 | 描述 |
23. **`io_requestor_0_req_bits_vaddr`**: 请求者 0 的请求虚拟地址vaddr |--------------------------------------------|----------|----|--------------------------------|
24. **`io_requestor_0_resp_bits_paddr_0`**: 请求者 0 的物理地址paddr响应信号。 | io_requestor_2_req_ready | `output` | 1 | 请求2就绪信号 |
25. **`io_requestor_0_resp_bits_gpaddr_0`**: 请求者 0 的物理地址转换为 GPAGuest Physical Address的响应信号。 | io_requestor_2_req_valid | `input` | 1 | 请求2有效 |
26. **`io_requestor_0_resp_bits_miss`**: 请求者 0 请求的地址未命中的信号。 | io_requestor_2_req_bits_vaddr | `input` | 50 | 请求2的虚拟地址 |
27. **`io_requestor_0_resp_bits_excp_0_gpf_instr`**: 请求者 0 出现 General Protection Fault (GPF) 异常的信号。 | io_requestor_2_resp_ready | `input` | 1 | 响应2就绪信号 |
28. **`io_requestor_0_resp_bits_excp_0_pf_instr`**: 请求者 0 出现 Page Fault (PF) 异常的信号。 | io_requestor_2_resp_valid | `output` | 1 | 响应2有效 |
29. **`io_requestor_0_resp_bits_excp_0_af_instr`**: 请求者 0 出现 Access Fault (AF) 异常的信号。 | io_requestor_2_resp_bits_paddr_0 | `output` | 48 | 响应2的物理地址 |
| io_requestor_2_resp_bits_gpaddr_0 | `output` | 64 | 响应2的虚拟化物理地址 |
| io_requestor_2_resp_bits_pbmt_0 | `output` | 2 | 响应2的物理内存保护类型 |
| io_requestor_2_resp_bits_miss | `output` | 1 | 响应2是否TLB缺失 |
| io_requestor_2_resp_bits_isForVSnonLeafPTE | `output` | 1 | 响应2是否为虚拟机非叶子PTE |
| io_requestor_2_resp_bits_excp_0_gpf_instr | `output` | 1 | PTW访问的虚拟化缺页异常 |
| io_requestor_2_resp_bits_excp_0_pf_instr | `output` | 1 | PTW访问的缺页异常 |
| io_requestor_2_resp_bits_excp_0_af_instr | `output` | 1 | PTW访问的访问权限异常 |
#### Requestor 1 信号 ### 7. 流水线刷新信号(来自外部)
30. **`io_requestor_1_req_valid`**: 请求者 1 的请求有效信号。 | 信号名 | 方向 | 位宽 | 描述 |
31. **`io_requestor_1_req_bits_vaddr`**: 请求者 1 的请求虚拟地址。 |-----------------------|---------|------|---------------|
32. **`io_requestor_1_resp_bits_paddr_0`**: 请求者 1 的物理地址响应信号。 | io_flushPipe_0 | `input` | 1 | 刷新流水线 0 |
33. **`io_requestor_1_resp_bits_gpaddr_0`**: 请求者 1 的 GPA 响应信号。 | io_flushPipe_1 | `input` | 1 | 刷新流水线 1 |
34. **`io_requestor_1_resp_bits_miss`**: 请求者 1 的未命中信号。 | io_flushPipe_2 | `input` | 1 | 刷新流水线 2 |
35. **`io_requestor_1_resp_bits_excp_0_gpf_instr`**: 请求者 1 出现 GPF 异常的信号。
36. **`io_requestor_1_resp_bits_excp_0_pf_instr`**: 请求者 1 出现 PF 异常的信号。
37. **`io_requestor_1_resp_bits_excp_0_af_instr`**: 请求者 1 出现 AF 异常的信号。
#### Requestor 2 信号 ### 8. PTW 请求接口共3个通道
38. **`io_requestor_2_req_ready`**: 请求者 2 的请求就绪信号。 | 信号名 | 方向 | 位宽 | 描述 |
39. **`io_requestor_2_req_valid`**: 请求者 2 的请求有效信号。 |-----------------------------|----------|------|----------------------------------|
40. **`io_requestor_2_req_bits_vaddr`**: 请求者 2 的请求虚拟地址。 | io_ptw_req_0_valid | `output` | 1 | PTW请求通道0有效 |
41. **`io_requestor_2_resp_ready`**: 请求者 2 的响应就绪信号。 | io_ptw_req_0_bits_vpn | `output` | 38 | 请求的虚拟页号VPN |
42. **`io_requestor_2_resp_valid`**: 请求者 2 的响应有效信号。 | io_ptw_req_0_bits_s2xlate | `output` | 2 | 二级转换类型指示 |
43. **`io_requestor_2_resp_bits_paddr_0`**: 请求者 2 的物理地址响应信号。 | io_ptw_req_0_bits_getGpa | `output` | 1 | 是否请求获得GPA |
44. **`io_requestor_2_resp_bits_gpaddr_0`**: 请求者 2 的 GPA 响应信号。 | io_ptw_req_1_valid | `output` | 1 | PTW请求通道1有效 |
45. **`io_requestor_2_resp_bits_excp_0_gpf_instr`**: 请求者 2 出现 GPF 异常的信号。 | io_ptw_req_1_bits_vpn | `output` | 38 | 请求的虚拟页号VPN |
46. **`io_requestor_2_resp_bits_excp_0_pf_instr`**: 请求者 2 出现 PF 异常的信号。 | io_ptw_req_1_bits_s2xlate | `output` | 2 | 二级转换类型指示 |
47. **`io_requestor_2_resp_bits_excp_0_af_instr`**: 请求者 2 出现 AF 异常的信号。 | io_ptw_req_1_bits_getGpa | `output` | 1 | 是否请求获得GPA |
| io_ptw_req_2_ready | `input` | 1 | PTW请求通道2就绪 |
| io_ptw_req_2_valid | `output` | 1 | PTW请求通道2有效 |
| io_ptw_req_2_bits_vpn | `output` | 38 | 请求的虚拟页号VPN |
| io_ptw_req_2_bits_s2xlate | `output` | 2 | 二级转换类型指示 |
| io_ptw_req_2_bits_getGpa | `output` | 1 | 是否请求获得GPA |
### 刷新管道Flush Pipe信号 ### 9. PTW 响应接口共1个通道
这些信号用于通知 TLB 刷新请求。 | 信号名 | 方向 | 位宽 | 描述 |
|------------------------------------|---------|------|-----------------------------------|
48. **`io_flushPipe_0`**: 刷新管道 0 的信号。 | io_ptw_resp_valid | `input` | 1 | PTW响应有效 |
49. **`io_flushPipe_1`**: 刷新管道 1 的信号。 | io_ptw_resp_bits_s2xlate | `input` | 2 | 二级转换类型(回环) |
50. **`io_flushPipe_2`**: 刷新管道 2 的信号。 | **s1_entry 相关信号** | | | **第一级转换响应信息** |
| io_ptw_resp_bits_s1_entry_tag | `input` | 35 | 标签VPN高位 |
### 页表遍历Page Table Walker, PTW接口信号 | io_ptw_resp_bits_s1_entry_asid | `input` | 16 | ASID |
| io_ptw_resp_bits_s1_entry_vmid | `input` | 14 | VMID |
这些信号用于与页表遍历单元PTW的交互处理 TLB 未命中的情况。 | io_ptw_resp_bits_s1_entry_n | `input` | 1 | 非叶子节点标志 |
| io_ptw_resp_bits_s1_entry_pbmt | `input` | 2 | 物理内存保护类型 |
#### PTW 请求信号 | io_ptw_resp_bits_s1_entry_perm_d | `input` | 1 | 脏位标志D |
| io_ptw_resp_bits_s1_entry_perm_a | `input` | 1 | 访问位A |
51. **`io_ptw_req_0_valid`**: PTW 请求 0 有效信号。 | io_ptw_resp_bits_s1_entry_perm_g | `input` | 1 | 全局映射G |
52. **`io_ptw_req_0_bits_vpn`**: PTW 请求 0 的虚拟页号VPN | io_ptw_resp_bits_s1_entry_perm_u | `input` | 1 | 用户模式访问位U |
53. **`io_ptw_req_0_bits_s2xlate`**: PTW 请求 0 的 S2 转换位。 | io_ptw_resp_bits_s1_entry_perm_x | `input` | 1 | 执行位X |
54. **`io_ptw_req_0_bits_getGpa`**: PTW 请求 0 的获取 GPA 信号。 | io_ptw_resp_bits_s1_entry_perm_w | `input` | 1 | 写位W |
55. **`io_ptw_req_1_valid`**: PTW 请求 1 有效信号。 | io_ptw_resp_bits_s1_entry_perm_r | `input` | 1 | 读位R |
56. **`io_ptw_req_1_bits_vpn`**: PTW 请求 1 的虚拟页号。 | io_ptw_resp_bits_s1_entry_level | `input` | 2 | 页表级0-2 |
57. **`io_ptw_req_1_bits_s2xlate`**: PTW 请求 1 的 S2 转换位。 | io_ptw_resp_bits_s1_entry_v | `input` | 1 | 页表项有效标志 |
58. **`io_ptw_req_1_bits_getGpa`**: PTW 请求 1 的获取 GPA 信号。 | io_ptw_resp_bits_s1_entry_ppn | `input` | 41 | 物理页号PPN |
59. **`io_ptw_req_2_ready`**: PTW 请求 2 就绪信号。 | io_ptw_resp_bits_s1_addr_low | `input` | 3 | 虚拟地址低位(页内偏移高位) |
60. **`io_ptw_req_2_valid`**: PTW 请求 2 有效信号。 | io_ptw_resp_bits_s1_ppn_low_[0-7] | `input` | 8×3 | PPN低位8组 |
61. **`io_ptw_req_2_bits_vpn`**: PTW 请求 2 的虚拟页号。 | io_ptw_resp_bits_s1_valididx_[0-7] | `input` | 8×1 | 页表项索引有效性(位图) |
62. **`io_ptw_req_2_bits_s2xlate`**: PTW 请求 2 的 S2 转换位。 | io_ptw_resp_bits_s1_pteidx_[0-7] | `input` | 8×1 | 真实PTE索引位图 |
63. **`io_ptw_req_2_bits_getGpa`**: PTW 请求 2 的获取 GPA 信号。 | io_ptw_resp_bits_s1_pf | `input` | 1 | 第一级转换缺页错误标志 |
| io_ptw_resp_bits_s1_af | `input` | 1 | 第一级转换访问错误标志 |
#### PTW 响应信号 | **s2_entry 相关信号** | | | **第二级转换响应信息** |
| io_ptw_resp_bits_s2_entry_tag | `input` | 38 | 标签GPA高位 |
64. **`io_ptw_resp_valid`**: PTW 响应有效信号。 | io_ptw_resp_bits_s2_entry_vmid | `input` | 14 | VMID |
65. **`io_ptw_resp_bits_s2xlate`**: PTW 响应的 S2 转换位。 | io_ptw_resp_bits_s2_entry_n | `input` | 1 | 非叶子节点标志 |
66. **`io_ptw_resp_bits_s1_entry_tag`**: PTW 响应的第一级页表条目标签。 | io_ptw_resp_bits_s2_entry_pbmt | `input` | 2 | 物理内存保护类型 |
67. **`io_ptw_resp_bits_s1_entry_asid`**: PTW 响应的第一级页表条目 ASID。 | io_ptw_resp_bits_s2_entry_ppn | `input` | 38 | 物理页号PPN |
68. **`io_ptw_resp_bits_s1_entry_vmid`**: PTW 响应的第一级页表条目 VMID。 | io_ptw_resp_bits_s2_entry_perm_d | `input` | 1 | 脏位标志D |
69. **`io_ptw_resp_bits_s1_entry_perm_d`**: PTW 响应的第一级页表条目可写位。 | io_ptw_resp_bits_s2_entry_perm_a | `input` | 1 | 访问位A |
70. **`io_ptw_resp_bits_s1_entry_perm_a`**: PTW 响应的第一级页表条目已访问位。 | io_ptw_resp_bits_s2_entry_perm_g | `input` | 1 | 全局映射G |
71. **`io_ptw_resp_bits_s1_entry_perm_g`**: PTW 响应的第一级页表条目全局位。 | io_ptw_resp_bits_s2_entry_perm_u | `input` | 1 | 用户模式访问位U |
72. **`io_ptw_resp_bits_s1_entry_perm_u`**: PTW 响应的第一级页表条目用户模式位。 | io_ptw_resp_bits_s2_entry_perm_x | `input` | 1 | 执行位X |
73. **`io_ptw_resp_bits_s1_entry_perm_x`**: PTW 响应的第一级页表条目可执行位。 | io_ptw_resp_bits_s2_entry_perm_w | `input` | 1 | 写位W |
74. **`io_ptw_resp_bits_s1_entry_perm_w`**: PTW 响应的第一级页表条目可写位。 | io_ptw_resp_bits_s2_entry_perm_r | `input` | 1 | 读位R |
75. **`io_ptw_resp_bits_s1_entry_perm_r`**: PTW 响应的第一级页表条目可读位。 | io_ptw_resp_bits_s2_entry_level | `input` | 2 | 页表级0-2 |
76. **`io_ptw_resp_bits_s1_entry_level`**: PTW 响应的第一级页表条目级别。 | io_ptw_resp_bits_s2_gpf | `input` | 1 | 第二级转换非法权限错误标志 |
77. **`io_ptw_resp_bits_s1_entry_ppn`**: PTW 响应的第一级页表条目物理页号PPN | io_ptw_resp_bits_s2_gaf | `input` | 1 | 第二级转换访问错误标志 |
78. **`io_ptw_resp_bits_s1_addr_low`**: PTW 响应的第一级页表条目地址低位。 | io_ptw_resp_bits_getGpa | `input` | 1 | 响应中是否包含GPA |
79. **`io_ptw_resp_bits_s1_ppn_low_*`**: PTW 响应的第一级页表条目 PPN 低位。
80. **`io_ptw_resp_bits_s1_valididx_*`**: PTW 响应的第一级页表条目有效索引。
81. **`io_ptw_resp_bits_s1_pteidx_*`**: PTW 响应的第一级页表条目 PTE 索引。
82. **`io_ptw_resp_bits_s1_pf`**: PTW 响应的第一级页表条目页错误信号。
83. **`io_ptw_resp_bits_s1_af`**: PTW 响应的第一级页表条目访问错误信号。
84. **`io_ptw_resp_bits_s2_entry_tag`**: PTW 响应的第二级页表条目标签。
85. **`io_ptw_resp_bits_s2_entry_vmid`**: PTW 响应的第二级页表条目 VMID。
86. **`io_ptw_resp_bits_s2_entry_ppn`**: PTW 响应的第二级页表条目 PPN。
87. **`io_ptw_resp_bits_s2_entry_perm_*`**: PTW 响应的第二级页表条目的权限位。
88. **`io_ptw_resp_bits_s2_entry_level`**: PTW 响应的第二级页表条目级别。
89. **`io_ptw_resp_bits_s2_gpf`**: PTW 响应的第二级页表条目 GPF 信号。
90. **`io_ptw_resp_bits_s2_gaf`**: PTW 响应的第二级页表条目 GAF 信号。
91. **`io_ptw_resp_bits_getGpa`**: PTW 响应的获取 GPA 信号。
## 二、测试用 Bundle 说明 ## 二、测试用 Bundle 说明
- **`TLBWrapper`** | **TLBWrapper** | | |
- `clock` |----------------|------------------------------|---------------------|
- `ctrl` |`clock` | | |
- `reset` |`ctrl` | `reset` | |
- `io_sfence_valid` | | `io_sfence_valid` | |
- `io_requestor_2_resp_ready` | | `io_hartId` | |
- `io_requestor_2_resp_valid` | | `io_requestor_2_resp_ready` | |
- `io_ptw_req_0_valid` | | `io_requestor_2_resp_valid` | |
- `io_ptw_req_1_valid` | | `io_ptw_req_0_valid` | |
- `io_ptw_req_2_ready` | | `io_ptw_req_1_valid` | |
- `io_ptw_req_2_valid` | | `io_ptw_req_2_ready` | |
- `io_ptw_resp_valid` | | `io_ptw_req_2_valid` | |
- `io_ptw_resp_bits_s2xlate` | | `io_ptw_resp_valid` | |
- `io_ptw_resp_bits_getGpa` | | `io_ptw_resp_bits_s2xlate` | |
- `sfence` | | `io_ptw_resp_bits_getGpa` | |
- `rs1` | `sfence` | `rs1` | |
- `rs2` | | `rs2` | |
- `addr` | | `addr` | |
- `id` | | `id` | |
- `flushPipe` | | `flushPipe` | |
- `hv` | | `hv` | |
- `hg` | | `hg` | |
- `csr` | `csr` | `satp` | `mode` |
- `satp` | | | `asid` |
- `mode` | | | `changed` |
- `asid` | | `vsatp` | `mode` |
- `changed` | | | `asid` |
- `vsatp` | | | `changed` |
- `mode` | | `hgatp` | `mode` |
- `asid` | | | `vmid` |
- `changed` | | | `changed` |
- `hgatp` | | `priv` | `virt` |
- `mode` | | | `imode` |
- `vmid` | `requestor_0` | `req` | `valid` |
- `changed` | | | `bits_vaddr` |
- `priv` | | `resp` | `paddr_0` |
- `virt` | | | `gpaddr_0` |
- `imode` | | | `pbmt_0` |
- `requestor_0` | | | `miss` |
- `req` | | | `idForVSnonLeafPTE` |
- `valid` | | | `excp_0_gpf_instr` |
- `bits_vaddr` | | | `excp_0_pf_instr` |
- `resp` | | | `excp_0_af_instr` |
- `paddr_0` | `requestor_1` | `req` | `valid` |
- `gpaddr_0` | | | `bits_vaddr` |
- `miss` | | `resp` | `paddr_0` |
- `excp_0_gpf_instr` | | | `gpaddr_0` |
- `excp_0_pf_instr` | | | `pbmt_0` |
- `excp_0_af_instr` | | | `miss` |
- `requestor_1` | | | `idForVSnonLeafPTE` |
- `req` | | | `excp_0_gpf_instr` |
- `valid` | | | `excp_0_pf_instr` |
- `bits_vaddr` | | | `excp_0_af_instr` |
- `resp` | `requestor_0` | `req` | `valid` |
- `paddr_0` | | | `ready` |
- `gpaddr_0` | | | `bits_vaddr` |
- `miss` | | `resp` | `paddr_0` |
- `excp_0_gpf_instr` | | | `gpaddr_0` |
- `excp_0_pf_instr` | | | `pbmt_0` |
- `excp_0_af_instr` | | | `miss` |
- `requestor_2` | | | `idForVSnonLeafPTE` |
- `req` | | | `excp_0_gpf_instr` |
- `valid` | | | `excp_0_pf_instr` |
- `ready` | | | `excp_0_af_instr` |
- `bits_vaddr` | `flushPipe[3]` | | |
- `resp` | `ptw_req_0` | `vpn` | |
- `paddr_0` | | `s2xlate` | |
- `gpaddr_0` | | `getGpa` | |
- `excp_0_gpf_instr` | `ptw_req_1` | `vpn` | |
- `excp_0_pf_instr` | | `s2xlate` | |
- `excp_0_af_instr` | | `getGpa` | |
- `flushPipe[3]` | `ptw_req_2` | `vpn` | |
- `ptw_req_0` | | `s2xlate` | |
- `vpn` | | `getGpa` | |
- `s2xlate` | `ptw_resp_s1` | `entry_tag` | |
- `getGpa` | | `entry_asid` | |
- `ptw_req_1` | | `entry_vmid` | |
- `vpn` | | `entry_n` | |
- `s2xlate` | | `entry_pbmt` | |
- `getGpa` | | `entry_perm_d` | |
- `ptw_req_2` | | `entry_perm_a` | |
- `vpn` | | `entry_perm_g` | |
- `s2xlate` | | `entry_perm_u` | |
- `getGpa` | | `entry_perm_x` | |
- `ptw_resp_s1` | | `entry_perm_w` | |
- `entry_tag` | | `entry_perm_r` | |
- `entry_asid` | | `entry_level` | |
- `entry_vmid` | | `entry_v` | |
- `entry_perm_*` | | `entry_ppn` | |
- `entry_level` | | `addr_low` | |
- `entry_ppn` | | `ppn_low_0` | |
- `addr_low` | | `ppn_low_1` | |
- `ppn_low_*` | | `ppn_low_2` | |
- `valididx_*` | | `ppn_low_3` | |
- `pteidx_*` | | `ppn_low_4` | |
- `pf` | | `ppn_low_5` | |
- `af` | | `ppn_low_6` | |
- `ptw_resp_s2` | | `ppn_low_7` | |
- `entry_tag` | | `valididx_0` | |
- `entry_vmid` | | `valididx_1` | |
- `entry_perm_*` | | `valididx_2` | |
- `entry_level` | | `valididx_3` | |
- `gpf` | | `valididx_4` | |
- `gaf` | | `valididx_5` | |
| | `valididx_6` | |
| | `valididx_7` | |
| | `pteidx_0` | |
| | `pteidx_1` | |
| | `pteidx_2` | |
| | `pteidx_3` | |
| | `pteidx_4` | |
| | `pteidx_5` | |
| | `pteidx_6` | |
| | `pteidx_7` | |
| | `pf` | |
| | `af` | |
| `ptw_resp_s2` | `entry_tag` | |
| | `entry_vmid` | |
| | `entry_n` | |
| | `entry_pbmt` | |
| | `entry_ppn` | |
| | `entry_perm_d` | |
| | `entry_perm_a` | |
| | `entry_perm_g` | |
| | `entry_perm_u` | |
| | `entry_perm_x` | |
| | `entry_perm_w` | |
| | `entry_perm_r` | |
| | `entry_level` | |
| | `gpf` | |
| | `gaf` | |
## 三、测试用例格式(方便复制粘贴) ## 三、测试用例格式(方便复制粘贴)
```python
def test_TODO(tlb_fixture): def test_TODO(tlb_fixture):
""" """
Func: TODO Func: TODO
@ -271,3 +327,4 @@ def test_TODO(tlb_fixture):
tlb.dut.Step(2) tlb.dut.Step(2)
# assert result # assert result
```

View File

@ -14,4 +14,38 @@
class consts(): class consts():
Width = 3 Width = 3
nRespDups = 1 nRespDups = 1
class BaseConstant(int):
"""特殊常量基类"""
__slots__ = ()
_name = ""
_value = None
def __new__(cls):
return int.__new__(cls, cls._value)
def __repr__(self):
return f"<{self._name}>"
def __str__(self):
return self._name
def __eq__(self, other):
return other == self._value or other is self
class DontCareType(BaseConstant):
_name = "DONTCARE"
_value = 0
class Unused0Type(BaseConstant):
_name = "UNUSED_0"
_value = 0
class Unused1Type(BaseConstant):
_name = "UNUSED_1"
_value = 1
DONTCARE = DontCareType()
UNUSED0 = Unused0Type()
UNUSED1 = Unused1Type()

View File

@ -88,6 +88,7 @@ class ControlBundle(toffee.Bundle):
signals = [ signals = [
"reset", "reset",
"io_sfence_valid", "io_sfence_valid",
"io_hartId",
"io_requestor_2_resp_ready", "io_requestor_2_resp_ready",
"io_requestor_2_resp_valid", "io_requestor_2_resp_valid",
"io_ptw_req_0_valid", "io_ptw_req_0_valid",
@ -323,15 +324,95 @@ class TLBWrapper(toffee.Bundle):
req_2_valid, req_2_vaddr = self.rand_req2() req_2_valid, req_2_vaddr = self.rand_req2()
return req_0_valid, req_0_vaddr, req_1_valid, req_1_vaddr, req_2_valid, req_2_vaddr return req_0_valid, req_0_vaddr, req_1_valid, req_1_vaddr, req_2_valid, req_2_vaddr
def gene_rand_ptw_resp(self, vpn, s2xlate): def rand_ptw_resp(self, vpn, asid, s2xlate):
""" """
generate random PTW response by s2xlate generate random PTW response by s2xlate
""" """
self.ctrl.io_ptw_resp_valid = 1 # generate random input signals
self.ctrl.io_ptw_resp_bits_s2xlate = s2xlate randPPN = random.randint(0, 2 ** 36 - 1)
# nos2xlate (s2xlate == 0b00) randValididx = [random.choice([0,1]) for _ in range(8)]
self.ptw_resp_s1.entry_tag = vpn >> 12 randPPN_low = [random.randint(0, 2 ** 3 - 1) for _ in range(8)]
self.ptw_resp_s1.entry_asid
addr_low = vpn & 0b111
# assign to DUT
## ctrl signals
self.ctrl.io_ptw_resp_valid.value = 1
self.ctrl.io_ptw_resp_bits_s2xlate.value = s2xlate
## nos2xlate (s2xlate == 0b00)
if (s2xlate == 0b00):
self.ptw_resp_s1.entry_tag.value = vpn >> 3
self.ptw_resp_s1.entry_asid.value = asid
self.ptw_resp_s1.entry_vmid.value = DONTCARE
self.ptw_resp_s1.entry_n.value = UNUSED0
self.ptw_resp_s1.entry_pbmt.value = UNUSED0
self.ptw_resp_s1.entry_perm_d.value = UNUSED0
self.ptw_resp_s1.entry_perm_a.value = UNUSED0
self.ptw_resp_s1.entry_perm_g.value = UNUSED0
self.ptw_resp_s1.entry_perm_u.value = UNUSED0
self.ptw_resp_s1.entry_perm_x.value = UNUSED1
self.ptw_resp_s1.entry_perm_w.value = UNUSED0
self.ptw_resp_s1.entry_perm_r.value = UNUSED0
self.ptw_resp_s1.entry_level.value = UNUSED0
self.ptw_resp_s1.entry_v.value = 1
self.ptw_resp_s1.entry_ppn.value = randPPN >> 3
self.ptw_resp_s1.addr_low.value = addr_low
ppn_low_dict = {
0: self.ptw_resp_s1.ppn_low_0,
1: self.ptw_resp_s1.ppn_low_1,
2: self.ptw_resp_s1.ppn_low_2,
3: self.ptw_resp_s1.ppn_low_3,
4: self.ptw_resp_s1.ppn_low_4,
5: self.ptw_resp_s1.ppn_low_5,
6: self.ptw_resp_s1.ppn_low_6,
7: self.ptw_resp_s1.ppn_low_7
}
valididx_dict = {
0: self.ptw_resp_s1.valididx_0,
1: self.ptw_resp_s1.valididx_1,
2: self.ptw_resp_s1.valididx_2,
3: self.ptw_resp_s1.valididx_3,
4: self.ptw_resp_s1.valididx_4,
5: self.ptw_resp_s1.valididx_5,
6: self.ptw_resp_s1.valididx_6,
7: self.ptw_resp_s1.valididx_7
}
pteidx_dict = {
0: self.ptw_resp_s1.pteidx_0,
1: self.ptw_resp_s1.pteidx_1,
2: self.ptw_resp_s1.pteidx_2,
3: self.ptw_resp_s1.pteidx_3,
4: self.ptw_resp_s1.pteidx_4,
5: self.ptw_resp_s1.pteidx_5,
6: self.ptw_resp_s1.pteidx_6,
7: self.ptw_resp_s1.pteidx_7
}
for i in range(8):
if i == addr_low:
ppn_low_dict[i].value = randPPN & 0b111
valididx_dict[i].value = 1
else:
ppn_low_dict[i].value = randPPN_low[i]
valididx_dict[i].value = randValididx[i]
pteidx_dict[addr_low].value = 1
self.ptw_resp_s1.pf.value = UNUSED0
self.ptw_resp_s1.af.value = UNUSED0
## OnlyStage1 (s2xlate == 0b01)
elif (s2xlate == 0b01):
self.ptw_resp_s1.entry_tag.value = vpn >> 12
self.ptw_resp_s1.entry_asid.value = asid
# TODO
## OnlyStage2 (s2xlate == 0b10)
elif (s2xlate == 0b10):
self.ptw_resp_s1.entry_tag.value = vpn >> 12
self.ptw_resp_s1.entry_asid.value = asid
# TODO
## AllStage (s2xlate == 0b11)
else:
self.ptw_resp_s1.entry_tag.value = vpn >> 12
self.ptw_resp_s1.entry_asid.value = asid
# TODO
return randPPN
class TLBrwWrapper(toffee.Bundle): class TLBrwWrapper(toffee.Bundle):
""" """
@ -432,4 +513,4 @@ class TLBrwWrapper(toffee.Bundle):
self.dut.Step(10) self.dut.Step(10)
self.dut.reset.value = 0 self.dut.reset.value = 0
self.dut.Step(2) self.dut.Step(2)
# print(">>> RESET FINISHED !") # print(">>> RESET FINISHED !")

View File

@ -19,7 +19,7 @@ import inspect
# Running the following test case will show a pass: # Running the following test case will show a pass:
def test_receive_ptw_resp_nonstage(tlb_fixture): def test_receive_ptw_resp_nonstage(tlb_fixture):
""" """
Func: TODO Func: receive PTW response under nonstage condition and stored it into TLB entry
subfunc1: TODO subfunc1: TODO
""" """
# connect to fixture # connect to fixture
@ -38,10 +38,30 @@ def test_receive_ptw_resp_nonstage(tlb_fixture):
# add clock # add clock
tlb.dut.xclock.StepRis(lambda _: g.sample()) tlb.dut.xclock.StepRis(lambda _: g.sample())
# start # start
for _ in range(10000): for _ in range(1000):
# add signal and assign to dut for _ in range(30):
# add signal and assign to dut
vaddr = random.randint(0, 2 ** 50 - 1)
asid = random.randint(0, 2 ** 16 - 1)
vpn = vaddr >> 12
offset = vaddr & 0xfff
s2xlate = 0b00
ppn = tlb.rand_ptw_resp(vpn, asid, s2xlate)
# step to next cycle tlb.csr.satp.asid.value = asid
tlb.dut.Step(2)
# assert result # step to next cycle
tlb.dut.Step()
# check whether PTW resp is stored
tlb.requestor_0.req.valid.value = 1
tlb.requestor_0.req.bits_vaddr.value = (vpn << 12) | offset
# step to next cycle
tlb.dut.Step(2)
# assert result
assert(tlb.requestor_0.resp.paddr_0.value == ((ppn << 12) | offset))
assert(tlb.requestor_0.resp.miss.value == 0)
# reset
tlb.reset()