forked from XS-MLVP/UnityChipForXiangShan
Pr smy ifu predecode new (#140)
* test * f3predecoder * predecode * predecode * update * 优化细节 * fix * fix * delete some files * update * final * update * Simplify and remove duplicate code * Revert: 撤回在3a2d830中的错误修改 * Revert: 撤回在6a3fa2f中的错误修改 * Update files --------- Co-authored-by: mingyu shi <smy@DESKTOP-FO5TJ66>
This commit is contained in:
parent
5c2f4df801
commit
59460cfdc0
|
|
@ -173,4 +173,4 @@ cython_debug/
|
|||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# 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/
|
||||
#.idea/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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(100):
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
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
|
||||
|
|
@ -20,4 +57,4 @@ async def predecode_env(toffee_request: toffee_test.ToffeeRequest):
|
|||
try:
|
||||
await task
|
||||
except asyncio.CancelledError:
|
||||
break
|
||||
break
|
||||
|
|
|
|||
|
|
@ -0,0 +1,168 @@
|
|||
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
|
||||
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 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 = (self.new_instrs[0] & mask) == 0b11
|
||||
self.valid_starts.append(1)
|
||||
|
||||
for i in range(1, 16):
|
||||
if flag:
|
||||
self.valid_starts.append(0)
|
||||
flag = False
|
||||
else:
|
||||
self.valid_starts.append(1)
|
||||
flag = (self.new_instrs[i] & mask) == 0b11
|
||||
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
|
||||
self.half_valid_starts.append(0) # i == 0
|
||||
self.half_valid_starts.append(1) # i == 1
|
||||
flag = (self.new_instrs[1] & mask) == 0b11
|
||||
|
||||
for i in range(2, 16):
|
||||
if flag:
|
||||
self.half_valid_starts.append(0)
|
||||
flag = False
|
||||
else:
|
||||
self.half_valid_starts.append(1)
|
||||
flag = (self.new_instrs[i] & mask) == 0b11
|
||||
return self.instrs, self.half_valid_starts
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,112 @@
|
|||
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):
|
||||
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判定 传入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判定 传入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
|
||||
|
|
|
|||
Loading…
Reference in New Issue