forked from XS-MLVP/UnityChipForXiangShan
Compare commits
16 Commits
main
...
pr-smy-ifu
| Author | SHA1 | Date |
|---|---|---|
|
|
4204b942e7 | |
|
|
56962b77dd | |
|
|
a5c34f6cfb | |
|
|
f35f96a3ba | |
|
|
708c440ce3 | |
|
|
502d823fc7 | |
|
|
15fea20a5f | |
|
|
f68fd0ad55 | |
|
|
6b4e2f0680 | |
|
|
a7f82fe823 | |
|
|
380febef36 | |
|
|
2a701680c8 | |
|
|
23fcd1f1ba | |
|
|
554bbfcf43 | |
|
|
663d857694 | |
|
|
5a01b8b026 |
|
|
@ -171,3 +171,6 @@ cython_debug/
|
|||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
.vscode/
|
||||
.metals/
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ class F3PreDecodeData():
|
|||
def __str__(self):
|
||||
return f"brTypes: {self.brTypes}\nisCalls: {self.isCalls}\nisRets: {self.isRets}"
|
||||
|
||||
def clear(self):
|
||||
self.brTypes = []
|
||||
self.isCalls = []
|
||||
self.isRets = []
|
||||
class F3PreDecoderAgent(Agent):
|
||||
|
||||
def __init__(self, bundle:F3PreDecoderBundle):
|
||||
|
|
@ -23,6 +27,7 @@ class F3PreDecoderAgent(Agent):
|
|||
await self.bundle.step()
|
||||
|
||||
ret = F3PreDecodeData()
|
||||
ret.clear()
|
||||
for i in range(16):
|
||||
ret.brTypes.append(getattr(self.bundle.io._out_pd, f"_{i}")._brType.value)
|
||||
ret.isCalls.append(getattr(self.bundle.io._out_pd, f"_{i}")._isCall.value)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,56 @@ import toffee_test
|
|||
from dut.F3Predecoder import DUTF3Predecoder
|
||||
from toffee import start_clock
|
||||
from ..env import F3PreDecoderEnv
|
||||
import toffee.funcov as fc
|
||||
from comm import UT_FCOV, module_name_with, get_version_checker
|
||||
|
||||
grp = fc.CovGroup(UT_FCOV("../../CLASSIC"))
|
||||
def init_cov(dut:DUTF3Predecoder, grp: fc.CovGroup):
|
||||
for i in range(16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is not cfi": lambda x: getattr(dut, f'io_out_pd_{i}_brType').value == 0,
|
||||
"instr is branch": lambda x: getattr(dut, f'io_out_pd_{i}_brType').value == 1,
|
||||
"instr is jal": lambda x: getattr(dut, f'io_out_pd_{i}_brType').value == 2,
|
||||
"instr is jalr": lambda x: getattr(dut, f'io_out_pd_{i}_brType').value == 3,
|
||||
},name = f'check_cfi_{i}')
|
||||
|
||||
for i in range(16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is RVI.JAL and is call": lambda x: getattr(dut, f'io_out_pd_{i}_isCall').value == 1 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b1101111,
|
||||
"instr is RVI.JAL and is not call or ret": lambda x: getattr(dut, f'io_out_pd_{i}_isCall').value == 0 and getattr(dut, f'io_out_pd_{i}_isRet').value == 0 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b1101111,
|
||||
"instr is RVC.JAL and is not call or ret": lambda x: getattr(dut, f'io_out_pd_{i}_isCall').value == 0 and getattr(dut, f'io_out_pd_{i}_isRet').value == 0 and getattr(dut, f'io_in_instr_{i}').value & 0b11 == 0b01 and (getattr(dut, f'io_in_instr_{i}').value >> 13) == 0b101,
|
||||
},name = f'check_jal_{i}')
|
||||
|
||||
for i in range(16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is RVI.JALR and is call":lambda x: getattr(dut, f'io_out_pd_{i}_isCall').value == 1 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b1100111,
|
||||
"instr is RVI.JALR and is ret":lambda x: getattr(dut, f'io_out_pd_{i}_isRet').value == 1 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b1100111,
|
||||
"instr is RVI.JALR and is not call or ret":lambda x: getattr(dut, f'io_out_pd_{i}_isRet').value == 0 and getattr(dut, f'io_out_pd_{i}_isCall').value == 0 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b1100111,
|
||||
"instr is RVC.JALR and is not call or ret":lambda x: getattr(dut, f'io_out_pd_{i}_isRet').value == 0 and getattr(dut, f'io_out_pd_{i}_isCall').value == 0 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b0000010 and (getattr(dut, f'io_in_instr_{i}').value >> 12) == 0b1001
|
||||
},name=f'check_jalr_{i}')
|
||||
|
||||
for i in range(16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is RVC.JR and is ret":lambda x: getattr(dut, f'io_out_pd_{i}_isRet').value == 1 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b0000010 and (getattr(dut, f'io_in_instr_{i}').value >> 12) == 0b1000,
|
||||
"instr is RVC.JR and is not call or ret":lambda x:getattr(dut, f'io_out_pd_{i}_isRet').value == 0 and getattr(dut, f'io_out_pd_{i}_isCall').value == 0 and getattr(dut, f'io_in_instr_{i}').value & 0b1111111 == 0b0000010 and (getattr(dut, f'io_in_instr_{i}').value >> 12) == 0b1000,
|
||||
},name=f'check_jr_{i}')
|
||||
|
||||
def _mark(name):
|
||||
return module_name_with(name, "../f3predecoder_test")
|
||||
|
||||
for i in range(16):
|
||||
grp.mark_function(f'check_cfi_{i}',_mark(["test_cfi_checker_1_1","test_cfi_checker_1_2","test_cfi_checker_1_3"]))
|
||||
grp.mark_function(f'check_jal_{i}',_mark(["test_cfi_checker_2_2_1_1","test_cfi_checker_2_2_1_2","test_cfi_checker_2_2_2"]))
|
||||
grp.mark_function(f'check_jalr_{i}',_mark(["test_cfi_checker_2_3_2_1","test_cfi_checker_2_3_1_2","test_cfi_checker_2_3_1_3","test_cfi_checker_2_3_2_1"]))
|
||||
grp.mark_function(f'check_jr_{i}',_mark(["test_cfi_checker_2_3_2_2_1","test_cfi_checker_2_3_2_2_2"]))
|
||||
return grp
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def f3predecoder_env(toffee_request: toffee_test.ToffeeRequest):
|
||||
import asyncio
|
||||
dut = toffee_request.create_dut(DUTF3Predecoder)
|
||||
toffee_request.add_cov_groups(init_cov(dut, grp))
|
||||
start_clock(dut)
|
||||
predecode_env = F3PreDecoderEnv(dut)
|
||||
yield predecode_env
|
||||
|
|
|
|||
|
|
@ -0,0 +1,231 @@
|
|||
import random
|
||||
|
||||
class F3PredecodeInstrGen():
|
||||
def __init__(self):
|
||||
self.brTypes = []
|
||||
self.isCalls = []
|
||||
self.isRets = []
|
||||
self.instrs = []
|
||||
|
||||
def clear(self):
|
||||
self.brTypes = []
|
||||
self.isCalls = []
|
||||
self.isRets = []
|
||||
self.instrs = []
|
||||
|
||||
def inst_gen(self, isa = 'random', type = 'not_cfi'):
|
||||
if type == 'br':
|
||||
#generate br type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
opcode = 0b1100011
|
||||
funct3 = random.choice([0b000,0b001,0b100,0b101,0b110,0b111])
|
||||
rs1 = random.getrandbits(5)
|
||||
rs2 = random.getrandbits(5)
|
||||
instr_rvi = (random.getrandbits(7) << 25) | rs1 << 20 |\
|
||||
rs2 << 15 | funct3 << 12 | (random.getrandbits(5) << 7) |\
|
||||
opcode
|
||||
|
||||
#rvc
|
||||
op = 0b01
|
||||
func3 = random.choice([0b110,0b111])
|
||||
instr_rvc = func3 << 13 | (random.getrandbits(11) << 2) | op
|
||||
|
||||
self.brTypes.append(1)
|
||||
if isa == 'random':
|
||||
self.instrs.append(random.choice([instr_rvi, instr_rvc]))
|
||||
elif isa == 'rvi':
|
||||
self.instrs.append(instr_rvi)
|
||||
elif isa == 'rvc':
|
||||
self.instrs.append(instr_rvc)
|
||||
|
||||
elif type == 'jal':
|
||||
#generate jal type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
opcode = 0b1101111
|
||||
instr_rvi = (random.getrandbits(25) << 7) | opcode
|
||||
|
||||
#rvc
|
||||
func3 = 0b101
|
||||
op = 0b01
|
||||
instr_rvc = (func3 << 13) | (random.getrandbits(11) << 2) | op
|
||||
|
||||
self.brTypes.append(2)
|
||||
if isa == 'random':
|
||||
self.instrs.append(random.choice([instr_rvi, instr_rvc]))
|
||||
elif isa == 'rvi':
|
||||
self.instrs.append(instr_rvi)
|
||||
elif isa == 'rvc':
|
||||
self.instrs.append(instr_rvc)
|
||||
|
||||
elif type == 'jalr':
|
||||
#generate jalr type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
funct3 = 0b000
|
||||
opcode = 0b1100111
|
||||
instr_rvi = (random.getrandbits(17) << 25) | funct3 << 12 |\
|
||||
(random.getrandbits(5) << 7) | opcode
|
||||
|
||||
#rvc
|
||||
rs1 = random.getrandbits(5) | 0b1
|
||||
head = random.choice([0b1001,0b1000])
|
||||
tail = 0b00000_10
|
||||
instr_rvc = (head << 12) | (rs1 << 7) | tail
|
||||
|
||||
self.brTypes.append(3)
|
||||
if isa == 'random':
|
||||
self.instrs.append(random.choice([instr_rvi, instr_rvc]))
|
||||
elif isa == 'rvi':
|
||||
self.instrs.append(instr_rvi)
|
||||
elif isa == 'rvc':
|
||||
self.instrs.append(instr_rvc)
|
||||
|
||||
elif type == 'not_cfi':
|
||||
#generate not cfi type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
opcode = random.getrandbits(7) | 0b11
|
||||
funct3 = random.getrandbits(3)
|
||||
|
||||
while True:
|
||||
flag1 = (opcode == 0b1100011) and (funct3 in [0b000,0b001,0b010,0b011,0b100,0b101,0b110,0b111])
|
||||
flag2 = (opcode == 0b1101111)
|
||||
flag3 = (opcode == 0b1100111) and (funct3 == 0b000)
|
||||
if not flag3 and not flag2 and not flag1:
|
||||
break
|
||||
opcode = random.getrandbits(7) | 0b11
|
||||
funct3 = random.getrandbits(3)
|
||||
instr_rvi = random.getrandbits(17) << 15 | funct3 << 12 | random.getrandbits(5) << 7 | opcode
|
||||
|
||||
#rvc
|
||||
c_ebreak = 0b100_1_00000_00000_10
|
||||
instr_rvc = random.getrandbits(16)
|
||||
while True:
|
||||
op = instr_rvc & 0b11
|
||||
func3 = instr_rvc >> 13
|
||||
flag1 = (op == 0b01) and (func3 in [0b110, 0b111, 0b101])
|
||||
|
||||
j1 = instr_rvc & 0b1111111
|
||||
j2 = instr_rvc >> 12
|
||||
flag2 = (j1 == 0b0000010) and (j2 in [0b1001, 0b1000])
|
||||
|
||||
flag3 = op == 0b11
|
||||
|
||||
if not flag1 and not flag2 and not flag3:
|
||||
break
|
||||
instr_rvc = random.getrandbits(16)
|
||||
|
||||
self.brTypes.append(0)
|
||||
self.instrs.append(random.choice([instr_rvc,instr_rvi,c_ebreak]))
|
||||
|
||||
return self.instrs, self.brTypes
|
||||
|
||||
def ret_call_checker(self,task = '2.1.1'):
|
||||
if task =='2.1.1':
|
||||
self.inst_gen(type = 'not_cfi')
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
if task == '2.1.2':
|
||||
self.inst_gen(type = 'br')
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
if task == '2.2.1.1':
|
||||
def rd():
|
||||
return random.choice([1, 5]) << 7
|
||||
mask = 0b1111_1111_1111_1111_1111_0000_0111_1111
|
||||
self.inst_gen(type = 'jal', isa = 'rvi')
|
||||
self.instrs = [i & mask | rd() for i in self.instrs]
|
||||
self.isCalls = [1 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
if task == '2.2.1.2':
|
||||
def rd():
|
||||
valid_numbers = [x for x in range(33) if x not in {1, 5}]
|
||||
num = random.choice(valid_numbers)
|
||||
return num << 7
|
||||
mask = 0b1111_1111_1111_1111_1111_0000_0111_1111
|
||||
self.inst_gen(type = 'jal', isa = 'rvi')
|
||||
self.instrs = [i & mask | rd() for i in self.instrs]
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
if task == '2.2.2':
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
self.inst_gen(type = 'jal', isa = 'rvc')
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
if task == '2.3.1.1':
|
||||
def rd():
|
||||
return random.choice([1, 5]) << 7
|
||||
mask = 0b1111_1111_1111_1111_1111_0000_0111_1111
|
||||
self.inst_gen(type = 'jalr', isa = 'rvi')
|
||||
self.instrs = [i & mask | rd() for i in self.instrs]
|
||||
self.isCalls = [1 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
|
||||
if task == '2.3.1.2':
|
||||
def rs():
|
||||
return random.choice([1,5]) << 15
|
||||
def rd():
|
||||
valid_numbers = [x for x in range(32) if x not in {1, 5}]
|
||||
num = random.choice(valid_numbers)
|
||||
return num << 7
|
||||
mask = 0b1111_1111_1111_0000_0111_0000_0111_1111
|
||||
self.inst_gen('jalr', 'rvi')
|
||||
self.inst_gen(type = 'jalr', isa = 'rvi')
|
||||
self.instrs = [i & mask | rd() | rs() for i in self.instrs]
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [1 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
|
||||
if task == '2.3.1.3':
|
||||
def rd():
|
||||
valid_numbers = [x for x in range(32) if x not in {1, 5}]
|
||||
num = random.choice(valid_numbers)
|
||||
return num << 7
|
||||
def rs():
|
||||
valid_numbers = [x for x in range(32) if x not in {1, 5}]
|
||||
num = random.choice(valid_numbers)
|
||||
return num << 15
|
||||
mask = 0b1111_1111_1111_0000_0111_0000_0111_1111
|
||||
self.inst_gen('jalr', 'rvi')
|
||||
self.inst_gen(type = 'jalr', isa = 'rvi')
|
||||
self.instrs = [i & mask | rd() | rs() for i in self.instrs]
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
|
||||
if task == '2.3.2.1':
|
||||
self.inst_gen(type = 'jalr', isa = 'rvc')
|
||||
self.instrs = [i | 1 << 12 for i in self.instrs]
|
||||
self.isCalls = [1 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
|
||||
if task == '2.3.2.2.1':
|
||||
def rs():
|
||||
return random.choice([1,5]) << 7
|
||||
mask = 0b1110000001111111
|
||||
self.inst_gen(type = 'jalr', isa = 'rvc')
|
||||
self.instrs = [i & mask | rs() for i in self.instrs]
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [1 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
|
||||
if task == '2.3.2.2.2':
|
||||
def rs():
|
||||
valid_numbers = [x for x in range(32) if x not in {1, 5}]
|
||||
num = random.choice(valid_numbers)
|
||||
return num << 7
|
||||
mask = 0b1110000001111111
|
||||
self.inst_gen(type = 'jalr', isa = 'rvc')
|
||||
self.instrs = [i & mask | rs() for i in self.instrs]
|
||||
self.isCalls = [0 for _ in range(16)]
|
||||
self.isRets = [0 for _ in range(16)]
|
||||
return self.instrs, self.isCalls, self.isRets
|
||||
|
||||
|
|
@ -1,10 +1,184 @@
|
|||
from .f3predecoder_fixture import f3predecoder_env
|
||||
from ..env import F3PreDecoderEnv
|
||||
import toffee_test
|
||||
from .f3predecoder_instr_gen import F3PredecodeInstrGen
|
||||
|
||||
instrGen = F3PredecodeInstrGen()
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_smoke(f3predecoder_env : F3PreDecoderEnv):
|
||||
instrs = [483 for i in range(16)]
|
||||
async def test_cfi_checker_1_1(f3predecoder_env : F3PreDecoderEnv):
|
||||
print("test_cfi_checker_1_1")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='not_cfi', isa='rvc')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='not_cfi', isa='rvi')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
print(await f3predecoder_env.agent.f3_predecode(instrs))
|
||||
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_cfi_checker_1_2(f3predecoder_env : F3PreDecoderEnv):
|
||||
print("test_cfi_checker_1_2")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='br', isa='rvi')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='br', isa='rvc')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_cfi_checker_1_3(f3predecoder_env : F3PreDecoderEnv):
|
||||
print("test_cfi_checker_1_3")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='jal', isa='rvi')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='jal', isa='rvc')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_cfi_checker_1_4(f3predecoder_env : F3PreDecoderEnv):
|
||||
print("test_cfi_checker_1_4")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='jalr', isa='rvi')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
instrGen.clear()
|
||||
instrs, brTypes = instrGen.inst_gen(type='jalr', isa='rvc')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.brTypes == brTypes
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_1_1(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check not cfi
|
||||
print("test_ret_call_checker_2_1_1")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.1.1')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_1_2(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check br
|
||||
print("test_ret_call_checker_2_1_2")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.1.2')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_2_1_1(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check RVI.JAL call
|
||||
print("test_ret_call_checker_2_2_1_1")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.2.1.1')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_2_1_2(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check RVI.JAL not call and ret
|
||||
print("test_ret_call_checker_2_2_1_2")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.2.1.2')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_2_2(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check RVC.JAL not call and ret
|
||||
print("test_ret_call_checker_2_2_2")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.2.2')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_3_1_1(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check RVI.JALR call
|
||||
print("test_ret_call_checker_2_3_1_1")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.3.1.1')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_3_1_2(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check RVI.JALR ret
|
||||
print("test_ret_call_checker_2_3_1_2")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.3.1.2')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_3_1_3(f3predecoder_env : F3PreDecoderEnv):
|
||||
#check RVI.JALR not call and ret
|
||||
print("test_ret_call_checker_2_3_1_3")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.3.1.3')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_3_2_1(f3predecoder_env: F3PreDecoderEnv):
|
||||
#check RVC.JALR call
|
||||
print("test_ret_call_checker_2_3_2_1")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.3.2.1')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_3_2_2_1(f3predecoder_env: F3PreDecoderEnv):
|
||||
#check RVC.JR ret
|
||||
print("test_ret_call_checker_2_3_2_2_1")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.3.2.2.1')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_ret_call_checker_2_3_2_2_2(f3predecoder_env: F3PreDecoderEnv):
|
||||
#check RVC.JR not ret
|
||||
print("test_ret_call_checker_2_3_2_2_2")
|
||||
for _ in range(2000):
|
||||
instrGen.clear()
|
||||
instrs, isCalls, isRets = instrGen.ret_call_checker(task = '2.3.2.2.2')
|
||||
res = await f3predecoder_env.agent.f3_predecode(instrs)
|
||||
assert res.isCalls == isCalls
|
||||
assert res.isRets == isRets
|
||||
|
|
|
|||
|
|
@ -18,32 +18,30 @@ TBD
|
|||
|
||||
## 功能点和测试点
|
||||
|
||||
| 序号 | 功能 | 名称 | 描述 |
|
||||
|--------|--------------------|--------------------|-----------------------------------------------------------------------------------------------|
|
||||
| 1\.1\.1 | BPU预测信息的JAL预测错误检查 | 误检测试1 | 预测块中没有JAL指令且最终预测信息也没有取用任何跳转指令的输入,检查PredChecker是否会误报JAL预测错误。 |
|
||||
| 1\.1\.2 | BPU预测信息的JAL预测错误检查 | 误检测试2 | 预测块中有JAL指令且最终预测信息取用的正是本条跳转指令的输入,检查PredChecker是否会误报JAL预测错误。 |
|
||||
| 1\.2\.1 | BPU预测信息的JAL预测错误检查 | 存在JAL未预测 | 预测块中存在JAL指令,但是最终预测信息未预测跳转,检查PredChecker是否能检测出JAL预测错误。 |
|
||||
| 1\.2\.2 | BPU预测信息的JAL预测错误检查 | 预测的JAL并非第一条 | 预测块中存在JAL指令,但是最终预测信息取的跳转指令在第一条JAL指令之后,检查PredChecker是否能检测出JAL预测错误。 |
|
||||
| 2\.1\.1 | BPU预测信息的RET预测错误检查 | 误检测试1 | 预测块中没有RET指令且最终预测信息也没有取用任何跳转指令的输入,检查PredChecker是否会误报RET预测错误。 |
|
||||
| 2\.1\.2 | BPU预测信息的RET预测错误检查 | 误检测试2 | 预测块中有RET指令且最终预测信息取用的正是本条跳转指令的输入,检查PredChecker是否会误报RET预测错误。 |
|
||||
| 2\.2\.1 | BPU预测信息的RET预测错误检查 | 存在RET未预测 | 预测块中存在RET指令,但是最终预测信息未预测跳转,检查PredChecker是否能检测出RET预测错误。 |
|
||||
| 2\.2\.2 | BPU预测信息的RET预测错误检查 | 预测的跳转并非第一条 | 预测块中存在RET指令,但是最终预测信息取的跳转指令在第一条RET指令之后,检查PredChecker是否能检测出RET预测错误。 |
|
||||
| 3\.1 | 更新指令有效范围向量和预测跳转的指令 | 有效范围无误 | 不存在任何错误的情况下,PredChecker应当保留之前的预测结果。 |
|
||||
| 3\.2 | 更新指令有效范围向量和预测跳转的指令 | RET和JAL预测错误引起的范围偏大 | 如果检测到了JAL或RET类的预测错误,PredChecker应该将有效指令的范围修正为预测块开始至第一条跳转指令。同时,应该将预测跳转的指令位置修正为预测块中的第一条跳转指令。 |
|
||||
| 3\.3 | 更新指令有效范围向量和预测跳转的指令 | 非CFI和无效指令引起的预测范围偏小 | 如果出现了非控制流指令和无效指令的误预测,应该将预测跳转的指令重新修正到预测块中第一条跳转指令 |
|
||||
| 4\.1\.1 | 非CFI预测错误检查 | 误检测试1 | 构造不存在CFI指令并且未预测跳转的预测信息作为输入,测试PredChecker是否会错检非CFI预测错误 |
|
||||
| 4\.1\.2 | 非CFI预测错误检查 | 误检测试2 | 构造存在CFI指令并且正确预测跳转的预测信息作为输入,测试PredChecker是否会错检非CFI预测错误 |
|
||||
| 4\.2 | 非CFI预测错误检查 | 正确检测测试 | 构造不存在CFI指令但是预测了跳转的预测信息作为输入,测试PredChecker是否能检查出非CFI预测错误 |
|
||||
| 5\.1\.1 | 无效指令预测错误检查 | 误检测试1 | 构造不存在跳转指令并且未预测跳转的预测信息作为输入,测试PredChecker是否会错检无效指令预测错误 |
|
||||
| 5\.1\.2 | 无效指令预测错误检查 | 误检测试2 | 构造存在无效跳转指令并且未预测跳转的预测信息作为输入,测试PredChecker是否会错检无效指令预测错误 |
|
||||
| 5\.1\.3 | 无效指令预测错误检查 | 误检测试3 | 构造存在有效跳转指令并且正确预测跳转的预测信息作为输入,测试PredChecker是否会错检无效指令预测错误 |
|
||||
| 5\.2 | 无效指令预测错误检查 | 正确检测测试 | 构造无效指令但是预测了跳转的预测信息作为输入,测试PredChecker是否能检查出无效指令预测错误 |
|
||||
| 6\.1\.1 | 目标地址预测错误检查 | 误检测试1 | 构造不存在跳转指令并且未预测跳转的预测信息作输入,测试PredChecker是否会错检目标地址预测错误 |
|
||||
| 6\.1\.2 | 目标地址预测错误检查 | 误检测试2 | 构造存在有效跳转指令并且正确预测跳转的预测信息作为输入,测试PredChecker是否会错检目标地址预测错误 |
|
||||
| 6\.2 | 目标地址预测错误检查 | 正确检测测试 | 构造存在有效跳转指令的预测块和预测跳转但跳转目标计算错误的预测信息作为输入,测试PredChecker能否检出目标地址预测错误 |
|
||||
| 7\.1 | 生成跳转和顺序目标 | 随机测试 | 随机提供译码信息,检测生成的跳转目标和顺序目标。 |
|
||||
|
||||
|
||||
| 序号 | 功能 | 名称 | 描述 |
|
||||
| ------- | ------------------------------------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1\.1\.1 | BPU预测信息的JAL预测错误检查 | 误检测试1 | 预测块中没有JAL指令且最终预测信息也没有取用任何跳转指令的输入,检查PredChecker是否会误报JAL预测错误。 |
|
||||
| 1\.1\.2 | BPU预测信息的JAL预测错误检查 | 误检测试2 | 预测块中有JAL指令且最终预测信息取用的正是本条跳转指令的输入,检查PredChecker是否会误报JAL预测错误。 |
|
||||
| 1\.2\.1 | BPU预测信息的JAL预测错误检查 | 存在JAL未预测 | 预测块中存在JAL指令,但是最终预测信息未预测跳转,检查PredChecker是否能检测出JAL预测错误。 |
|
||||
| 1\.2\.2 | BPU预测信息的JAL预测错误检查 | 预测的JAL并非第一条 | 预测块中存在JAL指令,但是最终预测信息取的跳转指令在第一条JAL指令之后,检查PredChecker是否能检测出JAL预测错误。 |
|
||||
| 2\.1\.1 | BPU预测信息的RET预测错误检查 | 误检测试1 | 预测块中没有RET指令且最终预测信息也没有取用任何跳转指令的输入,检查PredChecker是否会误报RET预测错误。 |
|
||||
| 2\.1\.2 | BPU预测信息的RET预测错误检查 | 误检测试2 | 预测块中有RET指令且最终预测信息取用的正是本条跳转指令的输入,检查PredChecker是否会误报RET预测错误。 |
|
||||
| 2\.2\.1 | BPU预测信息的RET预测错误检查 | 存在RET未预测 | 预测块中存在RET指令,但是最终预测信息未预测跳转,检查PredChecker是否能检测出RET预测错误。 |
|
||||
| 2\.2\.2 | BPU预测信息的RET预测错误检查 | 预测的跳转并非第一条 | 预测块中存在RET指令,但是最终预测信息取的跳转指令在第一条RET指令之后,检查PredChecker是否能检测出RET预测错误。 |
|
||||
| 3\.1 | 更新指令有效范围向量和预测跳转的指令 | 有效范围无误 | 不存在任何错误的情况下,PredChecker应当保留之前的预测结果。 |
|
||||
| 3\.2 | 更新指令有效范围向量和预测跳转的指令 | RET和JAL预测错误引起的范围偏大 | 如果检测到了JAL或RET类的预测错误,PredChecker应该将有效指令的范围修正为预测块开始至第一条跳转指令。同时,应该将预测跳转的指令位置修正为预测块中的第一条跳转指令。 |
|
||||
| 3\.3 | 更新指令有效范围向量和预测跳转的指令 | 非CFI和无效指令引起的预测范围偏小 | 如果出现了非控制流指令和无效指令的误预测,应该将预测跳转的指令重新修正到预测块中第一条跳转指令 |
|
||||
| 4\.1\.1 | 非CFI预测错误检查 | 误检测试1 | 构造不存在CFI指令并且未预测跳转的预测信息作为输入,测试PredChecker是否会错检非CFI预测错误 |
|
||||
| 4\.1\.2 | 非CFI预测错误检查 | 误检测试2 | 构造存在CFI指令并且正确预测跳转的预测信息作为输入,测试PredChecker是否会错检非CFI预测错误 |
|
||||
| 4\.2 | 非CFI预测错误检查 | 正确检测测试 | 构造不存在CFI指令但是预测了跳转的预测信息作为输入,测试PredChecker是否能检查出非CFI预测错误 |
|
||||
| 5\.1\.1 | 无效指令预测错误检查 | 误检测试1 | 构造不存在跳转指令并且未预测跳转的预测信息作为输入,测试PredChecker是否会错检无效指令预测错误 |
|
||||
| 5\.1\.2 | 无效指令预测错误检查 | 误检测试2 | 构造存在无效跳转指令并且未预测跳转的预测信息作为输入,测试PredChecker是否会错检无效指令预测错误 |
|
||||
| 5\.1\.3 | 无效指令预测错误检查 | 误检测试3 | 构造存在有效跳转指令并且正确预测跳转的预测信息作为输入,测试PredChecker是否会错检无效指令预测错误 |
|
||||
| 5\.2 | 无效指令预测错误检查 | 正确检测测试 | 构造无效指令但是预测了跳转的预测信息作为输入,测试PredChecker是否能检查出无效指令预测错误 |
|
||||
| 6\.1\.1 | 目标地址预测错误检查 | 误检测试1 | 构造不存在跳转指令并且未预测跳转的预测信息作输入,测试PredChecker是否会错检目标地址预测错误 |
|
||||
| 6\.1\.2 | 目标地址预测错误检查 | 误检测试2 | 构造存在有效跳转指令并且正确预测跳转的预测信息作为输入,测试PredChecker是否会错检目标地址预测错误 |
|
||||
| 6\.2 | 目标地址预测错误检查 | 正确检测测试 | 构造存在有效跳转指令的预测块和预测跳转但跳转目标计算错误的预测信息作为输入,测试PredChecker能否检出目标地址预测错误 |
|
||||
| 7\.1 | 生成跳转和顺序目标 | 随机测试 | 随机提供译码信息,检测生成的跳转目标和顺序目标。 |
|
||||
|
||||
## Env提供的验证接口(API)
|
||||
|
||||
|
|
@ -75,4 +73,4 @@ TBD
|
|||
|
||||
参考模型
|
||||
|
||||
文档:测试流程
|
||||
文档:测试流程
|
||||
|
|
|
|||
|
|
@ -16,6 +16,16 @@ class PreDecodeDataDef():
|
|||
res = f"new instrs: {self.new_instrs}\njump offsets: {self.jmp_offsets}\nrvcs: {self.rvcs}\nvalid_starts: {self.valid_starts}\nhalf_valid_starts: {self.half_valid_starts}\n"
|
||||
res += f"isRets:{self.isRets}\nisCalls:{self.isCalls}\nbyTypes:{self.brTypes}"
|
||||
return res
|
||||
def clear(self):
|
||||
self.new_instrs = []
|
||||
self.jmp_offsets = []
|
||||
self.rvcs = []
|
||||
self.valid_starts = []
|
||||
self.half_valid_starts = []
|
||||
|
||||
self.isRets = []
|
||||
self.isCalls = []
|
||||
self.brTypes = []
|
||||
|
||||
|
||||
class PreDecodeAgent(Agent):
|
||||
|
|
@ -29,10 +39,11 @@ class PreDecodeAgent(Agent):
|
|||
async def predecode(self, instrs: list[int]) -> PreDecodeDataDef:
|
||||
for i in range(17):
|
||||
getattr(self.bundle.io._in_bits_data, f"_{i}").value = instrs[i]
|
||||
print("going to step")
|
||||
#print("going to step")
|
||||
await self.bundle.step()
|
||||
print("step over")
|
||||
#print("step over")
|
||||
ret = PreDecodeDataDef()
|
||||
ret.clear()
|
||||
|
||||
for i in range(16):
|
||||
ret.new_instrs.append(getattr(self.bundle.io._out._instr, f"_{i}").value)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,50 @@ import toffee_test
|
|||
from dut.PreDecode import DUTPreDecode
|
||||
from ..env import PreDecodeEnv
|
||||
from toffee import start_clock
|
||||
import toffee.funcov as fc
|
||||
from comm import UT_FCOV, module_name_with, get_version_checker
|
||||
|
||||
grp = fc.CovGroup(UT_FCOV("../../CLASSIC"))
|
||||
|
||||
def init_cov(dut:DUTPreDecode, grp: fc.CovGroup):
|
||||
for i in range(16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is rvc:": lambda x: getattr(dut,f'io_out_pd_{i}_isRVC').value == 1,
|
||||
"instr is rvi:": lambda x: getattr(dut,f'io_out_pd_{i}_isRVC').value == 0,
|
||||
},name=f'check_rvc_rvi_{i}')
|
||||
|
||||
for i in range(2,16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is half_valid_start:": lambda x: getattr(dut,f'io_out_hasHalfValid_{i}').value == 1,
|
||||
"instr is not half_valid_start:": lambda x: getattr(dut,f'io_out_hasHalfValid_{i}').value == 0,
|
||||
},name=f'check_half_valid_start_{i}')
|
||||
|
||||
for i in range(1,16):
|
||||
grp.add_cover_point(dut,{
|
||||
"instr is valid_starts:": lambda x: getattr(dut,f'io_out_pd_{i}_valid').value == 1,
|
||||
"instr is not valid_starts:": lambda x: getattr(dut,f'io_out_pd_{i}_valid').value == 0,
|
||||
},name=f'check_valid_start_{i}')
|
||||
|
||||
|
||||
|
||||
def _mark(name):
|
||||
return module_name_with(name, "../predecode_test")
|
||||
|
||||
for i in range(16):
|
||||
grp.mark_function(f'check_rvc_rvi_{i}',_mark(["test_rvc_rvi_checker_2_1_2","test_rvc_rvi_checker_2_1_1"]))
|
||||
for i in range(2,16):
|
||||
grp.mark_function(f'check_half_valid_start_{i}',_mark(["test_precoding_checker_2_3_2"]))
|
||||
for i in range(1,16):
|
||||
grp.mark_function(f'check_valid_start_{i}',_mark(["test_precoding_checker_2_3_1"]))
|
||||
|
||||
return grp
|
||||
|
||||
|
||||
@toffee_test.fixture
|
||||
async def predecode_env(toffee_request: toffee_test.ToffeeRequest):
|
||||
import asyncio
|
||||
# version_check()
|
||||
dut = toffee_request.create_dut(DUTPreDecode)
|
||||
toffee_request.add_cov_groups(init_cov(dut, grp))
|
||||
start_clock(dut)
|
||||
predecode_env = PreDecodeEnv(dut)
|
||||
yield predecode_env
|
||||
|
|
|
|||
|
|
@ -0,0 +1,289 @@
|
|||
import random
|
||||
|
||||
class PreDecodeInstrGen():
|
||||
def __init__(self):
|
||||
self.instrs = []
|
||||
self.new_instrs = []
|
||||
self.jmp_offsets = []
|
||||
self.rvcs = []
|
||||
self.valid_starts = []
|
||||
self.half_valid_starts = []
|
||||
|
||||
self.isRets = []
|
||||
self.isCalls = []
|
||||
self.brTypes = []
|
||||
|
||||
def clear(self):
|
||||
self.instrs = []
|
||||
self.new_instrs = []
|
||||
self.jmp_offsets = []
|
||||
self.rvcs = []
|
||||
self.valid_starts = []
|
||||
self.half_valid_starts = []
|
||||
|
||||
self.isRets = []
|
||||
self.isCalls = []
|
||||
self.brTypes = []
|
||||
|
||||
def random_instrs(self):
|
||||
#genetare random instructions
|
||||
self.instrs = [random.getrandbits(16) for _ in range(17)]
|
||||
self.new_instrs = [self.instrs[i+1] << 16 | self.instrs[i] for i in range(16)]
|
||||
return self.instrs, self.new_instrs
|
||||
def instr_gen(self, type='random', isa='rvi'):
|
||||
if type == 'random':
|
||||
instr_rvi = random.getrandbits(32) | 0b11
|
||||
instr_rvc = random.getrandbits(14) << 2 | random.choice([0b00,0b01,0b10])
|
||||
return instr_rvi if isa == 'rvi' else instr_rvc
|
||||
if type == 'j':
|
||||
opcode = 0b1101111
|
||||
instr_rvi = (random.getrandbits(25) << 7) | opcode
|
||||
instr_rvi = (0b1111100101100010010000111 << 7) | opcode
|
||||
func3 = random.choice([0b101])
|
||||
op = 0b01
|
||||
instr_rvc = (func3) << 13 | (random.getrandbits(11) << 2) | op
|
||||
|
||||
return instr_rvi if isa == 'rvi' else instr_rvc
|
||||
|
||||
if type == 'br':
|
||||
instr_rvi = 0 #instr_rvi is aborted
|
||||
func3 = random.choice([0b110,0b111])
|
||||
op = 0b01
|
||||
instr_rvc = func3 << 13 | random.getrandbits(11) << 2 | op
|
||||
return instr_rvi if isa == 'rvi' else instr_rvc
|
||||
|
||||
if type == 'jalr':
|
||||
instr_rvc = (0b1101) << 12 | random.getrandbits(5) << 7 | 0b0000010
|
||||
instr_rvi = random.getrandbits(1) << 15 | (0b000) << 12 | random.getrandbits(5) << 7 | 0b1100111
|
||||
return instr_rvi
|
||||
if type == 'jal':
|
||||
instr_rvi = random.getrandbits(9) << 7 | 0b1101111
|
||||
return instr_rvi
|
||||
|
||||
def inst_gen_new_signal(self, isa = 'random', type = 'not_cfi'):
|
||||
if type == 'br':
|
||||
#generate br type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
opcode = 0b1100011
|
||||
funct3 = random.choice([0b000,0b001,0b100,0b101,0b110,0b111])
|
||||
rs1 = random.getrandbits(5)
|
||||
rs2 = random.getrandbits(5)
|
||||
instr_rvi = (random.getrandbits(7) << 25) | rs1 << 20 |\
|
||||
rs2 << 15 | funct3 << 12 | (random.getrandbits(5) << 7) |\
|
||||
opcode
|
||||
|
||||
#rvc
|
||||
op = 0b01
|
||||
func3 = random.choice([0b110,0b111])
|
||||
instr_rvc = func3 << 13 | (random.getrandbits(11) << 2) | op
|
||||
|
||||
self.brTypes.append(1)
|
||||
if isa == 'random':
|
||||
self.instrs.append(random.choice([instr_rvi, instr_rvc]))
|
||||
elif isa == 'rvi':
|
||||
self.instrs.append(instr_rvi)
|
||||
elif isa == 'rvc':
|
||||
self.instrs.append(instr_rvc)
|
||||
|
||||
elif type == 'jal':
|
||||
#generate jal type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
opcode = 0b1101111
|
||||
instr_rvi = (random.getrandbits(25) << 7) | opcode
|
||||
|
||||
#rvc
|
||||
func3 = 0b101
|
||||
op = 0b01
|
||||
instr_rvc = (func3 << 13) | (random.getrandbits(11) << 2) | op
|
||||
|
||||
self.brTypes.append(2)
|
||||
if isa == 'random':
|
||||
self.instrs.append(random.choice([instr_rvi, instr_rvc]))
|
||||
elif isa == 'rvi':
|
||||
self.instrs.append(instr_rvi)
|
||||
elif isa == 'rvc':
|
||||
self.instrs.append(instr_rvc)
|
||||
|
||||
elif type == 'jalr':
|
||||
#generate jalr type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
funct3 = 0b000
|
||||
opcode = 0b1100111
|
||||
instr_rvi = (random.getrandbits(17) << 25) | funct3 << 12 |\
|
||||
(random.getrandbits(5) << 7) | opcode
|
||||
|
||||
#rvc
|
||||
rs1 = random.getrandbits(5) | 0b1
|
||||
head = random.choice([0b1001,0b1000])
|
||||
tail = 0b00000_10
|
||||
instr_rvc = (head << 12) | (rs1 << 7) | tail
|
||||
|
||||
self.brTypes.append(3)
|
||||
if isa == 'random':
|
||||
self.instrs.append(random.choice([instr_rvi, instr_rvc]))
|
||||
elif isa == 'rvi':
|
||||
self.instrs.append(instr_rvi)
|
||||
elif isa == 'rvc':
|
||||
self.instrs.append(instr_rvc)
|
||||
|
||||
elif type == 'not_cfi':
|
||||
#generate not cfi type instructions
|
||||
for _ in range(16):
|
||||
#rvi
|
||||
opcode = random.getrandbits(7) | 0b11
|
||||
funct3 = random.getrandbits(3)
|
||||
|
||||
while True:
|
||||
flag1 = (opcode == 0b1100011) and (funct3 in [0b000,0b001,0b010,0b011,0b100,0b101,0b110,0b111])
|
||||
flag2 = (opcode == 0b1101111)
|
||||
flag3 = (opcode == 0b1100111) and (funct3 == 0b000)
|
||||
if not flag3 and not flag2 and not flag1:
|
||||
break
|
||||
opcode = random.getrandbits(7) | 0b11
|
||||
funct3 = random.getrandbits(3)
|
||||
instr_rvi = random.getrandbits(17) << 15 | funct3 << 12 | random.getrandbits(5) << 7 | opcode
|
||||
|
||||
#rvc
|
||||
c_ebreak = 0b100_1_00000_00000_10
|
||||
instr_rvc = random.getrandbits(16)
|
||||
while True:
|
||||
op = instr_rvc & 0b11
|
||||
func3 = instr_rvc >> 13
|
||||
flag1 = (op == 0b01) and (func3 in [0b110, 0b111, 0b101])
|
||||
|
||||
j1 = instr_rvc & 0b1111111
|
||||
j2 = instr_rvc >> 12
|
||||
flag2 = (j1 == 0b0000010) and (j2 in [0b1001, 0b1000])
|
||||
|
||||
flag3 = op == 0b11
|
||||
|
||||
if not flag1 and not flag2 and not flag3:
|
||||
break
|
||||
instr_rvc = random.getrandbits(16)
|
||||
|
||||
self.brTypes.append(0)
|
||||
self.instrs.append(random.choice([instr_rvc,instr_rvi,c_ebreak]))
|
||||
|
||||
return self.instrs, self.brTypes
|
||||
|
||||
|
||||
def precoding_checker(self, task = '2.1.1'):
|
||||
if task == '2.1.1':
|
||||
self.instrs = [self.instr_gen(type = 'random', isa = 'rvc') for _ in range(17)]
|
||||
self.rvcs = [1 for _ in range(16)]
|
||||
return self.instrs, self.rvcs
|
||||
if task == '2.1.2':
|
||||
self.instrs = [random.getrandbits(16) | 0b11 for _ in range(17)]
|
||||
self.rvcs = [0 for _ in range(16)]
|
||||
return self.instrs, self.rvcs
|
||||
|
||||
if task == '2.2.1':
|
||||
self.instrs = [self.instr_gen(type = 'j', isa = 'rvc') for _ in range(17)]
|
||||
def offset(instr):
|
||||
mask = 0b11111111111
|
||||
offset = (instr >> 2) & mask
|
||||
o11 = (offset >> 10) & 1
|
||||
o4 = (offset >> 9) & 1
|
||||
o98 = (offset >> 7) & 0b11
|
||||
o10 = (offset >> 6) & 1
|
||||
o6 = (offset >> 5) & 1
|
||||
o7 = (offset >> 4) & 1
|
||||
o31 = (offset >> 1) & 0b111
|
||||
o5 = (offset >> 0) & 1
|
||||
offset = (o11 << 11) | (o4 << 4) | (o98 << 8) | (o10 << 10) | (o6 << 6) | (o7 << 7) | (o31 << 1) | (o5 << 5)
|
||||
offset = offset if o11 == 0 else (offset | (0b1111) << 12) & 0xFFFF
|
||||
return offset
|
||||
self.jmp_offsets = [offset(i) for i in self.instrs]
|
||||
self.jmp_offsets.pop()
|
||||
return self.instrs, self.jmp_offsets
|
||||
if task == '2.2.2':
|
||||
self.instrs = [random.getrandbits(9) << 7 | 0b1101111 for _ in range(17)]
|
||||
self.new_instrs = [self.instrs[i+1] << 16 | self.instrs[i] for i in range(16)]
|
||||
def offset(instr):
|
||||
offset = instr >> 12
|
||||
o20 = (offset >> 19) & 1
|
||||
o101 = (offset >> 9) & 0b1111111111
|
||||
o11 = (offset >> 8) & 1
|
||||
o1912 = offset & 0b11111111
|
||||
offset = (o20 << 20) | (o101 << 1) | (o11 << 11) | (o1912 << 12)
|
||||
offset = offset & 0xFFFFFFFF if o20 == 0 else (offset | (0xFFFFFF) << 21) & 0xFFFFFFFF
|
||||
return offset
|
||||
self.jmp_offsets = [offset(i) for i in self.new_instrs]
|
||||
return self.instrs, self.jmp_offsets
|
||||
|
||||
if task == '2.2.3':
|
||||
self.instrs = [self.instr_gen(type = 'br', isa = 'rvc') for _ in range(17)]
|
||||
def offset(instr):
|
||||
o5 = (instr >> 2) & 1
|
||||
o21 = (instr >> 3) & 0b11
|
||||
o76 = (instr >> 5) & 0b11
|
||||
o43 = (instr >> 10) & 0b11
|
||||
o8 = (instr >> 12) & 1
|
||||
offset = o5 << 5 | o21 << 1 | o76 << 6 | o43 << 3 | o8 << 8
|
||||
offset = offset if o8 == 0 else (offset | 0xFF << 9) & 0xFFFF
|
||||
return offset
|
||||
self.jmp_offsets = [offset(i) for i in self.instrs]
|
||||
self.jmp_offsets.pop()
|
||||
return self.instrs, self.jmp_offsets
|
||||
if task == '2.2.4':
|
||||
def offset(instr):
|
||||
o12 = (instr >> 31) & 1
|
||||
o105 = (instr >> 25) & 0b111111
|
||||
o11 = (instr >> 7) & 1
|
||||
o41 = (instr >> 8) & 0b1111
|
||||
offset = o12 << 12 | o105 << 5 | o11 << 11 | o41 << 1
|
||||
offset = offset if o12 == 0 else (offset | 0xFFFFFFF << 13) & 0xFFFFFFFF
|
||||
return offset
|
||||
self.instrs = [random.getrandbits(5) << 7 | random.getrandbits(1) << 15 | 0b1100011 | random.choice([0b000,0b001,0b100,0b101,0b110,0b111]) << 12 for _ in range(17)]
|
||||
self.new_instrs = [self.instrs[i+1] << 16 | self.instrs[i] for i in range(16)]
|
||||
self.jmp_offsets = [offset(i) for i in self.new_instrs]
|
||||
return self.instrs, self.jmp_offsets
|
||||
|
||||
if task == '3.1':
|
||||
self.instrs = [random.getrandbits(16) for _ in range(17)]
|
||||
self.new_instrs = [self.instrs[i+1] << 16 | self.instrs[i] for i in range(16)]
|
||||
mask = 0b11
|
||||
flag = 2
|
||||
for i in range(16):
|
||||
if i == 0:
|
||||
self.valid_starts.append(1)
|
||||
flag = 1 if (self.new_instrs[i] & mask) == 0b11 else 0
|
||||
else:
|
||||
if flag == 1:
|
||||
self.valid_starts.append(0)
|
||||
flag = 2
|
||||
elif flag == 0:
|
||||
self.valid_starts.append(1)
|
||||
flag = 1 if (self.new_instrs[i] & mask) == 0b11 else 0
|
||||
elif flag == 2:
|
||||
self.valid_starts.append(1)
|
||||
flag = 1 if (self.new_instrs[i] & mask) == 0b11 else 0
|
||||
return self.instrs, self.valid_starts
|
||||
|
||||
if task == '3.2':
|
||||
self.instrs = [random.getrandbits(16) for _ in range(17)]
|
||||
self.new_instrs = [self.instrs[i+1] << 16 | self.instrs[i] for i in range(16)]
|
||||
mask = 0b11
|
||||
flag = 2
|
||||
for i in range(16):
|
||||
if i == 0:
|
||||
self.half_valid_starts.append(0)
|
||||
elif i == 1:
|
||||
self.half_valid_starts.append(1)
|
||||
flag = 1 if (self.new_instrs[i] & mask) == 0b11 else 0
|
||||
else:
|
||||
if flag == 1:
|
||||
self.half_valid_starts.append(0)
|
||||
flag = 2
|
||||
elif flag == 0:
|
||||
self.half_valid_starts.append(1)
|
||||
flag = 1 if (self.new_instrs[i] & mask) == 0b11 else 0
|
||||
elif flag == 2:
|
||||
self.half_valid_starts.append(1)
|
||||
flag = 1 if (self.new_instrs[i] & mask) == 0b11 else 0
|
||||
return self.instrs, self.half_valid_starts
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,108 @@
|
|||
import toffee_test
|
||||
from .predecode_fixture import predecode_env
|
||||
from ..env import PreDecodeEnv
|
||||
from .predecode_instr_gen import PreDecodeInstrGen
|
||||
|
||||
instrGen = PreDecodeInstrGen()
|
||||
@toffee_test.testcase
|
||||
async def test_smoke(predecode_env : PreDecodeEnv):
|
||||
fake_instrs = [54541 for i in range(17)]
|
||||
|
||||
res = await predecode_env.agent.predecode(fake_instrs)
|
||||
print(res)
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_splice_checker(predecode_env : PreDecodeEnv):
|
||||
#指令拼接测试
|
||||
print('test_splice_checker')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, new_instrs = instrGen.random_instrs()
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert res.new_instrs == new_instrs
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_1_1(predecode_env : PreDecodeEnv):
|
||||
##RVC判定
|
||||
print('test_precoding_checker_2_1_1')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, rvcs = instrGen.precoding_checker(task = '2.1.1')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert res.rvcs == rvcs
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_1_2(predecode_env : PreDecodeEnv):
|
||||
#RVI判定
|
||||
print('test_precoding_checker_2_1_2')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, rvcs = instrGen.precoding_checker(task = '2.1.2')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert res.rvcs == rvcs
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_2_1(predecode_env : PreDecodeEnv):
|
||||
##RVC.J计算 offset
|
||||
print('test_precoding_checker_2_2_1')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, jmp_offsets = instrGen.precoding_checker(task = '2.2.1')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert [i & 0xFFFF for i in res.jmp_offsets] == jmp_offsets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_2_2(predecode_env : PreDecodeEnv):
|
||||
##RVI.J计算 offset
|
||||
print('test_precoding_checker_2_2_2')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, jmp_offsets = instrGen.precoding_checker(task = '2.2.2')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert [i & 0xFFFFFFFF for i in res.jmp_offsets] == jmp_offsets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_2_3(predecode_env : PreDecodeEnv):
|
||||
#RVC.BR计算 offset
|
||||
print('test_precoding_checker_2_2_3')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, jmp_offsets = instrGen.precoding_checker(task = '2.2.3')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert [i & 0xFFFF for i in res.jmp_offsets] == jmp_offsets
|
||||
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_2_4(predecode_env : PreDecodeEnv):
|
||||
#RVI.BR计算 offset
|
||||
print('test_precoding_checker_2_2_4')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, jmp_offsets = instrGen.precoding_checker(task = '2.2.4')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert [i & 0xFFFFFFFF for i in res.jmp_offsets] == jmp_offsets
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_3_1(predecode_env : PreDecodeEnv):
|
||||
#有效指令开始向量计算1
|
||||
print('test_precoding_checker_3_1')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, valid_starts = instrGen.precoding_checker(task = '3.1')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert res.valid_starts == valid_starts
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_3_2(predecode_env : PreDecodeEnv):
|
||||
#有效指令开始向量计算2
|
||||
print('test_precoding_checker_3_2')
|
||||
for _ in range(100):
|
||||
instrGen.clear()
|
||||
instrs, half_valid_starts = instrGen.precoding_checker(task = '3.2')
|
||||
res = await predecode_env.agent.predecode(instrs)
|
||||
assert res.half_valid_starts ==half_valid_starts
|
||||
|
||||
@toffee_test.testcase
|
||||
async def test_precoding_checker_2_3_1(predecode_env : PreDecodeEnv):
|
||||
#非CFI判定
|
||||
print('test_precoding_checker_2_3_1')
|
||||
#TODO
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ def test_req_from_icache_rand_vaddr_rand_valid_single_port(tlb_fixture):
|
|||
# connect to fixture
|
||||
tlb = tlb_fixture
|
||||
# add watch point
|
||||
|
||||
case_name = inspect.currentframe().f_back.f_code.co_name
|
||||
g.add_watch_point(tlb.requestor_0.resp.miss, {
|
||||
"miss": fc.Eq(1),
|
||||
|
|
@ -52,7 +53,7 @@ def test_req_from_icache_rand_vaddr_rand_valid_single_port(tlb_fixture):
|
|||
tlb.set_default_value()
|
||||
# reset
|
||||
tlb.reset()
|
||||
|
||||
print(tlb)
|
||||
# add clock
|
||||
tlb.dut.xclock.StepRis(lambda _: g.sample())
|
||||
# start
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import inspect
|
|||
# the bug occurs. In practice, initiating a request (req) simultaneously with
|
||||
# a reset signal constitutes an invalid input and violates the protocol
|
||||
# specification.
|
||||
def test_reset_when_request(tlb_fixture):
|
||||
def reset_when_request(tlb_fixture):
|
||||
"""
|
||||
Check reset
|
||||
Request & reset in the same cycle
|
||||
|
|
|
|||
Loading…
Reference in New Issue