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:
shimingyu 2025-07-30 15:48:03 +08:00 committed by GitHub
parent 5c2f4df801
commit 59460cfdc0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 784 additions and 11 deletions

2
.gitignore vendored
View File

@ -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/

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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