Compare commits

..

1 Commits

21 changed files with 511 additions and 616 deletions

View File

@ -18,7 +18,7 @@ weight: 13
```bash
git clone https://github.com/XS-MLVP/UnityChipForXiangShan.git
cd UnityChipForXiangShan
pip3 install -r requirements.txt # 安装 python 依赖(例如 toffee
pip3 install -r requirements.txt # 安装python依赖例如 toffee
```
#### 下载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。
```bash
make rtl # 该命令下载最新的 rtl 代码,解压至 rtl 目录,并创建软链
make rtl # 该命下载最新的rtl代码并解压至rtl目录并创建软连
```
可以用以下命令指定下载的 rtl 版本:
可以用以下命令指定下载的rtl版本
```bash
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压缩包的命名规范为`名称-微架构-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
openxiangshan-kmh-97e37a2237-24092701.tar.gz

View File

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

View File

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

View File

@ -13,10 +13,6 @@ async def ctrlunit_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock")
start_clock(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
cur_loop = asyncio.get_event_loop()

View File

@ -13,10 +13,6 @@ async def icache_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock")
start_clock(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
cur_loop = asyncio.get_event_loop()

View File

@ -8,6 +8,21 @@ class IPrefetchPipeAgent(Agent):
super().__init__(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):

View File

@ -14,10 +14,6 @@ async def iprefetchpipe_env(toffee_request: toffee_test.ToffeeRequest):
start_clock(dut)
iprefetchpipe_env = IPrefetchPipeEnv(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
cur = asyncio.get_event_loop()

View File

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

View File

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

View File

@ -8,17 +8,25 @@ class ICacheMainPipeAgent(Agent):
bundle.set_all(0)
self.bundle = bundle
async def flush_s0_fire(self):
async def set_flush(self):
# set s0_fire
self.bundle.io._dataArray._toIData._3._ready.value = 1
self.bundle.io._wayLookupRead._valid.value = 1
self.bundle.io._fetch._req._valid.value = 1
await self.bundle.step()
print( f"\nBefore setting: s0_fire is: ",self.bundle.ICacheMainPipe._s0_fire.value)
print(
f"\nBefore 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 \
"
)
self.bundle.io._flush.value = 1
await self.bundle.step()
print( f"After setting: s0_fire is: ",self.bundle.ICacheMainPipe._s0_fire.value)
print(
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,231 +1,282 @@
from toffee import Bundle, Signals, Signal
class _0Bundle(Bundle):
_fire, _valid = Signals(2)
_4 = Signal()
class _1Bundle(Bundle):
_s2 = _0Bundle.from_prefix("_s2")
_s0_fire = Signal()
_valid_T = _0Bundle.from_prefix("_valid_T")
class _2Bundle(Bundle):
_4 = Signal()
_0 = _1Bundle.from_prefix("_0")
_1 = _1Bundle.from_prefix("_1")
class _3Bundle(Bundle):
_valid_T = _2Bundle.from_prefix("_valid_T")
_fire, _valid = Signals(2)
class _4Bundle(Bundle):
_1 = _3Bundle.from_prefix("_1")
_0 = _3Bundle.from_prefix("_0")
_6, _7, _3, _5, _4, _1, _2, _0 = Signals(8)
class _5Bundle(Bundle):
_1, _7, _3, _4, _6, _2, _5, _0 = Signals(8)
_datas = _4Bundle.from_prefix("_datas")
_codes = _4Bundle.from_prefix("_codes")
class _6Bundle(Bundle):
_datas = _5Bundle.from_prefix("_datas")
_codes = _5Bundle.from_prefix("_codes")
_1, _0 = Signals(2)
class _7Bundle(Bundle):
_1, _0 = Signals(2)
_1, _0, _2, _3 = Signals(4)
class _8Bundle(Bundle):
_1, _2, _3, _0 = Signals(4)
_1 = _7Bundle.from_prefix("_1")
_0 = _7Bundle.from_prefix("_0")
class _9Bundle(Bundle):
_0 = _8Bundle.from_prefix("_0")
_1 = _8Bundle.from_prefix("_1")
_waymask = _8Bundle.from_prefix("_waymask")
_vSetIdx = _6Bundle.from_prefix("_vSetIdx")
_blkOffset = Signal()
class _10Bundle(Bundle):
_waymask = _9Bundle.from_prefix("_waymask")
_vSetIdx = _7Bundle.from_prefix("_vSetIdx")
_blkOffset = Signal()
_bits = _9Bundle.from_prefix("_bits")
_valid = Signal()
class _11Bundle(Bundle):
_bits = _10Bundle.from_prefix("_bits")
_valid = Signal()
_bits_vSetIdx = _6Bundle.from_prefix("_bits_vSetIdx")
_valid = Signal()
class _12Bundle(Bundle):
_bits_vSetIdx = _7Bundle.from_prefix("_bits_vSetIdx")
_valid = Signal()
_bits_vSetIdx = _6Bundle.from_prefix("_bits_vSetIdx")
_ready, _valid = Signals(2)
class _13Bundle(Bundle):
_bits_vSetIdx = _7Bundle.from_prefix("_bits_vSetIdx")
_valid, _ready = Signals(2)
_3 = _12Bundle.from_prefix("_3")
_1 = _11Bundle.from_prefix("_1")
_2 = _11Bundle.from_prefix("_2")
_0 = _10Bundle.from_prefix("_0")
class _14Bundle(Bundle):
_3 = _13Bundle.from_prefix("_3")
_1 = _12Bundle.from_prefix("_1")
_2 = _12Bundle.from_prefix("_2")
_0 = _11Bundle.from_prefix("_0")
_fromIData = _5Bundle.from_prefix("_fromIData")
_toIData = _13Bundle.from_prefix("_toIData")
class _15Bundle(Bundle):
_toIData = _14Bundle.from_prefix("_toIData")
_fromIData = _6Bundle.from_prefix("_fromIData")
_report_to_beu, _paddr = Signals(2)
class _16Bundle(Bundle):
_paddr, _report_to_beu = Signals(2)
_bits = _15Bundle.from_prefix("_bits")
_valid = Signal()
class _17Bundle(Bundle):
_bits = _16Bundle.from_prefix("_bits")
_valid = Signal()
_0 = _16Bundle.from_prefix("_0")
_1 = _16Bundle.from_prefix("_1")
class _18Bundle(Bundle):
_0 = _17Bundle.from_prefix("_0")
_1 = _17Bundle.from_prefix("_1")
_startAddr, _nextlineStart = Signals(2)
class _19Bundle(Bundle):
_nextlineStart, _startAddr = Signals(2)
_1 = _18Bundle.from_prefix("_1")
_3 = _18Bundle.from_prefix("_3")
_0 = _18Bundle.from_prefix("_0")
_4 = _18Bundle.from_prefix("_4")
_2 = _18Bundle.from_prefix("_2")
class _20Bundle(Bundle):
_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")
_3, _4, _1, _2, _0 = Signals(5)
class _21Bundle(Bundle):
_1, _3, _4, _2, _0 = Signals(5)
_readValid = _20Bundle.from_prefix("_readValid")
_pcMemRead = _19Bundle.from_prefix("_pcMemRead")
_backendException = Signal()
class _22Bundle(Bundle):
_pcMemRead = _20Bundle.from_prefix("_pcMemRead")
_readValid = _21Bundle.from_prefix("_readValid")
_backendException = Signal()
_bits = _21Bundle.from_prefix("_bits")
_ready, _valid = Signals(2)
class _23Bundle(Bundle):
_bits = _22Bundle.from_prefix("_bits")
_valid, _ready = Signals(2)
_0 = Signal()
class _24Bundle(Bundle):
_0 = Signal()
_exception = _6Bundle.from_prefix("_exception")
_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):
_vaddr = _7Bundle.from_prefix("_vaddr")
_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)
_bits = _24Bundle.from_prefix("_bits")
_valid = Signal()
class _26Bundle(Bundle):
_bits = _25Bundle.from_prefix("_bits")
_valid = Signal()
_resp = _25Bundle.from_prefix("_resp")
_req = _22Bundle.from_prefix("_req")
_topdownIcacheMiss, _topdownItlbMiss = Signals(2)
class _27Bundle(Bundle):
_resp = _26Bundle.from_prefix("_resp")
_req = _23Bundle.from_prefix("_req")
_topdownIcacheMiss, _topdownItlbMiss = Signals(2)
_virIdx, _waymask = Signals(2)
class _28Bundle(Bundle):
_waymask, _virIdx = Signals(2)
_bits = _27Bundle.from_prefix("_bits")
_valid = Signal()
class _29Bundle(Bundle):
_bits = _28Bundle.from_prefix("_bits")
_valid = Signal()
_0 = _28Bundle.from_prefix("_0")
_1 = _28Bundle.from_prefix("_1")
class _30Bundle(Bundle):
_1 = _29Bundle.from_prefix("_1")
_0 = _29Bundle.from_prefix("_0")
_blkPaddr, _vSetIdx = Signals(2)
class _31Bundle(Bundle):
_blkPaddr, _vSetIdx = Signals(2)
_bits = _30Bundle.from_prefix("_bits")
_valid, _ready = Signals(2)
class _32Bundle(Bundle):
_bits = _31Bundle.from_prefix("_bits")
_valid, _ready = Signals(2)
_corrupt, _blkPaddr, _vSetIdx, _data = Signals(4)
class _33Bundle(Bundle):
_data, _blkPaddr, _vSetIdx, _corrupt = Signals(4)
_bits = _32Bundle.from_prefix("_bits")
_valid = Signal()
class _34Bundle(Bundle):
_bits = _33Bundle.from_prefix("_bits")
_valid = Signal()
_resp = _33Bundle.from_prefix("_resp")
_req = _31Bundle.from_prefix("_req")
class _35Bundle(Bundle):
_resp = _34Bundle.from_prefix("_resp")
_req = _32Bundle.from_prefix("_req")
_1 = Signal()
class _36Bundle(Bundle):
_1 = Signal()
_miss = _35Bundle.from_prefix("_miss")
_hit = _35Bundle.from_prefix("_hit")
_except = _35Bundle.from_prefix("_except")
class _37Bundle(Bundle):
_hit = _36Bundle.from_prefix("_hit")
_except = _36Bundle.from_prefix("_except")
_miss = _36Bundle.from_prefix("_miss")
_0 = _36Bundle.from_prefix("_0")
class _38Bundle(Bundle):
_0 = _37Bundle.from_prefix("_0")
_hit, _miss = Signals(2)
class _39Bundle(Bundle):
_miss, _hit = Signals(2)
_0 = _38Bundle.from_prefix("_0")
class _40Bundle(Bundle):
_0 = _39Bundle.from_prefix("_0")
_except = _23Bundle.from_prefix("_except")
_miss = _37Bundle.from_prefix("_miss")
_bank_hit = _6Bundle.from_prefix("_bank_hit")
_only = _39Bundle.from_prefix("_only")
_hit = Signal()
class _41Bundle(Bundle):
_bank_hit = _7Bundle.from_prefix("_bank_hit")
_miss = _38Bundle.from_prefix("_miss")
_except = _24Bundle.from_prefix("_except")
_only = _40Bundle.from_prefix("_only")
_hit = Signal()
_mmio, _instr = Signals(2)
class _42Bundle(Bundle):
_instr, _mmio = Signals(2)
_resp = _41Bundle.from_prefix("_resp")
_req_bits_addr = Signal()
class _43Bundle(Bundle):
_resp = _42Bundle.from_prefix("_resp")
_req_bits_addr = Signal()
_0 = _42Bundle.from_prefix("_0")
_1 = _42Bundle.from_prefix("_1")
class _44Bundle(Bundle):
_1 = _43Bundle.from_prefix("_1")
_0 = _43Bundle.from_prefix("_0")
_way, _vSetIdx = Signals(2)
class _45Bundle(Bundle):
_way, _vSetIdx = Signals(2)
_bits = _44Bundle.from_prefix("_bits")
_valid = Signal()
class _46Bundle(Bundle):
_bits = _45Bundle.from_prefix("_bits")
_valid = Signal()
_0 = _45Bundle.from_prefix("_0")
_1 = _45Bundle.from_prefix("_1")
class _47Bundle(Bundle):
_0 = _46Bundle.from_prefix("_0")
_1 = _46Bundle.from_prefix("_1")
_pbmt = _6Bundle.from_prefix("_pbmt")
_exception = _6Bundle.from_prefix("_exception")
class _48Bundle(Bundle):
_pbmt = _7Bundle.from_prefix("_pbmt")
_exception = _7Bundle.from_prefix("_exception")
_waymask = _6Bundle.from_prefix("_waymask")
_ptag = _6Bundle.from_prefix("_ptag")
_vSetIdx = _6Bundle.from_prefix("_vSetIdx")
_meta_codes = _6Bundle.from_prefix("_meta_codes")
_itlb = _47Bundle.from_prefix("_itlb")
class _49Bundle(Bundle):
_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")
_gpaddr, _isForVSnonLeafPTE = Signals(2)
class _50Bundle(Bundle):
_isForVSnonLeafPTE, _gpaddr = Signals(2)
_entry = _48Bundle.from_prefix("_entry")
_gpf = _49Bundle.from_prefix("_gpf")
class _51Bundle(Bundle):
_entry = _49Bundle.from_prefix("_entry")
_gpf = _50Bundle.from_prefix("_gpf")
_bits = _50Bundle.from_prefix("_bits")
_ready, _valid = Signals(2)
class _52Bundle(Bundle):
_bits = _51Bundle.from_prefix("_bits")
_valid, _ready = Signals(2)
_dataArray = _14Bundle.from_prefix("_dataArray")
_pmp = _43Bundle.from_prefix("_pmp")
_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):
ICacheMainPipe = _1Bundle.from_prefix("ICacheMainPipe")
ICacheMainPipe__toMSHRArbiter_io_in = _4Bundle.from_prefix("ICacheMainPipe__toMSHRArbiter_io_in")
io = _53Bundle.from_prefix("io")
reset, clock = Signals(2)
ICacheMainPipe_s2 = _3Bundle.from_prefix("ICacheMainPipe_s2")
io = _52Bundle.from_prefix("io")
ICacheMainPipe__toMSHRArbiter_io_in = _2Bundle.from_prefix(
"ICacheMainPipe__toMSHRArbiter_io_in"
)
clock, reset = Signals(2)

View File

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

View File

@ -13,10 +13,6 @@ async def icachemainpipe_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock")
start_clock(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
cur_loop = asyncio.get_event_loop()

View File

@ -13,10 +13,6 @@ async def icachemissunit_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock")
start_clock(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
cur_loop = asyncio.get_event_loop()

View File

@ -1,6 +1,34 @@
from toffee import Agent
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):
def __init__(self, bundle: WayLookupBundle):
@ -8,30 +36,38 @@ class WayLookupAgent(Agent):
bundle.set_all(0)
self.bundle = bundle
async def flush_write_ptr(self):
# set io_write_fireio.write.ready is already 1
self.bundle.io._write._valid.value = 1
await self.bundle.step()
# set write_ptr by writting entry
self.bundle.io._write._bits._entry._vSetIdx._0.value = 0
self.bundle.io._write._bits._entry._vSetIdx._1.value = 1
self.bundle.io._write._bits._entry._waymask._0.value = 0
self.bundle.io._write._bits._entry._waymask._1.value = 1
self.bundle.io._write._bits._entry._ptag._0.value = 0
self.bundle.io._write._bits._entry._ptag._1.value = 1
self.bundle.io._write._bits._entry._itlb._exception._0.value = 0
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
async def flush(self) -> ReadBitsData:
ret = ReadBitsData()
ret.WayLookup_readPtr_value_before_flush = (
self.bundle.WayLookup._readPtr._value.value
)
ret.WayLookup_readPtr_flag_before_flush = (
self.bundle.WayLookup._readPtr._flag.value
)
ret.WayLookup_writePtr_value_before_flush = (
self.bundle.WayLookup._writePtr._value.value
)
ret.WayLookup_writePtr_flag_before_flush = (
self.bundle.WayLookup._writePtr._flag.value
)
self.bundle.io._flush.value = 1
await self.bundle.step()
# print
print("After flush, write_ptr is: ", self.bundle.WayLookup._writePtr._value.value)
await self.bundle.step()
ret.WayLookup_readPtr_value_after_flush = (
self.bundle.WayLookup._readPtr._value.value
)
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,10 +13,6 @@ async def waylookup_env(toffee_request: toffee_test.ToffeeRequest):
dut.InitClock("clock")
start_clock(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
cur_loop = asyncio.get_event_loop()

View File

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

View File

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

View File

@ -14,38 +14,4 @@
class consts():
Width = 3
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()
nRespDups = 1

View File

@ -88,7 +88,6 @@ class ControlBundle(toffee.Bundle):
signals = [
"reset",
"io_sfence_valid",
"io_hartId",
"io_requestor_2_resp_ready",
"io_requestor_2_resp_valid",
"io_ptw_req_0_valid",
@ -324,95 +323,15 @@ class TLBWrapper(toffee.Bundle):
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
def rand_ptw_resp(self, vpn, asid, s2xlate):
def gene_rand_ptw_resp(self, vpn, s2xlate):
"""
generate random PTW response by s2xlate
"""
# generate random input signals
randPPN = random.randint(0, 2 ** 36 - 1)
randValididx = [random.choice([0,1]) for _ in range(8)]
randPPN_low = [random.randint(0, 2 ** 3 - 1) for _ in range(8)]
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
self.ctrl.io_ptw_resp_valid = 1
self.ctrl.io_ptw_resp_bits_s2xlate = s2xlate
# nos2xlate (s2xlate == 0b00)
self.ptw_resp_s1.entry_tag = vpn >> 12
self.ptw_resp_s1.entry_asid
class TLBrwWrapper(toffee.Bundle):
"""
@ -513,4 +432,4 @@ class TLBrwWrapper(toffee.Bundle):
self.dut.Step(10)
self.dut.reset.value = 0
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:
def test_receive_ptw_resp_nonstage(tlb_fixture):
"""
Func: receive PTW response under nonstage condition and stored it into TLB entry
Func: TODO
subfunc1: TODO
"""
# connect to fixture
@ -38,30 +38,10 @@ def test_receive_ptw_resp_nonstage(tlb_fixture):
# add clock
tlb.dut.xclock.StepRis(lambda _: g.sample())
# start
for _ in range(1000):
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)
for _ in range(10000):
# add signal and assign to dut
tlb.csr.satp.asid.value = asid
# step to next cycle
tlb.dut.Step(2)
# 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()
# assert result