env
This commit is contained in:
parent
4634979680
commit
192c19c853
|
|
@ -143,6 +143,7 @@ celerybeat.pid
|
|||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
!ut_frontend/ifu/ifu_top/env/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
from ..commons import PREDICT_WIDTH, is_next_line, is_last_in_line
|
||||
|
||||
class IFUICacheReceiverRef():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def gen_exceptions(self,none_mmio_exceptions, mmio_exceptions):
|
||||
f2_exception = []
|
||||
for i in range(2):
|
||||
f2_exception.append(none_mmio_exceptions[i] if none_mmio_exceptions[i] != 0 else mmio_exceptions[i])
|
||||
return f2_exception
|
||||
|
||||
def gen_exceptions_each_instr(self, non_mmio_exceptions, mmio_exceptions, pcs, rvcs, start_addr, double_line):
|
||||
cross_page_vec = []
|
||||
exception_each_instr = []
|
||||
f2_exception = self.gen_exceptions(non_mmio_exceptions, mmio_exceptions)
|
||||
# 生成每条指令的异常情况
|
||||
for i in range(PREDICT_WIDTH):
|
||||
if not is_next_line(pcs[i], start_addr):
|
||||
exception_each_instr.append(f2_exception[0])
|
||||
else:
|
||||
exception_each_instr.append(f2_exception[1] if double_line else 0)
|
||||
|
||||
enable_next = is_last_in_line(pcs[i]) and not rvcs[i] and double_line and non_mmio_exceptions[0] == 0
|
||||
cross_page_vec.append(non_mmio_exceptions[1] if enable_next else 0)
|
||||
return exception_each_instr, cross_page_vec
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
from .ifu_top_ctrl_ref import IFUTopCtrl
|
||||
from ..datadef import MMIOReq, ExceptionType, FTQIdx, ITLBReq, MMIOToIbufferFTQ, MMIOCycleInfo, MMIOState, PbmtAssist
|
||||
from ..instr_utils import is_rvc, if_call, if_ret, get_cfi_type
|
||||
from .rvc_expander_ref import rvc_expand_ref
|
||||
|
||||
class IFUMMIOCtrler():
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.pbmt_assist = PbmtAssist()
|
||||
self.cur_state = MMIOState.STATE_IDLE
|
||||
self.next_mmio_state = MMIOState.STATE_IDLE
|
||||
self.first_instr = True
|
||||
self.low_instr = 0
|
||||
self.high_instr = 0
|
||||
self.mmio_rvc = False
|
||||
self.need_resend = False
|
||||
self.mmio_exception = 0
|
||||
self.resend_paddr = 0
|
||||
self.resend_gpaddr = 0
|
||||
self.exceptions = [False, False]
|
||||
self.commit_res = MMIOToIbufferFTQ()
|
||||
|
||||
|
||||
def calc_f2_mmio_exception(self, double_line, pmps, pbmts):
|
||||
f2_mmio_exception = [0, 0]
|
||||
if not double_line:
|
||||
return f2_mmio_exception
|
||||
|
||||
if pmps[0] != pmps[1] or pbmts[0] != pbmts[1]:
|
||||
f2_mmio_exception[1] = 3
|
||||
return f2_mmio_exception
|
||||
|
||||
def setup_before_mmio_states(self, cycle_req: MMIOCycleInfo, final_exceptions):
|
||||
self.cycle_req = cycle_req
|
||||
self.exceptions = final_exceptions
|
||||
|
||||
def reset_all_state(self):
|
||||
self.reset_state()
|
||||
self.cur_state = MMIOState.STATE_IDLE
|
||||
|
||||
def reset_state(self):
|
||||
self.next_mmio_state = MMIOState.STATE_IDLE
|
||||
self.need_resend = False
|
||||
self.mmio_rvc = False
|
||||
self.resend_paddr = 0
|
||||
self.resend_gpaddr = 0
|
||||
self.mmio_exception = ExceptionType.NONE
|
||||
|
||||
def push_state(self, req: MMIOReq):
|
||||
last_state = self.cur_state
|
||||
self.cur_state = self.next_mmio_state
|
||||
if self.next_mmio_state == MMIOState.STATE_IDLE:
|
||||
is_mmio_space = (self.cycle_req.icache_pmp_mmios[0] or self.pbmt_assist.is_uncache(self.cycle_req.icache_itlb_pbmts[0])) and (self.exceptions[0] + self.exceptions[1] == 0)
|
||||
if is_mmio_space:
|
||||
if self.cycle_req.icache_itlb_pbmts[0] == PbmtAssist.NC:
|
||||
self.next_mmio_state = MMIOState.STATE_SEND_REQ
|
||||
# return self.next_mmio_state, self.cycle_req.icache_paddr
|
||||
else:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_LAST_CMT
|
||||
# self.from_icache_itlb_pbmt = req.itlb_pbmt
|
||||
# self.from_icache_pmp_mmio = req.pmp_mmio
|
||||
elif self.next_mmio_state == MMIOState.STATE_WAIT_LAST_CMT:
|
||||
if self.first_instr or req.last_commited:
|
||||
self.next_mmio_state = MMIOState.STATE_SEND_REQ
|
||||
# return self.next_mmio_state, self.cycle_req.icache_paddr
|
||||
# else:
|
||||
# if req.last_commit:
|
||||
# self.mmio_state = MMIOState.STATE_SEND_REQ
|
||||
|
||||
elif self.next_mmio_state == MMIOState.STATE_SEND_REQ:
|
||||
if req.to_uncache_ready:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_RESP
|
||||
elif self.next_mmio_state == MMIOState.STATE_WAIT_RESP:
|
||||
self.high_instr = (req.from_uncache.data >> 16) & ((1 << 16) -1)
|
||||
self.low_instr = req.from_uncache.data & ((1 << 16) -1)
|
||||
self.commit_res = self.calc_instr_and_infos()
|
||||
if req.from_uncache.valid:
|
||||
self.mmio_rvc = (req.from_uncache.data & 3) != 3
|
||||
self.need_resend = (not self.mmio_rvc) and ((self.cycle_req.icache_paddr >> 1) & 3) == 3
|
||||
|
||||
if self.need_resend:
|
||||
self.next_mmio_state = MMIOState.STATE_SEND_TLB
|
||||
itlb_req = ITLBReq()
|
||||
itlb_req.vaddr = self.cycle_req.ftq_start_addr + 2
|
||||
# return self.next_mmio_state, itlb_req
|
||||
else:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_COMMIT
|
||||
# return self.next_mmio_state, self.get_instr_and_infos()
|
||||
|
||||
elif self.next_mmio_state == MMIOState.STATE_SEND_TLB:
|
||||
if req.itlb_req_ready:
|
||||
self.next_mmio_state = MMIOState.STATE_TLB_RESP
|
||||
|
||||
elif self.next_mmio_state == MMIOState.STATE_TLB_RESP:
|
||||
if req.itlb_resp.valid:
|
||||
itlb_resp_excp_code = req.itlb_resp.get_excp_code()
|
||||
self.resend_paddr = req.itlb_resp.paddr
|
||||
self.resend_gpaddr = req.itlb_resp.gpaddr
|
||||
if itlb_resp_excp_code != ExceptionType.NONE:
|
||||
self.mmio_exception = itlb_resp_excp_code
|
||||
else:
|
||||
self.mmio_exception = ExceptionType.AF if req.itlb_resp.pbmt != self.cycle_req.icache_itlb_pbmts[0] else ExceptionType.NONE
|
||||
|
||||
if self.mmio_exception != ExceptionType.NONE:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_COMMIT
|
||||
# return self.next_mmio_state, self.mmio_exception
|
||||
else:
|
||||
self.next_mmio_state = MMIOState.STATE_SEND_PMP
|
||||
# return self.next_mmio_state, self.resend_paddr
|
||||
|
||||
|
||||
elif self.next_mmio_state == MMIOState.STATE_SEND_PMP:
|
||||
self.mmio_exception = ExceptionType.AF if (req.pmp_resp.instr) or self.cycle_req.icache_pmp_mmios[0] != req.pmp_resp.mmio else ExceptionType.NONE
|
||||
if self.mmio_exception != ExceptionType.NONE:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_COMMIT
|
||||
# return self.next_mmio_state, self.mmio_exception
|
||||
else:
|
||||
self.next_mmio_state = MMIOState.STATE_RESEND_REQ
|
||||
# return self.next_mmio_state, self.resend_paddr
|
||||
|
||||
elif self.next_mmio_state == MMIOState.STATE_RESEND_REQ:
|
||||
if req.to_uncache_ready:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_RESEND_RESP
|
||||
elif self.next_mmio_state == MMIOState.STATE_WAIT_RESEND_RESP:
|
||||
if req.from_uncache.valid:
|
||||
self.next_mmio_state = MMIOState.STATE_WAIT_COMMIT
|
||||
self.high_instr = req.from_uncache.data & ((1 << 16) -1)
|
||||
self.commit_res = self.calc_instr_and_infos()
|
||||
# return self.next_mmio_state, self.get_instr_and_infos()
|
||||
elif self.next_mmio_state == MMIOState.STATE_WAIT_COMMIT:
|
||||
mmio_commit = any(commit.valid and commit.ftqIdx == self.cycle_req.ftq_idx and commit.ftqOffset == 0 for commit in req.rob_commits)
|
||||
if mmio_commit or self.cycle_req.icache_itlb_pbmts[0] == PbmtAssist.NC:
|
||||
self.next_mmio_state = MMIOState.STATE_COMMITED
|
||||
# return self.next_mmio_state, self.cycle_req.ftq_start_addr + 2 if self.is_rvc else self.cycle_req.ftq_start_addr + 4
|
||||
elif self.next_mmio_state == MMIOState.STATE_COMMITED:
|
||||
self.first_instr = self.first_instr and (not req.to_ibuffer_ready)
|
||||
self.reset_state()
|
||||
|
||||
if last_state == MMIOState.STATE_WAIT_RESP and self.cur_state == MMIOState.STATE_SEND_TLB:
|
||||
itlb_req = ITLBReq()
|
||||
itlb_req.vaddr = self.cycle_req.ftq_start_addr + 2
|
||||
return [self.cur_state, itlb_req]
|
||||
elif (last_state == MMIOState.STATE_TLB_RESP or last_state == MMIOState.STATE_SEND_PMP) \
|
||||
and self.cur_state == MMIOState.STATE_WAIT_COMMIT.value:
|
||||
return [self.cur_state, self.mmio_exception, self.resend_gpaddr]
|
||||
elif (last_state == MMIOState.STATE_TLB_RESP.value and self.cur_state == MMIOState.STATE_SEND_PMP) \
|
||||
or (last_state == MMIOState.STATE_SEND_PMP.value and self.cur_state == MMIOState.STATE_RESEND_REQ):
|
||||
return [self.cur_state, self.resend_paddr]
|
||||
elif ((last_state == MMIOState.STATE_IDLE or last_state == MMIOState.STATE_WAIT_LAST_CMT) \
|
||||
and self.cur_state == MMIOState.STATE_SEND_REQ):
|
||||
return [self.cur_state, self.cycle_req.icache_paddr]
|
||||
elif (last_state == MMIOState.STATE_WAIT_RESP.value or last_state == MMIOState.STATE_WAIT_RESEND_RESP.value) \
|
||||
and self.cur_state == MMIOState.STATE_WAIT_COMMIT.value:
|
||||
return [self.cur_state, self.commit_res]
|
||||
elif (last_state == MMIOState.STATE_WAIT_COMMIT and self.cur_state == MMIOState.STATE_COMMITED):
|
||||
return [MMIOState.STATE_COMMITED, self.cycle_req.ftq_start_addr + 2 if self.commit_res.is_rvc else self.cycle_req.ftq_start_addr + 4]
|
||||
|
||||
return [self.cur_state]
|
||||
|
||||
def calc_instr_and_infos(self):
|
||||
res = MMIOToIbufferFTQ()
|
||||
new_instr = (self.high_instr << 16) | self.low_instr
|
||||
res.br_type = get_cfi_type(new_instr)
|
||||
|
||||
res.is_rvc = is_rvc(new_instr)
|
||||
res.is_call = if_call(new_instr, res.br_type)
|
||||
res.is_ret = if_ret(new_instr, res.br_type)
|
||||
res.expd_instr, res.ill = rvc_expand_ref(new_instr, self.cycle_req.csr_fs_is_off)
|
||||
if res.ill:
|
||||
res.expd_instr = new_instr
|
||||
return res
|
||||
|
|
@ -0,0 +1,650 @@
|
|||
|
||||
from toffee import Model, driver_hook
|
||||
from ..datadef import ExistsIdx, ICacheResp, ICacheStatusResp, FTQQuery, FTQFlushInfo, \
|
||||
FTQResp, ToIbufferAllRes,FTQRedirect, FTQFlushFromBPU, NonMMIOReq, NonMMIOResp, \
|
||||
MMIOCycleInfo, MMIOReq, ExceptionType
|
||||
from .ifu_mmio_ref import IFUMMIOCtrler
|
||||
from .ifu_top_ctrl_ref import IFUTopCtrl, DataManagement
|
||||
from .predecode_ref import PredecodeRef, F3PredecoderRef
|
||||
from .pred_checker_ref import PredCheckerRef, TYPE_JAL
|
||||
from .rvc_expander_ref import rvc_expand_ref
|
||||
from .ifu_icache_receiver import IFUICacheReceiverRef
|
||||
|
||||
from ..commons import PREDICT_WIDTH, LAST_HALF_ERR, BLOCK_OFF_BITS, is_next_line, is_last_in_line, \
|
||||
calc_double_line, calc_blk_length, calc_cut_ptr
|
||||
|
||||
def generate_prefix_one_hots(prefix_length, length):
|
||||
prefix_length = min(max(prefix_length, 0), length)
|
||||
bits = [1] * prefix_length + [0] * (length - prefix_length)
|
||||
return bits
|
||||
|
||||
def bool_list_to_int(bits):
|
||||
result = 0
|
||||
for bit in reversed(bits):
|
||||
result = (result << 1) | bit
|
||||
return result
|
||||
|
||||
|
||||
class IFUReqReceiverRef():
|
||||
def __init__(self):
|
||||
# self.ftq_double_line = False
|
||||
pass
|
||||
|
||||
def cal_f1_pcs(self, start_addr):
|
||||
# self.f1_pcs = [start_addr + i * 2 for i in range(PREDICT_WIDTH)]
|
||||
|
||||
return [start_addr + i * 2 for i in range(PREDICT_WIDTH)], calc_double_line(start_addr)
|
||||
|
||||
def get_f1_pcs(self):
|
||||
return self.f1_pcs
|
||||
|
||||
def set_paddr(self, paddr):
|
||||
self.f1_paddr = paddr
|
||||
|
||||
def get_f1_paddr(self):
|
||||
return self.f1_paddr
|
||||
|
||||
def set_gpaddr(self, gpaddr):
|
||||
self.f1_gpaddr = gpaddr
|
||||
|
||||
def get_f1_gpaddr(self):
|
||||
return self.f1_gpaddr
|
||||
|
||||
def set_f2_exception(self, exception: list[int], bked_excp):
|
||||
self.f2_none_mmio_exception = exception
|
||||
self.backend_exception = bked_excp
|
||||
|
||||
# 无跳转时的指令距离
|
||||
def calc_ftr_ranges(self, valid, cur_start_addr, next_start_addr):
|
||||
self.start_addr = cur_start_addr
|
||||
self.next_start_addr = next_start_addr
|
||||
if valid:
|
||||
length = PREDICT_WIDTH
|
||||
else:
|
||||
# block_length = (next_start_addr - cur_start_addr) // 2
|
||||
length = calc_blk_length(cur_start_addr, next_start_addr)
|
||||
# length = ((next_start_addr - cur_start_addr) & 0x1F ) // 2
|
||||
|
||||
# self.ftr_ranges = generate_prefix_one_hots(length, PREDICT_WIDTH)
|
||||
return generate_prefix_one_hots(length, PREDICT_WIDTH)
|
||||
|
||||
def calc_jump_ranges(self, valid, ftq_offset):
|
||||
length = ftq_offset + 1 if valid else PREDICT_WIDTH
|
||||
# self.jump_ranges = generate_prefix_one_hots(length, PREDICT_WIDTH)
|
||||
return generate_prefix_one_hots(length, PREDICT_WIDTH)
|
||||
|
||||
# def get_ranges(self):
|
||||
# return [ftr & jmp for ftr, jmp in zip(self.ftr_ranges, self.jump_ranges)]
|
||||
|
||||
def calc_cut_ptr(self, startAddr):
|
||||
idx_pos = (startAddr >> 1) & 0x1F
|
||||
# self.cut_ptr = [idx_pos + i for i in range(PREDICT_WIDTH + 1)]
|
||||
return [idx_pos + i for i in range(PREDICT_WIDTH + 1)]
|
||||
|
||||
def cut_from_cacheline(self, cacheline, cut_ptr):
|
||||
instrs = []
|
||||
for idx in cut_ptr:
|
||||
assert 0 <= idx < 64
|
||||
pos = idx * 16
|
||||
instrs.append((cacheline >> pos) & 0xFFFF)
|
||||
return instrs
|
||||
|
||||
AGENT_NAME="top_agent"
|
||||
|
||||
|
||||
class IFUReceiverModel(Model):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.common_data = DataManagement()
|
||||
self.step_funcs = []
|
||||
|
||||
self.ifu_req_receiver = IFUReqReceiverRef()
|
||||
self.mmio_ctrl = IFUMMIOCtrler()
|
||||
self.top_ctrl = IFUTopCtrl(self.common_data)
|
||||
self.predecode_ref = PredecodeRef()
|
||||
self.f3predecoder_ref = F3PredecoderRef()
|
||||
self.pred_checker_ref = PredCheckerRef()
|
||||
self.icache_receiver_ref = IFUICacheReceiverRef()
|
||||
self.last_half_valid = False
|
||||
|
||||
# self.f2_exception = [0, 0]
|
||||
# exception_each_instr = [0 for _ in range(17)]
|
||||
self.wb_tgt = 0
|
||||
|
||||
# 根据start addr和下一个块的start addr等计算信息; this function will be called at the f0 prepare stage
|
||||
def save_ftq_offset_start_addr(self):
|
||||
# this should be removed later
|
||||
# self.next_tgt = next_start_addr
|
||||
# nothing happens at f0 prepare-f0 except set ftq valid to be true
|
||||
yield False
|
||||
|
||||
# self.all_together_range = [ a & b for a, b in zip(self.ifu_req_receiver.ftr_ranges, self.ifu_req_receiver.jump_ranges)]
|
||||
|
||||
# this will be calculated after the f0 prepare stage, where
|
||||
start_addr_f1 = self.common_data.ftq_req.get(1).startAddr
|
||||
|
||||
|
||||
f1_pcs, double_line = self.ifu_req_receiver.cal_f1_pcs(start_addr_f1)
|
||||
self.common_data.pcs.set(f1_pcs)
|
||||
self.common_data.double_line.set(double_line)
|
||||
# TODO: add cut ptr var of stages
|
||||
cut_ptr = calc_cut_ptr(start_addr_f1)
|
||||
self.common_data.cut_ptr.set(cut_ptr)
|
||||
# print(f"calc cut_ptr: {cut_ptr}")
|
||||
yield False
|
||||
|
||||
# works at f2 stage
|
||||
|
||||
next_start_addr_f2 = self.common_data.ftq_req.get(2).nextStartAddr
|
||||
offset: ExistsIdx = self.common_data.ftq_req.get(2).ftqOffset
|
||||
|
||||
ftr_ranges = self.ifu_req_receiver.calc_ftr_ranges(offset.exists, start_addr_f1, next_start_addr_f2)
|
||||
jump_ranges = self.ifu_req_receiver.calc_jump_ranges(offset.exists, offset.offsetIdx)
|
||||
instr_ranges = [ftr & jmp for ftr, jmp in zip(ftr_ranges, jump_ranges)]
|
||||
|
||||
self.common_data.instr_range.set(instr_ranges)
|
||||
|
||||
yield True
|
||||
|
||||
|
||||
def icache_resp_receive(self, icache_resp: ICacheResp):
|
||||
self.common_data.from_icache_paddr.set(icache_resp.paddr)
|
||||
self.common_data.from_icache_gpaddr.set(icache_resp.gpaddr)
|
||||
self.common_data.backend_exception.set(icache_resp.backend_exception)
|
||||
|
||||
# self.ifu_req_receiver.set_paddr(icache_resp.paddr)
|
||||
# self.ifu_req_receiver.set_gpaddr(icache_resp.gpaddr)
|
||||
# self.ifu_req_receiver.set_f2_exception(icache_resp.exceptions, icache_resp.backend_exception)
|
||||
|
||||
|
||||
self.common_data.itlb_pbmt.set(icache_resp.itlb_pbmts[0])
|
||||
self.common_data.pmp_mmio.set(icache_resp.pmp_mmios[0])
|
||||
|
||||
|
||||
# mmio_exception =
|
||||
cut_instrs = self.ifu_req_receiver.cut_from_cacheline(icache_resp.data, self.common_data.cut_ptr.get(2))
|
||||
# print(self.common_data.cut_ptr.get(2))
|
||||
# print(icache_resp.data)
|
||||
# print(cut_instrs)
|
||||
self.common_data.cut_data = cut_instrs
|
||||
|
||||
none_mmio_exception = icache_resp.exceptions
|
||||
|
||||
f2_mmio_exception = self.mmio_ctrl.calc_f2_mmio_exception(icache_resp.double_line, icache_resp.pmp_mmios, icache_resp.itlb_pbmts)
|
||||
|
||||
f2_exception = []
|
||||
for i in range(2):
|
||||
f2_exception.append(none_mmio_exception[i] if none_mmio_exception[i] != 0 else f2_mmio_exception[i])
|
||||
|
||||
self.common_data.exceptions.set(f2_exception)
|
||||
|
||||
|
||||
# self.top_ctrl.f2_exception = self.f2_exception
|
||||
predecode_res = self.predecode_ref.predecode(self.common_data.cut_data)
|
||||
self.common_data.predecode_res.set(predecode_res)
|
||||
|
||||
cross_page_vec = []
|
||||
|
||||
exception_each_instr = []
|
||||
# 生成每条指令的异常情况
|
||||
for i in range(PREDICT_WIDTH):
|
||||
if not is_next_line(self.common_data.pcs.get(2)[i], self.common_data.ftq_req.get(2).startAddr):
|
||||
exception_each_instr.append(f2_exception[0])
|
||||
else:
|
||||
exception_each_instr.append(f2_exception[1] if self.common_data.double_line.get(2) else 0)
|
||||
|
||||
enable_next = is_last_in_line(self.common_data.pcs.get(2)[i]) and not predecode_res.rvcs[i] and self.common_data.double_line.get(2) and none_mmio_exception[0] == 0
|
||||
cross_page_vec.append(none_mmio_exception[1] if enable_next else 0)
|
||||
self.common_data.exception_each_instr.set(exception_each_instr)
|
||||
self.common_data.crosspage_exception_vec.set(cross_page_vec)
|
||||
|
||||
|
||||
yield False
|
||||
|
||||
f3predecode_res = self.f3predecoder_ref.f3_predecode(self.common_data.predecode_res.get(3).new_instrs)
|
||||
self.common_data.f3predecode_res.set(f3predecode_res)
|
||||
|
||||
integrated_valids = self.common_data.predecode_res.get(3).half_valid_starts if self.top_ctrl.last_half_valid else self.common_data.predecode_res.get(3).valid_starts
|
||||
|
||||
self.common_data.instr_valids.set(integrated_valids)
|
||||
|
||||
pred_check_stg1_res = self.pred_checker_ref.pred_check_stg1(f3predecode_res, self.common_data.predecode_res.get(3), integrated_valids, self.common_data.instr_range.get(3), \
|
||||
self.common_data.ftq_req.get(3).ftqOffset , self.common_data.pcs.get(3), self.common_data.ftq_req.get(3).nextStartAddr)
|
||||
|
||||
self.common_data.pred_check_stg1_res.set(pred_check_stg1_res)
|
||||
# calculate cross page exceptions
|
||||
|
||||
# self.cross_page_vec = []
|
||||
|
||||
self.common_data.lastvalid_idx.set(pred_check_stg1_res.fixed_length-1)
|
||||
|
||||
# here, will later be changed to internal values from internal wires
|
||||
ranges_and_valids = [a & b for (a,b ) in zip(pred_check_stg1_res.ranges, integrated_valids)]
|
||||
self.common_data.instr_ranges_and_valids.set(ranges_and_valids)
|
||||
|
||||
# prepare to ibuffer datas
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.valid = True
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.instr_valids = bool_list_to_int(integrated_valids)
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.enqEnable = bool_list_to_int(ranges_and_valids)
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.instrs = self.common_data.normal_expd_instrs.get(3)
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.pds.brTypes = f3predecode_res.brTypes
|
||||
self.common_data.to_ibuffer.toIbuffer.pds.isCalls = f3predecode_res.isCalls
|
||||
self.common_data.to_ibuffer.toIbuffer.pds.isRets = f3predecode_res.isRets
|
||||
self.common_data.to_ibuffer.toIbuffer.pds.isRVCs = self.common_data.predecode_res.get(3).rvcs
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.ftqPtr = self.common_data.ftq_req.get(3).ftqIdx
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.foldpcs = [xorfold((pc>>1) & ((1 << 49) -1), 10, 49) for pc in self.common_data.pcs.get(3)]
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.exceptionTypes = []
|
||||
|
||||
for i in range(PREDICT_WIDTH):
|
||||
cur_exception = self.common_data.exception_each_instr.get(3)[i]
|
||||
self.common_data.to_ibuffer.toIbuffer.exceptionTypes.append(cur_exception if cur_exception != 0 else self.common_data.crosspage_exception_vec.get(3)[i])
|
||||
|
||||
self.common_data.to_ibuffer.toIbuffer.backendException = self.common_data.backend_exception.get(3)
|
||||
|
||||
print("f3 finished")
|
||||
yield False
|
||||
|
||||
# wb
|
||||
|
||||
pred_check_stg2_res = self.pred_checker_ref.pred_check_stg2(True)
|
||||
self.common_data.pred_check_stg2_res = pred_check_stg2_res
|
||||
|
||||
fired_pred_check_stg1_res = self.common_data.pred_check_stg1_res.get(4)
|
||||
miss_pred_idx = -1
|
||||
for i in range(len(pred_check_stg2_res.miss_pred)):
|
||||
if pred_check_stg2_res.miss_pred[i] != 0:
|
||||
miss_pred_idx = i
|
||||
break
|
||||
|
||||
wb_lastvalid_idx = self.common_data.lastvalid_idx.get(4)
|
||||
wb_instr_valids = self.common_data.instr_valids.get(4)
|
||||
|
||||
wb_stg_predecode_res = self.common_data.predecode_res.get(4)
|
||||
wb_stg_f3_predecode_res = self.common_data.f3predecode_res.get(4)
|
||||
|
||||
miss_offset, mis_type = self.top_ctrl.redirect_flush(miss_pred_idx, wb_instr_valids, wb_lastvalid_idx, \
|
||||
wb_stg_predecode_res.rvcs, fired_pred_check_stg1_res, False)
|
||||
|
||||
if miss_pred_idx <0:
|
||||
miss_pred_idx = len(pred_check_stg2_res.miss_pred) - 1
|
||||
|
||||
# pc + 4
|
||||
wb_tgt = self.common_data.pcs.get(4)[wb_lastvalid_idx] + 4 if mis_type == 2 else pred_check_stg2_res.fixed_tgts[miss_pred_idx]
|
||||
# print(pred_check_stg2_res.fixed_tgts[miss_pred_idx])
|
||||
# print(mis_type)
|
||||
first_jmp_idx = len(pred_check_stg2_res.jmp_tgts) -1
|
||||
|
||||
# print(pred_check_stg2_res.jmp_tgts)
|
||||
|
||||
for i in range(len(pred_check_stg2_res.jmp_tgts)):
|
||||
if wb_instr_valids[i] and wb_stg_f3_predecode_res.brTypes[i] == TYPE_JAL:
|
||||
first_jmp_idx = i
|
||||
break
|
||||
|
||||
jal_tgt = pred_check_stg2_res.jmp_tgts[first_jmp_idx]
|
||||
|
||||
|
||||
# prepare write back datas
|
||||
self.common_data.wb_ftq.valid = True
|
||||
|
||||
self.common_data.wb_ftq.ftqIdx.flag = self.common_data.ftq_req.get(4).ftqIdx.flag
|
||||
self.common_data.wb_ftq.ftqIdx.value = self.common_data.ftq_req.get(4).ftqIdx.value
|
||||
|
||||
self.common_data.wb_ftq.pcs = self.common_data.pcs.get(4)
|
||||
|
||||
self.common_data.wb_ftq.misOffset = miss_offset
|
||||
|
||||
self.common_data.wb_ftq.target = wb_tgt
|
||||
self.common_data.wb_ftq.instrRanges = self.common_data.instr_ranges_and_valids.get(4)
|
||||
|
||||
self.common_data.wb_ftq.pds.brTypes = wb_stg_f3_predecode_res.brTypes
|
||||
self.common_data.wb_ftq.pds.isCalls = wb_stg_f3_predecode_res.isCalls
|
||||
self.common_data.wb_ftq.pds.isRets = wb_stg_f3_predecode_res.isRets
|
||||
self.common_data.wb_ftq.pds.isRVCs = wb_stg_predecode_res.rvcs
|
||||
self.common_data.wb_ftq.pds.pdValids = self.common_data.instr_valids.get(4) # if the instr is valid in the block
|
||||
|
||||
self.common_data.wb_ftq.jalTarget = jal_tgt
|
||||
self.common_data.wb_ftq.cfiOffset_valid = fired_pred_check_stg1_res.taken_occurs
|
||||
yield True
|
||||
|
||||
# MMIO在这个周期里做不了,不过可以先存下来
|
||||
|
||||
|
||||
def fake_resp(self, icache_status_resp: ICacheStatusResp):
|
||||
icache_work = self.icache_resp_receive(icache_status_resp.resp)
|
||||
self.step_funcs.append(icache_work)
|
||||
# self.extd_instrs = []
|
||||
# for instr in self.predecode_res.new_instrs:
|
||||
# ext_instr, ill = rvc_expand_ref(instr, fsIsOff=fs_is_off)
|
||||
# self.extd_instrs.append(instr if ill else ext_instr)
|
||||
|
||||
self.top_ctrl.check_icache_resp_all_valid(icache_status_resp.resp.icache_valid, icache_status_resp.resp.vaddrs)
|
||||
|
||||
|
||||
def set_fs_is_off(self, fs_is_off):
|
||||
expds = self.expd_instrs_yield(fs_is_off)
|
||||
self.step_funcs.append(expds)
|
||||
|
||||
def expd_instrs_yield(self, fs_is_off):
|
||||
self.common_data.normal_expd_instrs.set(self.expd_instrs(fs_is_off, self.common_data.predecode_res.get(3).new_instrs))
|
||||
yield True
|
||||
|
||||
def expd_instrs(self, fs_is_off, new_instrs):
|
||||
extd_instrs = []
|
||||
ills = []
|
||||
for instr in new_instrs:
|
||||
ext_instr, ill = rvc_expand_ref(instr, fsIsOff=fs_is_off)
|
||||
extd_instrs.append(instr if ill==1 else ext_instr)
|
||||
ills.append(ill)
|
||||
return extd_instrs, ills
|
||||
|
||||
|
||||
def set_icache_ready(self, icache_ready):
|
||||
self.top_ctrl.set_icache_ready(icache_ready)
|
||||
|
||||
|
||||
def query_from_ftq(self, query: FTQQuery):
|
||||
# 先把ftq query保存下来
|
||||
# 这个函数已经弃用,改为保存整个ftq
|
||||
self.common_data.ftq_req.set(query)
|
||||
self.step_funcs.append(self.save_ftq_offset_start_addr())
|
||||
|
||||
def bpu_flush_redirect(self, flush_from_bpu: FTQFlushFromBPU):
|
||||
self.top_ctrl.flush_from_bpu(flush_from_bpu)
|
||||
yield True
|
||||
# later will add redirect, but not now
|
||||
|
||||
|
||||
def from_ftq_flush(self, ftqFlushInfo:FTQFlushFromBPU):
|
||||
# done
|
||||
# self.common_data.ftq_redirect.set(ftqFlushInfo.redirect if ftqFlushInfo.redirect.valid else FTQRedirect())
|
||||
|
||||
self.step_funcs.append(self.bpu_flush_redirect(ftqFlushInfo))
|
||||
|
||||
|
||||
def step(self):
|
||||
print("st...")
|
||||
# 进行所有功能性的计算
|
||||
next_step_funcs = []
|
||||
while self.step_funcs:
|
||||
step_func = self.step_funcs.pop()
|
||||
# yield 函数未结束
|
||||
res = next(step_func)
|
||||
if not res:
|
||||
next_step_funcs.append(step_func)
|
||||
self.step_funcs = next_step_funcs
|
||||
|
||||
# 根据控制结果传递值
|
||||
self.common_data.step_pass_value(self.top_ctrl.get_fires())
|
||||
|
||||
# 这个用于控制信号的检验
|
||||
|
||||
def get_ftq_ready(self):
|
||||
return self.top_ctrl.get_ftq_ready()
|
||||
|
||||
|
||||
def get_bpu_flush(self):
|
||||
return self.top_ctrl.get_bpu_flush()
|
||||
|
||||
# 以下方法协助校验接取指令的正确性
|
||||
|
||||
def get_exception_vecs(self):
|
||||
return self.common_data.exceptions.get(3), self.common_data.exception_each_instr.get(3)
|
||||
|
||||
|
||||
def get_f3_pcs(self):
|
||||
return self.common_data.pcs.get(3)
|
||||
|
||||
|
||||
def get_cut_ptrs(self):
|
||||
return self.common_data.cut_ptr.get(2)
|
||||
|
||||
|
||||
def get_addrs(self):
|
||||
return self.common_data.from_icache_paddr.get(3), self.common_data.from_icache_gpaddr.get(3)
|
||||
|
||||
|
||||
def get_cut_instrs(self):
|
||||
return self.common_data.cut_data
|
||||
|
||||
|
||||
def get_ranges(self):
|
||||
return bool_list_to_int(self.common_data.instr_range.get(3))
|
||||
|
||||
|
||||
def get_predecode_res(self):
|
||||
return self.common_data.predecode_res.get(2)
|
||||
|
||||
|
||||
def get_f3predecoder_res(self):
|
||||
return self.common_data.f3predecode_res.get(3), self.common_data.instr_valids.get(3)
|
||||
|
||||
|
||||
def get_pred_checker_stg1_res(self):
|
||||
return self.common_data.pred_check_stg1_res.get(3)
|
||||
|
||||
|
||||
def get_pred_checker_stg2_res(self):
|
||||
return self.common_data.pred_check_stg2_res
|
||||
|
||||
|
||||
def get_extended_instrs(self):
|
||||
return self.common_data.normal_expd_instrs.get(3)
|
||||
|
||||
|
||||
#
|
||||
# def get_wb_flush(self):
|
||||
# return self.top_ctrl.miss_off
|
||||
|
||||
|
||||
def get_cur_last_half_valid(self):
|
||||
return self.top_ctrl.last_half_valid
|
||||
|
||||
|
||||
def collect_res_backto_ftq(self):
|
||||
return self.common_data.wb_ftq
|
||||
|
||||
|
||||
def get_toibuffer_info(self)-> ToIbufferAllRes:
|
||||
|
||||
return self.common_data.to_ibuffer
|
||||
|
||||
@driver_hook(agent_name=AGENT_NAME)
|
||||
def deal_with_non_mmio(self, req: NonMMIOReq):
|
||||
res = NonMMIOResp()
|
||||
|
||||
# f0
|
||||
res.bpu_flush_res = self.top_ctrl.flush_from_bpu(req.bpu_flush_info, req.ftq_req.ftqIdx)
|
||||
res.ftq_ready = req.icache_resp.ready
|
||||
if res.bpu_flush_res or (not res.ftq_ready):
|
||||
return res
|
||||
|
||||
# entering f1 stage
|
||||
|
||||
# this will be calculated after the f0 prepare stage, where
|
||||
start_addr_f1 = req.ftq_req.startAddr
|
||||
|
||||
f1_pcs, double_line = self.ifu_req_receiver.cal_f1_pcs(start_addr_f1)
|
||||
|
||||
cut_ptrs = calc_cut_ptr(start_addr_f1)
|
||||
|
||||
|
||||
# works at f2 stage
|
||||
|
||||
next_start_addr_f2 = req.ftq_req.nextStartAddr
|
||||
offset: ExistsIdx = req.ftq_req.ftqOffset
|
||||
|
||||
ftr_ranges = self.ifu_req_receiver.calc_ftr_ranges(offset.exists, start_addr_f1, next_start_addr_f2)
|
||||
jump_ranges = self.ifu_req_receiver.calc_jump_ranges(offset.exists, offset.offsetIdx)
|
||||
instr_ranges = [ftr & jmp for ftr, jmp in zip(ftr_ranges, jump_ranges)]
|
||||
|
||||
# at f2 stage, icache resp comes
|
||||
res.cut_ptrs = cut_ptrs
|
||||
cacheline = req.icache_resp.resp.data | (req.icache_resp.resp.data << 512)
|
||||
res.cut_instrs = self.ifu_req_receiver.cut_from_cacheline(cacheline, res.cut_ptrs)
|
||||
res.predecode_res = self.predecode_ref.predecode(res.cut_instrs)
|
||||
|
||||
res.icache_all_valid = self.top_ctrl.check_icache_resp_all_valid(req.icache_resp.resp.icache_valid, req.icache_resp.resp.vaddrs, req.icache_resp.resp.double_line, \
|
||||
double_line, req.ftq_req.startAddr, req.ftq_req.nextlineStart)
|
||||
if not res.icache_all_valid:
|
||||
return res
|
||||
|
||||
# goto f3 stage:
|
||||
|
||||
f2_mmio_exception = self.mmio_ctrl.calc_f2_mmio_exception(req.icache_resp.resp.double_line, req.icache_resp.resp.pmp_mmios, req.icache_resp.resp.itlb_pbmts)
|
||||
|
||||
f2_exception = self.icache_receiver_ref.gen_exceptions(req.icache_resp.resp.exceptions, f2_mmio_exception)
|
||||
|
||||
exception_each_instr, cross_page_vec = \
|
||||
self.icache_receiver_ref.gen_exceptions_each_instr(req.icache_resp.resp.exceptions, \
|
||||
f2_mmio_exception, f1_pcs, res.predecode_res.rvcs, req.ftq_req.startAddr, double_line)
|
||||
|
||||
res.exception_vecs = (f2_exception, exception_each_instr)
|
||||
res.pcs = f1_pcs
|
||||
res.addrs = (req.icache_resp.resp.paddr, req.icache_resp.resp.gpaddr)
|
||||
|
||||
res.ranges = bool_list_to_int(instr_ranges)
|
||||
res.f3_predecode_res = self.f3predecoder_ref.f3_predecode(res.predecode_res.new_instrs)
|
||||
|
||||
expd_instrs, ills = self.expd_instrs(req.fs_is_off, res.predecode_res.new_instrs)
|
||||
integrated_valids = res.predecode_res.half_valid_starts if self.last_half_valid else res.predecode_res.valid_starts
|
||||
|
||||
res.pred_checker_stg1_res, pred_checker_stg2_res = self.pred_checker_ref.pred_check_stgs(res.f3_predecode_res, res.predecode_res, integrated_valids, instr_ranges, \
|
||||
offset, f1_pcs, req.ftq_req.nextStartAddr)
|
||||
|
||||
last_valid_idx = res.pred_checker_stg1_res.fixed_length-1
|
||||
last_half_valid = self.top_ctrl.check_last_req_half_valid(res.pred_checker_stg1_res.ranges, integrated_valids, \
|
||||
res.predecode_res.rvcs, res.pred_checker_stg1_res.takens)
|
||||
self.last_half_valid = last_half_valid
|
||||
|
||||
res.to_ibuffer = self.get_toibuffer_info()
|
||||
res.to_ibuffer.toIbuffer.valid = True
|
||||
|
||||
res.to_ibuffer.toIbuffer.instr_valids = bool_list_to_int(integrated_valids)
|
||||
|
||||
ranges_and_valids = [a & b for (a,b ) in zip(res.pred_checker_stg1_res.ranges, integrated_valids)]
|
||||
|
||||
res.to_ibuffer.toIbuffer.enqEnable = bool_list_to_int(ranges_and_valids)
|
||||
|
||||
res.to_ibuffer.toIbuffer.instrs = expd_instrs
|
||||
res.to_ibuffer.toIbuffer.illegalInstrs = ills
|
||||
|
||||
res.to_ibuffer.toIbuffer.pds.brTypes = res.f3_predecode_res.brTypes
|
||||
res.to_ibuffer.toIbuffer.pds.isCalls = res.f3_predecode_res.isCalls
|
||||
res.to_ibuffer.toIbuffer.pds.isRets = res.f3_predecode_res.isRets
|
||||
res.to_ibuffer.toIbuffer.pds.isRVCs = res.predecode_res.rvcs
|
||||
|
||||
res.to_ibuffer.toIbuffer.ftqPtr = req.ftq_req.ftqIdx
|
||||
|
||||
res.to_ibuffer.toIbuffer.foldpcs = [xorfold((pc>>1) & ((1 << 49) -1), 10, 49) for pc in f1_pcs]
|
||||
|
||||
res.to_ibuffer.toIbuffer.exceptionTypes = []
|
||||
|
||||
for i in range(PREDICT_WIDTH):
|
||||
cur_exception = exception_each_instr[i]
|
||||
res.to_ibuffer.toIbuffer.exceptionTypes.append(cur_exception if cur_exception != 0 else cross_page_vec[i])
|
||||
|
||||
res.to_ibuffer.toIbuffer.backendException = req.icache_resp.resp.backend_exception
|
||||
res.to_ibuffer.toBackendGpaddrMem.wen = ExceptionType.GPF in f2_exception
|
||||
if res.to_ibuffer.toBackendGpaddrMem.wen:
|
||||
res.to_ibuffer.toBackendGpaddrMem.waddr = req.ftq_req.ftqIdx.value
|
||||
res.to_ibuffer.toBackendGpaddrMem.gpaddr = req.icache_resp.resp.gpaddr
|
||||
# entering wb stage, collect res
|
||||
|
||||
res.pred_checker_stg2_res = pred_checker_stg2_res
|
||||
|
||||
res.wb_res = self.collect_res_backto_ftq()
|
||||
|
||||
res.wb_res.valid = True
|
||||
|
||||
res.wb_res.ftqIdx.flag = req.ftq_req.ftqIdx.flag
|
||||
res.wb_res.ftqIdx.value = req.ftq_req.ftqIdx.value
|
||||
|
||||
res.wb_res.pcs = f1_pcs
|
||||
|
||||
miss_pred_idx = -1
|
||||
for i in range(len(res.pred_checker_stg2_res.miss_pred)):
|
||||
if res.pred_checker_stg2_res.miss_pred[i] != 0:
|
||||
miss_pred_idx = i
|
||||
break
|
||||
|
||||
miss_offset, mis_type = self.top_ctrl.redirect_flush(miss_pred_idx, integrated_valids, last_valid_idx, \
|
||||
res.predecode_res.rvcs, res.pred_checker_stg1_res, False)
|
||||
if miss_pred_idx <0:
|
||||
miss_pred_idx = len(res.pred_checker_stg2_res.miss_pred) - 1
|
||||
res.wb_res.misOffset = miss_offset
|
||||
wb_tgt = f1_pcs[last_valid_idx] + 4 if mis_type == LAST_HALF_ERR else res.pred_checker_stg2_res.fixed_tgts[miss_pred_idx]
|
||||
res.wb_res.target = wb_tgt
|
||||
res.wb_res.instrRanges = ranges_and_valids
|
||||
|
||||
res.wb_res.pds.brTypes = res.f3_predecode_res.brTypes
|
||||
res.wb_res.pds.isCalls = res.f3_predecode_res.isCalls
|
||||
res.wb_res.pds.isRets = res.f3_predecode_res.isRets
|
||||
res.wb_res.pds.isRVCs = res.predecode_res.rvcs
|
||||
res.wb_res.pds.pdValids = integrated_valids # if the instr is valid in the block
|
||||
|
||||
first_jmp_idx = len(res.pred_checker_stg2_res.jmp_tgts) -1
|
||||
|
||||
for i in range(len(res.pred_checker_stg2_res.jmp_tgts)):
|
||||
if integrated_valids[i] and res.f3_predecode_res.brTypes[i] == TYPE_JAL:
|
||||
first_jmp_idx = i
|
||||
break
|
||||
|
||||
res.wb_res.jalTarget = res.pred_checker_stg2_res.jmp_tgts[first_jmp_idx]
|
||||
res.wb_res.cfiOffset_valid = res.pred_checker_stg1_res.taken_occurs
|
||||
|
||||
res.last_half_valid = last_half_valid
|
||||
return res
|
||||
|
||||
@driver_hook(agent_name=AGENT_NAME)
|
||||
def set_up_before_mmio_states(self, mmio_cycle_info: MMIOCycleInfo):
|
||||
f1_pcs, double_line = self.ifu_req_receiver.cal_f1_pcs(mmio_cycle_info.ftq_start_addr)
|
||||
|
||||
mmio_exceptions = self.mmio_ctrl.calc_f2_mmio_exception(double_line, mmio_cycle_info.icache_pmp_mmios, \
|
||||
mmio_cycle_info.icache_itlb_pbmts)
|
||||
|
||||
f2_exception = self.icache_receiver_ref.gen_exceptions(mmio_cycle_info.exceptions, mmio_exceptions)
|
||||
|
||||
self.mmio_ctrl.setup_before_mmio_states(mmio_cycle_info, f2_exception)
|
||||
self.mmio_ctrl.push_state(MMIOReq())
|
||||
|
||||
|
||||
@driver_hook(agent_name=AGENT_NAME)
|
||||
def deal_with_single_mmio_req(self, mmio_req:MMIOReq):
|
||||
return self.mmio_ctrl.push_state(mmio_req)
|
||||
|
||||
@driver_hook
|
||||
def reset_mmio_state(self):
|
||||
self.mmio_ctrl.reset_all_state()
|
||||
|
||||
|
||||
def xorfold(x: int, res_width: int, width: int | None = None) -> int:
|
||||
"""
|
||||
把整数 x 按 res_width 分块并按位 XOR 折叠,返回 res_width 位结果。
|
||||
- x: 非负整数(对应 UInt)
|
||||
- res_width: 每块位宽,>0
|
||||
- width: x 的逻辑位宽(可选)。如果不写,就用 x.bit_length();如需和硬件一致(保留前导0),请显式传入。
|
||||
"""
|
||||
assert res_width > 0
|
||||
if width is None:
|
||||
width = max(1, x.bit_length()) # Python 对 0 的 bit_length 是 0,这里至少给 1
|
||||
|
||||
k = (width + res_width - 1) // res_width # 上取整块数
|
||||
acc = 0
|
||||
mask_block = (1 << res_width) - 1
|
||||
|
||||
# 逐块提取并 XOR:第 i 块是 [i*res_width, (i+1)*res_width)
|
||||
for i in range(k):
|
||||
chunk = (x >> (i * res_width)) & mask_block
|
||||
acc ^= chunk
|
||||
|
||||
# 结果自然落在 res_width 位
|
||||
return acc
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
from toffee import Model, driver_hook, monitor_hook
|
||||
from ..datadef import FTQFlushFromBPU, FTQFlushFromBPUStg, FTQIdx, ExistsIdx, FTQRedirect, FTQQuery, PreDecodeDataDef, \
|
||||
F3PreDecodeData, ToIbufferAllRes, PredCheckerStage1RetData, PredCheckerStage2RetData, FTQResp, ICacheResp
|
||||
from enum import Enum
|
||||
|
||||
from .tools import FakeReg, StagesWire, StagesWireManager
|
||||
from ..commons import PREDICT_WIDTH, PRED_ERR, LAST_HALF_ERR
|
||||
AGENT_NAME="top_agent"
|
||||
FULL_LAST_IDX = PREDICT_WIDTH - 1
|
||||
|
||||
|
||||
class MMIOState(Enum):
|
||||
STATE_IDLE = 0
|
||||
STATE_WAIT_LAST_CMT = 1
|
||||
STATE_SEND_REQ = 2
|
||||
STATE_WAIT_RESP = 3
|
||||
STATE_SEND_TLB = 4
|
||||
STATE_TLB_RESP = 5
|
||||
STATE_SEND_PMP = 6
|
||||
STATE_RESEND_REQ = 7
|
||||
STATE_WAIT_RESEND_RESP = 8
|
||||
STATE_WAIT_COMMIT = 9
|
||||
STATE_COMMITED = 10
|
||||
|
||||
class PbmtAssist():
|
||||
NC = 1
|
||||
IO = 2
|
||||
|
||||
def is_uncache(self, num):
|
||||
return num == self.NC or num == self.IO
|
||||
|
||||
class DataManagement():
|
||||
def __init__(self):
|
||||
self.stage_wire_manager = StagesWireManager()
|
||||
self.ftq_req: StagesWire[FTQQuery] = self.stage_wire_manager.create(init_val=FTQQuery())
|
||||
self.pcs: StagesWire[list[int]] = self.stage_wire_manager.create(init_val=[0] * PREDICT_WIDTH, start=1)
|
||||
self.double_line: StagesWire[int] = self.stage_wire_manager.create(start=1, end=3, init_val=False)
|
||||
self.cut_ptr: StagesWire[list[int]] = self.stage_wire_manager.create(start=1, end=2, init_val=[0] * (PREDICT_WIDTH+1))
|
||||
self.instr_range: StagesWire[list[int]] = self.stage_wire_manager.create(start=2, end=3, init_val=[0] * PREDICT_WIDTH)
|
||||
self.from_icache_paddr: StagesWire[int] = self.stage_wire_manager.create(start=2, end=3, init_val=0)
|
||||
self.from_icache_gpaddr: StagesWire[int] = self.stage_wire_manager.create(start=2, end=3, init_val=0)
|
||||
self.exceptions: StagesWire[list[int]] = self.stage_wire_manager.create(start=2, end=3, init_val=[0, 0])
|
||||
self.backend_exception: StagesWire[bool] = self.stage_wire_manager.create(start=2, end=3, init_val=False)
|
||||
self.pmp_mmio: StagesWire[bool] = self.stage_wire_manager.create(start=2, end=3, init_val=False)
|
||||
self.itlb_pbmt: StagesWire[bool] = self.stage_wire_manager.create(start=2, end=3, init_val=False)
|
||||
self.exception_each_instr: StagesWire[list[int]] = self.stage_wire_manager.create(start=2, end=3, init_val=[0] * 16)
|
||||
self.predecode_res: StagesWire[PreDecodeDataDef] = self.stage_wire_manager.create(start=2, end=4, init_val=PreDecodeDataDef())
|
||||
self.f3predecode_res: StagesWire[F3PreDecodeData] = self.stage_wire_manager.create(start=3, end=4, init_val=F3PreDecodeData())
|
||||
self.crosspage_exception_vec: StagesWire[list[int]] = self.stage_wire_manager.create(start=2, end=3, init_val=[0] * 16)
|
||||
self.lastvalid_idx: StagesWire[int] = self.stage_wire_manager.create(start=3, end=4, init_val=16)
|
||||
self.instr_valids: StagesWire[list[bool]] = self.stage_wire_manager.create(start=3, end=4, init_val=[False] * 16)
|
||||
self.pred_check_stg1_res: StagesWire[PredCheckerStage1RetData] = self.stage_wire_manager.create(start=3, end=4, init_val=PredCheckerStage1RetData())
|
||||
self.normal_expd_instrs: StagesWire[list[int]] = self.stage_wire_manager.create(start=3, end=4, init_val=[0] * 16)
|
||||
self.instr_ranges_and_valids : StagesWire[list[int]] = self.stage_wire_manager.create(start=3, end=4, init_val=[0] * 16)
|
||||
|
||||
self.ftq_redirect: FakeReg[FTQRedirect] = FakeReg(FTQRedirect())
|
||||
self.cut_data: list[int] = [0] * (PREDICT_WIDTH + 1)
|
||||
|
||||
# self.ftq_bpu_flush_info = FTQFlushFromBPU()
|
||||
|
||||
self.to_ibuffer = ToIbufferAllRes()
|
||||
self.wb_ftq = FTQResp()
|
||||
|
||||
self.pred_check_stg2_res: PredCheckerStage2RetData = PredCheckerStage2RetData()
|
||||
|
||||
# self.from_icache: ICacheResp = ICacheResp()
|
||||
|
||||
|
||||
def step_pass_value(self, fires):
|
||||
self.stage_wire_manager.fresh_all(fires)
|
||||
|
||||
|
||||
|
||||
class IFUTopCtrl():
|
||||
|
||||
def __init__(self, reuseable_data: DataManagement):
|
||||
self.common_data = reuseable_data
|
||||
|
||||
self.f2_exception = [0, 0]
|
||||
|
||||
self.f1_ready = True
|
||||
self.f2_ready = True
|
||||
self.icache_ready = True
|
||||
self.icache_resp_valid = True
|
||||
self.f0_fire = True
|
||||
self.f1_fire = True
|
||||
self.f2_fire = True
|
||||
self.wb_enable = True
|
||||
self.to_ibuffer_ready = True
|
||||
self.from_uncache_valid = True
|
||||
|
||||
self.f0_flush = False
|
||||
self.bpu_f0_flush = False
|
||||
# self.cur_ftq_idx = None
|
||||
self.last_half_valid = False
|
||||
self.f3_mmio_use_seq_pc = False
|
||||
|
||||
# self.miss_off = ExistsIdx()
|
||||
# self.mis_type = 0
|
||||
|
||||
self.mmio_state = MMIOState.STATE_IDLE
|
||||
|
||||
self.ftq_redirect : FTQRedirect = FTQRedirect()
|
||||
|
||||
|
||||
# @driver_hook(agent_name=AGENT_NAME)
|
||||
def get_ftq_ready(self):
|
||||
# self.f1_ready = self.f1_fire
|
||||
return self.icache_ready and self.f1_ready
|
||||
|
||||
def get_fires(self):
|
||||
return {1: self.f0_fire, 2:self.f1_fire, 3: self.f2_fire, 4: self.wb_enable}
|
||||
|
||||
# @driver_hook(agent_name=AGENT_NAME)
|
||||
def set_icache_ready(self, icache_ready):
|
||||
self.icache_ready = icache_ready
|
||||
|
||||
def set_f2_mmio_exception(self, double_line, pmps, pbmts):
|
||||
self.f2_mmio_exception = [0, 0]
|
||||
if not double_line:
|
||||
return
|
||||
|
||||
if pmps[0] != pmps[1] or pbmts[0] != pbmts[1]:
|
||||
self.f2_mmio_exception[1] = 3
|
||||
|
||||
self.pmp_mmio = pmps[0]
|
||||
self.itlb_pbmt = pbmts[0]
|
||||
|
||||
def set_ftq_valid(self, ftq_valid):
|
||||
self.ftq_valid = ftq_valid
|
||||
|
||||
def step(self):
|
||||
# 更新f0_flush, f2_flush, f3_flush, mmio_redirect, wb_redirect
|
||||
last_f2_flush = self.f2_flush
|
||||
last_f2_fire = self.f2_fire
|
||||
last_f3_valid = self.f3_valid
|
||||
last_wb_valid = self.wb_valid
|
||||
# last_wb_redirect = self.wb_redirect
|
||||
# last_mmio_redirect = self.mmio_redirect
|
||||
last_f3_wb_not_flush = self.f3_wb_not_flush
|
||||
last_f1_valid = self.f1_valid
|
||||
last_f2_valid = self.f2_valid
|
||||
mmio_f3_flush = self.f3_flush
|
||||
last_f3_mmio_use_seq_pc = self.f3_mmio_use_seq_pc
|
||||
|
||||
last_f2_icache_all_resp_reg = self.f2_icache_all_resp_reg
|
||||
|
||||
|
||||
self.ftq_valid = self.common_data.ftq_req.get(0).valid
|
||||
|
||||
|
||||
last_wb_enable = self.wb_enable
|
||||
|
||||
self.wb_valid = last_wb_enable
|
||||
|
||||
self.wb_redirect = self.common_data.wb_ftq.misOffset.exists and last_wb_valid
|
||||
|
||||
|
||||
exception_exists = False
|
||||
for exc in self.f3_exception:
|
||||
if exc != 0:
|
||||
exception_exists = True
|
||||
break
|
||||
|
||||
# done
|
||||
# the res related to func will not change
|
||||
self.f3_req_is_mmio = last_f3_valid and (self.pmp_mmio or self.itlb_pbmt == PbmtAssist.NC ) and not exception_exists
|
||||
|
||||
# temporarily done
|
||||
self.f3_wb_not_flush = self.common_data.ftq_req.get(4).ftqIdx == self.common_data.ftq_req.get(3).ftqIdx and last_f3_valid and last_wb_valid
|
||||
|
||||
|
||||
# val redirect_mmio_req =
|
||||
# fromFtqRedirectReg.valid && redirect_ftqIdx === f3_ftq_req.ftqIdx && redirect_ftqOffset === 0.U
|
||||
self.redirect_mmio_req = self.ftq_redirect.valid and self.ftq_redirect.ftqIdx == self.common_data.ftq_req.get(3).ftqIdx
|
||||
|
||||
if ((last_f2_fire and not last_f2_flush) and self.f3_req_is_mmio):
|
||||
self.f3_mmio_use_seq_pc = True
|
||||
elif self.redirect_mmio_req:
|
||||
# this condition value will be handled while receiving redirect req?
|
||||
self.f3_mmio_use_seq_pc = False
|
||||
|
||||
# here is the 'last' mmio state
|
||||
self.mmio_redirect = self.f3_req_is_mmio and self.mmio_state == MMIOState.STATE_WAIT_COMMIT and self.last_from_uncache_valid and last_f3_mmio_use_seq_pc
|
||||
|
||||
backend_redirect = self.ftq_redirect.valid
|
||||
self.f3_flush = backend_redirect or (self.wb_redirect and not last_f3_wb_not_flush)
|
||||
|
||||
|
||||
# these are all wires, so they all use value of this term
|
||||
self.f2_flush = backend_redirect or self.mmio_redirect or self.wb_redirect
|
||||
|
||||
self.f0_flush = self.f2_flush or self.bpu_f0_flush
|
||||
|
||||
|
||||
# fires & readys to control
|
||||
|
||||
|
||||
# f3_ready := (io.toIbuffer.ready && (f3_mmio_req_commit || !f3_req_is_mmio)) || !f3_valid
|
||||
|
||||
# ibuffer ready 是外部信号;也就是当前不是mmio状态或者mmio提交已经完成时可以为真
|
||||
|
||||
self.f3_ready = self.to_ibuffer_ready and (self.f3_mmio_req_commit or not self.f3_req_is_mmio) or not last_f3_valid
|
||||
|
||||
# icache_resp_all_valid
|
||||
|
||||
# val f2_icache_all_resp_wire =
|
||||
# fromICache.valid &&
|
||||
# fromICache.bits.vaddr(0) === f2_ftq_req.startAddr &&
|
||||
# (fromICache.bits.doubleline && fromICache.bits.vaddr(1) === f2_ftq_req.nextlineStart || !f2_doubleLine)
|
||||
|
||||
|
||||
|
||||
# when(f2_flush)(f2_icache_all_resp_reg := false.B)
|
||||
# .elsewhen(f2_valid && f2_icache_all_resp_wire && !f3_ready)(f2_icache_all_resp_reg := true.B)
|
||||
# .elsewhen(f2_fire && f2_icache_all_resp_reg)(f2_icache_all_resp_reg := false.B)
|
||||
|
||||
|
||||
self.f2_fire = last_f2_valid and self.f3_ready and self.icache_resp_all_valid
|
||||
|
||||
self.f2_ready = self.f2_fire or not last_f2_valid
|
||||
|
||||
self.f1_fire = last_f1_valid and self.f2_ready
|
||||
|
||||
|
||||
self.f3_fire = self.to_ibuffer_valid and self.to_ibuffer_ready
|
||||
|
||||
|
||||
self.f1_ready = self.f1_fire or not last_f1_valid
|
||||
|
||||
self.f0_fire = self.ftq_valid and self.icache_ready and self.f1_ready
|
||||
|
||||
|
||||
|
||||
# valids to control
|
||||
# f0 valid is ftq valid
|
||||
if self.f2_flush:
|
||||
self.f1_valid = False
|
||||
elif self.f0_fire and not self.f0_flush:
|
||||
self.f1_valid = True
|
||||
elif self.f1_fire:
|
||||
self.f1_valid = False
|
||||
|
||||
# when(f2_flush)(f2_valid := false.B)
|
||||
# .elsewhen(f1_fire && !f1_flush)(f2_valid := true.B)
|
||||
# .elsewhen(f2_fire)(f2_valid := false.B)
|
||||
|
||||
if self.f2_flush:
|
||||
self.f2_valid = False
|
||||
elif self.f1_fire and not self.f2_flush:
|
||||
self.f2_valid = True
|
||||
elif self.f2_fire:
|
||||
self.f2_valid = False
|
||||
|
||||
|
||||
if self.f3_flush and not self.f3_req_is_mmio:
|
||||
self.f3_valid = False
|
||||
elif mmio_f3_flush and self.f3_req_is_mmio and not self.f3_need_not_flush:
|
||||
self.f3_valid = False
|
||||
elif self.f2_fire and not self.f2_flush:
|
||||
self.f3_valid = True
|
||||
elif self.f3_fire and not self.f3_req_is_mmio:
|
||||
self.f3_valid = False
|
||||
elif self.f3_req_is_mmio and self.f3_mmio_req_commit:
|
||||
self.f3_valid = False
|
||||
|
||||
# done
|
||||
self.wb_enable = (last_f2_fire and not last_f2_flush) and (self.f3_req_is_mmio) and (not self.f3_flush)
|
||||
|
||||
self.f3_exception = self.f2_exception
|
||||
|
||||
self.last_from_uncache_valid = self.from_uncache_valid
|
||||
|
||||
# @driver_hook(agent_name=AGENT_NAME)
|
||||
def check_icache_resp_all_valid(self, icache_resp_valid, vaddrs, icache_doubleline, req_doubleline, start, next_start):
|
||||
if not req_doubleline:
|
||||
return True
|
||||
return icache_resp_valid and vaddrs[0] == start and (icache_doubleline and vaddrs[1] == next_start)
|
||||
|
||||
# self.icache_resp_valid = icache_resp_valid
|
||||
# if not icache_resp_valid:
|
||||
# self.f2_ready = False
|
||||
# self.f1_fire = self.f2_ready
|
||||
# else:
|
||||
# # here will be further changed and tested
|
||||
# self.f2_ready = True
|
||||
# self.f1_fire = self.f2_ready
|
||||
|
||||
# val f2_icache_all_resp_wire =
|
||||
# fromICache.valid &&
|
||||
# fromICache.bits.vaddr(0) === f2_ftq_req.startAddr &&
|
||||
# (fromICache.bits.doubleline && fromICache.bits.vaddr(1) === f2_ftq_req.nextlineStart || !f2_doubleLine)
|
||||
|
||||
# @driver_hook(agent_name=AGENT_NAME)
|
||||
def flush_from_bpu(self, flush_bpu: FTQFlushFromBPU, cur_ftq_idx: FTQIdx):
|
||||
for key in flush_bpu.stgs.keys():
|
||||
flush_info: FTQFlushFromBPUStg = flush_bpu.stgs[key]
|
||||
if not flush_info.stg_valid:
|
||||
continue
|
||||
if not (flush_info.ftqIdx > cur_ftq_idx):
|
||||
return True
|
||||
return False
|
||||
|
||||
def ftq_redirect(self, redirect: FTQRedirect):
|
||||
self.ftq_redirect.valid = redirect.valid
|
||||
self.ftq_redirect.ftqIdx.flag = redirect.ftqIdx.flag
|
||||
self.ftq_redirect.ftqIdx.value = redirect.ftqIdx.value
|
||||
self.ftq_redirect.ftqOffset = redirect.ftqOffset
|
||||
self.ftq_redirect.redirect_level = redirect.redirect_level
|
||||
|
||||
self.backend_redirect = self.ftq_redirect.valid
|
||||
|
||||
|
||||
# @driver_hook(agent_name=AGENT_NAME)
|
||||
def get_bpu_flush(self):
|
||||
return self.bpu_f0_flush
|
||||
|
||||
|
||||
|
||||
# may TODO: add pred checker err check and add mmio
|
||||
def redirect_flush(self, miss_pred_idx, valids, last_idx, rvcs, pred_check_stg1_res: PredCheckerStage1RetData, mmio=False):
|
||||
# TODO
|
||||
miss_off = ExistsIdx()
|
||||
mis_type = 0
|
||||
ranges = pred_check_stg1_res.ranges
|
||||
takens = pred_check_stg1_res.takens
|
||||
|
||||
|
||||
exists_last_half_err = check_last_valid(ranges, valids, last_idx, rvcs, takens, mmio=mmio) and last_idx != FULL_LAST_IDX
|
||||
# print(exists_last_half_err)
|
||||
self.last_half_valid = check_last_valid(ranges, valids, PREDICT_WIDTH - 1, rvcs, takens, mmio)
|
||||
if exists_last_half_err:
|
||||
miss_off.exists = True
|
||||
miss_off.offsetIdx = last_idx
|
||||
mis_type = LAST_HALF_ERR
|
||||
return miss_off, mis_type
|
||||
|
||||
# here may to be fixed
|
||||
|
||||
if 0 <= miss_pred_idx < 16:
|
||||
miss_off.exists = True
|
||||
miss_off.offsetIdx = miss_pred_idx
|
||||
mis_type = PRED_ERR
|
||||
|
||||
return miss_off, mis_type
|
||||
|
||||
def check_last_req_half_valid(self, ranges, valids, rvcs, takens):
|
||||
return check_last_valid(ranges, valids, PREDICT_WIDTH-1, rvcs, takens)
|
||||
|
||||
|
||||
def check_last_valid(ranges, valids, last_idx, rvcs, takens, mmio=False):
|
||||
return ranges[last_idx] and valids[last_idx] and (not rvcs[last_idx]) and (not takens[last_idx]) \
|
||||
and (not mmio)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
from ..datadef import F3PreDecodeData, PredCheckerRetData, ExistsIdx, PreDecodeDataDef, PredCheckerStage2RetData, PredCheckerStage1RetData
|
||||
from typing import Generator
|
||||
from ..commons import PREDICT_WIDTH
|
||||
|
||||
TYPE_JAL=2
|
||||
TYPE_JALR=3
|
||||
TYPE_BR = 1
|
||||
TYPE_NONE = 0
|
||||
|
||||
|
||||
NO_FAULT=0
|
||||
JAL_FAULT=1
|
||||
RET_FAULT=2
|
||||
TGT_FAULT=3
|
||||
NON_CFI_FAULT=4
|
||||
INVALID_TAKEN_FAULT=5
|
||||
JALR_FAULT=6
|
||||
|
||||
|
||||
def get_first_true(bool_list: list[bool]):
|
||||
if True not in bool_list:
|
||||
return len(bool_list)
|
||||
return bool_list.index(True)
|
||||
|
||||
|
||||
class PredCheckerRef():
|
||||
def __init__(self):
|
||||
self.generator_queue: list[Generator] = []
|
||||
|
||||
def pred_check_stg1(self, f3_pd: F3PreDecodeData, pd: PreDecodeDataDef, instr_valids, instr_ranges, jmp_idx_all: ExistsIdx, pcs, tgt) -> PredCheckerStage1RetData:
|
||||
generator = self.pred_check_yield(f3_pd, pd, instr_valids, instr_ranges, jmp_idx_all, pcs, tgt)
|
||||
res = next(generator)
|
||||
self.generator_queue.append(generator)
|
||||
return res
|
||||
|
||||
def pred_check_stg2(self, fire) -> PredCheckerStage2RetData:
|
||||
res = PredCheckerStage2RetData()
|
||||
if self.generator_queue:
|
||||
new_gen = self.generator_queue.pop()
|
||||
res = new_gen.send(fire)
|
||||
return res
|
||||
|
||||
|
||||
def pred_check_yield(self, f3_pd: F3PreDecodeData, pd: PreDecodeDataDef, instr_valids, instr_ranges, jmp_idx_all: ExistsIdx, pcs, tgt):
|
||||
jal_errs = [False] * 16
|
||||
jalr_errs = [False] * 16
|
||||
ret_errs = [False] * 16
|
||||
tgt_errs = [False] * 16
|
||||
non_cfi_errs = [False] * 16
|
||||
invalid_errs = [False] * 16
|
||||
|
||||
decode_jmp_offs = pd.jmp_offsets
|
||||
rvcs = pd.rvcs
|
||||
whether_jmp = jmp_idx_all.exists
|
||||
jmp_idx = jmp_idx_all.offsetIdx
|
||||
# res = PredCheckerRetData()
|
||||
|
||||
res1 = PredCheckerStage1RetData()
|
||||
jal_idxs = self.check_num_errs(f3_pd.brTypes, TYPE_JAL)
|
||||
jal_errs = self.jmp_type_err_check(jal_idxs, whether_jmp, jmp_idx, instr_ranges, instr_valids)
|
||||
|
||||
jalr_init_idxs = self.check_num_errs(f3_pd.brTypes, TYPE_JALR)
|
||||
ret_idxs = self.check_num_errs(f3_pd.isRets, 1)
|
||||
jalr_idxs = [jalr and not ret for jalr, ret in zip(jalr_init_idxs, ret_idxs)]
|
||||
|
||||
jalr_errs = self.jmp_type_err_check(jalr_idxs, whether_jmp, jmp_idx, instr_ranges, instr_valids)
|
||||
ret_errs = self.jmp_type_err_check(ret_idxs, whether_jmp, jmp_idx, instr_ranges, instr_valids)
|
||||
|
||||
true_jmp_stg = min(get_first_true(jal_errs), get_first_true(jalr_errs), get_first_true(ret_errs))
|
||||
if true_jmp_stg >= jmp_idx:
|
||||
res1.ranges = instr_ranges[:]
|
||||
retake = jmp_idx
|
||||
else:
|
||||
res1.ranges = [True] * true_jmp_stg + [False] * (len(instr_ranges) - true_jmp_stg)
|
||||
retake = true_jmp_stg
|
||||
|
||||
res1.fixed_length = 16 if 0 not in res1.ranges else res1.ranges.index(0)
|
||||
# above done the stage 1 work: jal/jalr/ret errs and fix range & taken idx
|
||||
|
||||
res1.takens = [res1.ranges[i] and instr_valids[i] and \
|
||||
( f3_pd.brTypes[i] == TYPE_JAL or f3_pd.brTypes[i] == TYPE_JALR or f3_pd.isRets[i] \
|
||||
or (whether_jmp and f3_pd.brTypes[i] != TYPE_NONE and i == retake)) \
|
||||
for i in range(len(instr_ranges))]
|
||||
|
||||
res1.taken_occurs = (1 in res1.takens)
|
||||
|
||||
|
||||
next_fire = yield res1
|
||||
|
||||
res2 = PredCheckerStage2RetData()
|
||||
|
||||
if next_fire:
|
||||
if whether_jmp:
|
||||
jmp_off_range = res1.ranges[jmp_idx]
|
||||
instr_valid_off = instr_valids[jmp_idx]
|
||||
non_cfi_errs[jmp_idx] = jmp_off_range and instr_valid_off and f3_pd.brTypes[jmp_idx] == TYPE_NONE
|
||||
invalid_errs[jmp_idx] = jmp_off_range and not instr_valid_off
|
||||
jmp_tgt_predecode = decode_jmp_offs[jmp_idx] + pcs[jmp_idx]
|
||||
tgt_errs[jmp_idx] = jmp_off_range and instr_valid_off and (f3_pd.brTypes[jmp_idx] == TYPE_JAL or f3_pd.brTypes[jmp_idx] == TYPE_BR) and jmp_tgt_predecode != tgt
|
||||
|
||||
# self.fault_type = []
|
||||
# self.fixed_tgt = []
|
||||
|
||||
for i in range(len(jal_errs)):
|
||||
res2.faults[i] = (JAL_FAULT if jal_errs[i] else \
|
||||
JALR_FAULT if jalr_errs[i] else \
|
||||
RET_FAULT if ret_errs[i] else \
|
||||
TGT_FAULT if tgt_errs[i] else \
|
||||
NON_CFI_FAULT if non_cfi_errs[i] else \
|
||||
INVALID_TAKEN_FAULT if invalid_errs[i] else \
|
||||
NO_FAULT
|
||||
)
|
||||
res2.miss_pred[i] = (res2.faults[i] != NO_FAULT)
|
||||
cur_jmp_tgt = (pcs[i] + decode_jmp_offs[i]) & (1 << 64) -1
|
||||
res2.jmp_tgts[i] = cur_jmp_tgt
|
||||
if jal_errs[i] or tgt_errs[i]:
|
||||
res2.fixed_tgts[i] = cur_jmp_tgt
|
||||
else:
|
||||
seq_tgt = pcs[i] + (2 if rvcs[i] or not instr_valids[i] else 4)
|
||||
res2.fixed_tgts[i] = seq_tgt
|
||||
res2.fixed_tgts[i] &= (1 << 64) -1
|
||||
|
||||
yield res2
|
||||
|
||||
|
||||
def pred_check_stgs(self, f3_pd: F3PreDecodeData, pd: PreDecodeDataDef, instr_valids, instr_ranges, jmp_idx_all: ExistsIdx, pcs, tgt):
|
||||
jal_errs = [False] * 16
|
||||
jalr_errs = [False] * 16
|
||||
ret_errs = [False] * 16
|
||||
tgt_errs = [False] * 16
|
||||
non_cfi_errs = [False] * 16
|
||||
invalid_errs = [False] * 16
|
||||
|
||||
decode_jmp_offs = pd.jmp_offsets
|
||||
rvcs = pd.rvcs
|
||||
whether_jmp = jmp_idx_all.exists
|
||||
jmp_idx = jmp_idx_all.offsetIdx if whether_jmp else PREDICT_WIDTH
|
||||
# res = PredCheckerRetData()
|
||||
|
||||
res1 = PredCheckerStage1RetData()
|
||||
jal_idxs = self.check_num_errs(f3_pd.brTypes, TYPE_JAL)
|
||||
jal_errs = self.jmp_type_err_check(jal_idxs, whether_jmp, jmp_idx, instr_ranges, instr_valids)
|
||||
|
||||
jalr_init_idxs = self.check_num_errs(f3_pd.brTypes, TYPE_JALR)
|
||||
ret_idxs = self.check_num_errs(f3_pd.isRets, 1)
|
||||
jalr_idxs = [jalr and not ret for jalr, ret in zip(jalr_init_idxs, ret_idxs)]
|
||||
|
||||
jalr_errs = self.jmp_type_err_check(jalr_idxs, whether_jmp, jmp_idx, instr_ranges, instr_valids)
|
||||
# print(f"jalr_errs: {jalr_errs}")
|
||||
ret_errs = self.jmp_type_err_check(ret_idxs, whether_jmp, jmp_idx, instr_ranges, instr_valids)
|
||||
|
||||
true_jmp_stg = min(get_first_true(jal_errs), get_first_true(jalr_errs), get_first_true(ret_errs))
|
||||
# print(f"valid: {whether_jmp}; jmp_idx: {jmp_idx}, true_jmp_stg: {true_jmp_stg}")
|
||||
|
||||
if true_jmp_stg >= jmp_idx:
|
||||
res1.ranges = instr_ranges[:]
|
||||
retake = jmp_idx
|
||||
else:
|
||||
true_jmp_stg += 1
|
||||
res1.ranges = [True] * true_jmp_stg + [False] * (len(instr_ranges) - true_jmp_stg)
|
||||
retake = true_jmp_stg
|
||||
# print(f"res1_ranges: {res1.ranges}")
|
||||
res1.fixed_length = 16 if 0 not in res1.ranges else res1.ranges.index(0)
|
||||
# above done the stage 1 work: jal/jalr/ret errs and fix range & taken idx
|
||||
|
||||
res1.takens = [res1.ranges[i] and instr_valids[i] and \
|
||||
( f3_pd.brTypes[i] == TYPE_JAL or f3_pd.brTypes[i] == TYPE_JALR or f3_pd.isRets[i] \
|
||||
or (whether_jmp and (f3_pd.brTypes[i] != TYPE_NONE) and (i == retake))) \
|
||||
for i in range(len(res1.ranges))]
|
||||
|
||||
res1.taken_occurs = (1 in res1.takens)
|
||||
|
||||
|
||||
|
||||
res2 = PredCheckerStage2RetData()
|
||||
|
||||
if whether_jmp:
|
||||
jmp_off_range = res1.ranges[jmp_idx]
|
||||
instr_valid_off = instr_valids[jmp_idx]
|
||||
non_cfi_errs[jmp_idx] = jmp_off_range and instr_valid_off and f3_pd.brTypes[jmp_idx] == TYPE_NONE
|
||||
invalid_errs[jmp_idx] = jmp_off_range and not instr_valid_off
|
||||
jmp_tgt_predecode = decode_jmp_offs[jmp_idx] + pcs[jmp_idx]
|
||||
tgt_errs[jmp_idx] = jmp_off_range and instr_valid_off and (f3_pd.brTypes[jmp_idx] == TYPE_JAL or f3_pd.brTypes[jmp_idx] == TYPE_BR) and jmp_tgt_predecode != tgt
|
||||
|
||||
# self.fault_type = []
|
||||
# self.fixed_tgt = []
|
||||
|
||||
for i in range(len(jal_errs)):
|
||||
res2.faults[i] = (JAL_FAULT if jal_errs[i] else \
|
||||
JALR_FAULT if jalr_errs[i] else \
|
||||
RET_FAULT if ret_errs[i] else \
|
||||
TGT_FAULT if tgt_errs[i] else \
|
||||
NON_CFI_FAULT if non_cfi_errs[i] else \
|
||||
INVALID_TAKEN_FAULT if invalid_errs[i] else \
|
||||
NO_FAULT
|
||||
)
|
||||
res2.miss_pred[i] = (res2.faults[i] != NO_FAULT)
|
||||
cur_jmp_tgt = (pcs[i] + decode_jmp_offs[i]) & ((1 << 64) -1)
|
||||
res2.jmp_tgts[i] = cur_jmp_tgt
|
||||
if jal_errs[i] or tgt_errs[i]:
|
||||
res2.fixed_tgts[i] = cur_jmp_tgt
|
||||
else:
|
||||
seq_tgt = pcs[i] + (2 if (rvcs[i] or not instr_valids[i]) else 4)
|
||||
res2.fixed_tgts[i] = seq_tgt
|
||||
res2.fixed_tgts[i] &= (1 << 64) -1
|
||||
|
||||
return res1, res2
|
||||
|
||||
|
||||
# async def agent_pred_check(self, ftqValid, ftqOffBits, instrRange, instrValid, jumpOffset, pc, pds, tgt, fire):
|
||||
|
||||
# returning: whether fault exists and the true position; -1 means no
|
||||
def check_num_errs(self, num_list:list[int], tgt_val):
|
||||
return [tgt_val == x for x in num_list]
|
||||
|
||||
def jmp_type_err_check(self, idxs, whether_jmp, jmp_instr_offset, ranges, valids):
|
||||
return [ranges[i] and valids[i] and idxs[i] and ((not whether_jmp) or ((i < jmp_instr_offset) and whether_jmp)) for i in range(len(idxs))]
|
||||
|
||||
|
||||
# def check_empty
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
from ..instr_utils import fetch, concat,get_cfi_type, if_call, if_ret, is_rvc
|
||||
from ..datadef import PreDecodeDataDef, F3PreDecodeData
|
||||
|
||||
|
||||
|
||||
class F3PredecoderRef():
|
||||
|
||||
def f3_predecode(self, instrs: list[int]) -> F3PreDecodeData:
|
||||
ret = F3PreDecodeData()
|
||||
for i in range(16):
|
||||
instr = instrs[i]
|
||||
ret.brTypes.append(get_cfi_type(instr))
|
||||
ret.isCalls.append(1 if if_call(instr, ret.brTypes[i]) else 0)
|
||||
ret.isRets.append(1 if if_ret(instr, ret.brTypes[i]) else 0)
|
||||
return ret
|
||||
|
||||
|
||||
class PredecodeRef():
|
||||
def predecode(self, instrs: list[int]) -> PreDecodeDataDef:
|
||||
ret = PreDecodeDataDef()
|
||||
|
||||
for i in range(16):
|
||||
ret.new_instrs.append(instrs[i] | (instrs[i+1] << 16))
|
||||
ret.rvcs.append(is_rvc(ret.new_instrs[i]))
|
||||
ret.jmp_offsets.append(self.calc_imm(ret.new_instrs[i]))
|
||||
ret.valid_starts.append(False)
|
||||
ret.half_valid_starts.append(False)
|
||||
|
||||
if i == 0:
|
||||
ret.valid_starts[i] = True
|
||||
ret.half_valid_starts[i] = False
|
||||
elif i == 1:
|
||||
ret.half_valid_starts[i] = True
|
||||
ret.valid_starts[i] = ret.rvcs[0]
|
||||
else:
|
||||
if ret.half_valid_starts[i-1] == True:
|
||||
ret.half_valid_starts[i] = ret.rvcs[i-1]
|
||||
else:
|
||||
ret.half_valid_starts[i] = True
|
||||
|
||||
if ret.valid_starts[i-1] == True:
|
||||
ret.valid_starts[i] = ret.rvcs[i-1]
|
||||
else:
|
||||
ret.valid_starts[i] = True
|
||||
return ret
|
||||
|
||||
def extend_to_64(self, value, bits):
|
||||
value &= (1 << bits) - 1 # 截断到 bits 位
|
||||
sign_bit = 1 << (bits - 1)
|
||||
if value & sign_bit:
|
||||
# 手动补全高位 1,但仍保持非负 Python int(模拟补码)
|
||||
value |= ((-1) << bits) & ((1 << 64) - 1)
|
||||
return value
|
||||
|
||||
|
||||
def calc_imm(self, instr):
|
||||
|
||||
op = fetch(instr, 0, 1)
|
||||
funct = fetch(instr, 13, 15)
|
||||
|
||||
if op < 3: # C.J or beq
|
||||
|
||||
if op == 1 and (funct == 6 or funct == 7): # beq
|
||||
imm = concat(instr, [[12], [5, 6], [2], [10, 11], [3, 4]]) << 1
|
||||
return self.extend_to_64(imm, 9)
|
||||
# if funct == 5: # C.J
|
||||
return self.extend_to_64(concat(instr, [[12], [8], [9, 10], [6],[7], [2], [11], [3, 5]]) << 1, 12)
|
||||
|
||||
rvi_funct = fetch(instr, 0, 6)
|
||||
|
||||
if rvi_funct == 99: # 1100011 b
|
||||
return self.extend_to_64(concat(instr, [[31], [7], [25, 30], [8, 11]]) << 1, 13)
|
||||
|
||||
# if rvi_funct == 111: # "1101111 JAL":
|
||||
return self.extend_to_64(concat(instr, [[31], [12, 19], [20], [21, 30]]) << 1, 21)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,328 @@
|
|||
def rvc_expand_ref(rvc_instr,fsIsOff):
|
||||
ill = 0
|
||||
expanded = 0
|
||||
rvc_instr_16bit = rvc_instr & 0xFFFF
|
||||
opcode = rvc_instr_16bit & 0b11
|
||||
if opcode == 0b00:
|
||||
# C.ADDI4SPN指令
|
||||
if (rvc_instr_16bit & 0xE003) == 0x0000:
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x3C) << 4) | (((rvc_instr_16bit >> 5) & 0x1) << 3) | (((rvc_instr_16bit >> 5) & 0x2) << 1) | (((rvc_instr_16bit >> 5) & 0xC0) >> 2)
|
||||
rd = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
expanded = 0x00000013 | (nzuimm << 20) | (rd << 7) |(2<<15) # ADDI
|
||||
if nzuimm == 0:
|
||||
ill = 1
|
||||
else :
|
||||
ill = 0
|
||||
return expanded,ill #"C.ADDI4SPN -> ADDI"
|
||||
# C.FLD
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x2000:
|
||||
rd = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x3) << 6) | (((rvc_instr_16bit >> 5) & 0xE0) >>2)
|
||||
expanded = 0x00000007 | (nzuimm << 20) | (rd << 7) |(0b011 <<12) |(rs1 << 15) # ADDI
|
||||
if(fsIsOff==True):
|
||||
ill=1
|
||||
else:
|
||||
ill=0
|
||||
return expanded,ill
|
||||
#C.lw lw的格式形如: | imm[11:0] | rs1 | 010 | rd | 0000011 |
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x4000:
|
||||
rd = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x1) << 6) | (((rvc_instr_16bit >> 5) & 0xE0) >>2)| (((rvc_instr_16bit >> 5) & 0x2) << 1)
|
||||
expanded = 0x00000003 | (nzuimm << 20) | (rd << 7) |(0b010 <<12) |(rs1 << 15) # ADDI
|
||||
return expanded,ill
|
||||
#C.ld
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x6000:
|
||||
rd2 = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x3) << 6) | (((rvc_instr_16bit >> 5) & 0xE0) >>2)
|
||||
expanded = 0x00000003 | (nzuimm << 20) | (rd2 << 7) |(0b011 <<12) |(rs1 << 15) # ADDI
|
||||
return expanded,ill
|
||||
#c.lbu/lhu/lh/sb/sh
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x8000:
|
||||
rs2 = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
fun6 = (rvc_instr_16bit>>10)&0x3F
|
||||
if(fun6==0b100000):#lbu
|
||||
nzuimm = ((rvc_instr_16bit >> 4) & 0x2) | ((rvc_instr_16bit >> 6) & 0x1)
|
||||
expanded = 0x00000003 | (rs2 << 7) | (0b100 <<12) | (rs1 << 15) |(nzuimm << 20) #
|
||||
return expanded,ill
|
||||
elif(fun6==0b100001)&(((rvc_instr_16bit >> 6) & 0x1)==0):#lhu
|
||||
nzuimm = ((rvc_instr_16bit >> 4) & 0x2)
|
||||
expanded = 0x00000003 | (rs2 << 7) | (0b101 <<12) | (rs1 << 15) |(nzuimm << 20) #
|
||||
return expanded,ill
|
||||
elif(fun6==0b100001)&(((rvc_instr_16bit >> 6) & 0x1)==1):#lh
|
||||
nzuimm = ((rvc_instr_16bit >> 4) & 0x2)
|
||||
expanded = 0x00000003 | (rs2 << 7) | (0b001 <<12) | (rs1 << 15) |(nzuimm << 20) #
|
||||
return expanded,ill
|
||||
elif(fun6==0b100010):#sb
|
||||
nzuimm = ((rvc_instr_16bit >> 4) & 0x2) | ((rvc_instr_16bit >> 6) & 0x1)
|
||||
expanded = 0x00000023 | ((nzuimm & 0x1F) << 7) | (rs2 << 20) |(0b000 <<12) |(rs1 << 15) |((nzuimm & 0xFE0) << 20)#
|
||||
return expanded,ill
|
||||
elif((fun6==0b100011)&(((rvc_instr_16bit >> 6) & 0x1)==0)):#sh
|
||||
nzuimm = ((rvc_instr_16bit >> 4) & 0x2)
|
||||
expanded = 0x00000023 | ((nzuimm & 0x1F) << 7) | (rs2 << 20) |(0b001 <<12) |(rs1 << 15) |((nzuimm & 0xFE0) << 20)#
|
||||
return expanded,ill
|
||||
else:
|
||||
ill=2
|
||||
return expanded,ill
|
||||
#C.fsd
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xa000:
|
||||
rs2 = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x3) << 6) | (((rvc_instr_16bit >> 5) & 0xE0) >>2)
|
||||
expanded = 0x00000027 | ((nzuimm & 0x1F) << 7) | (rs2 << 20) |(0b011 <<12) |(rs1 << 15) |((nzuimm & 0xFE0) << 20)#
|
||||
if(fsIsOff==True):
|
||||
ill=1
|
||||
else:
|
||||
ill=0
|
||||
return expanded,ill
|
||||
|
||||
#C.sw RVI的SW格式形如:| imm[11:5]| rs2 | rs1 | 010 | imm[4:0] | 0100011 |
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xC000:
|
||||
rs2 = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x1) << 6) | (((rvc_instr_16bit >> 5) & 0xE0) >>2)| (((rvc_instr_16bit >> 5) & 0x2) << 1)
|
||||
expanded = 0x00000023 | ((nzuimm & 0x1F) << 7) | (rs2 << 20) |(0b010 <<12) |(rs1 << 15) |((nzuimm & 0xFE0) << 20)#
|
||||
return expanded,ill
|
||||
#C.sd
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xE000:
|
||||
rs2 = 8 + ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rs1 = 8 + ((rvc_instr_16bit >> 7) & 0x7)
|
||||
nzuimm = (((rvc_instr_16bit >> 5) & 0x3) << 6) | (((rvc_instr_16bit >> 5) & 0xE0) >>2)
|
||||
expanded = 0x00000023 | ((nzuimm & 0x1F) << 7) | (rs2 << 20) |(0b011 <<12) |(rs1 << 15) |((nzuimm & 0xFE0) << 20)#
|
||||
return expanded,ill
|
||||
else:
|
||||
return expanded,ill
|
||||
|
||||
elif opcode == 0b01:
|
||||
#C.addi
|
||||
if (rvc_instr_16bit & 0xE003) == 0x0001:
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
if ((rvc_instr_16bit >> 12) & 0x1):
|
||||
nzuimm = 0xFE0 | ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
else:
|
||||
nzuimm = 0x000 | ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
expanded = 0x00000013 | (rd << 7) | (0b000 << 12) |(rs1 << 15) | (nzuimm << 20) #
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x2001:
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
if ((rvc_instr_16bit >> 12) & 0x1):
|
||||
nzuimm = 0xFE0 | ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
else:
|
||||
nzuimm = 0x000 | ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
expanded = 0x0000001B | (rd << 7) | (0b000 << 12) |(rs1 << 15) | (nzuimm << 20) #
|
||||
if (rd == 0):
|
||||
ill = 1
|
||||
|
||||
return expanded,ill
|
||||
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x4001:
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
if ((rvc_instr_16bit >> 12) & 0x1):
|
||||
nzuimm = 0xFE0 | ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
else:
|
||||
nzuimm = 0x000 | ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
expanded = 0x00000013 | (rd << 7) | (0b000 << 12) |(0b00000 << 15) | (nzuimm << 20) #
|
||||
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x6001:
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
if(rd == 2) or (rd == 0):
|
||||
if ((rvc_instr_16bit >> 12) & 0x1):
|
||||
nzuimm=0xE00|(((rvc_instr_16bit>>2)&0x1)<<5)|(((rvc_instr_16bit>>3)&0x3)<<7)|(((rvc_instr_16bit>>5)&0x1)<<6)|(((rvc_instr_16bit>>6)&0x1)<<4)
|
||||
else:
|
||||
nzuimm=0x000|(((rvc_instr_16bit>>2)&0x1)<<5)|(((rvc_instr_16bit>>3)&0x3)<<7)|(((rvc_instr_16bit>>5)&0x1)<<6)|(((rvc_instr_16bit>>6)&0x1)<<4)
|
||||
if(nzuimm == 0):
|
||||
ill = 1
|
||||
expanded = 0x00000013 | (rd << 7) | (0b000 << 12) |(rd << 15) | (nzuimm << 20) #
|
||||
else:#lui lui指令的格式形如: | imm[31:12] | rd | 0110111 |
|
||||
if ((rvc_instr_16bit >> 12) & 0x1):
|
||||
nzuimm = 0xFFFE0000 | (((rvc_instr_16bit >> 2) & 0x1F) << 12)
|
||||
else:
|
||||
nzuimm = 0x00000000 | (((rvc_instr_16bit >> 2) & 0x1F) << 12)
|
||||
expanded = 0x00000037 | (rd << 7) | (nzuimm)
|
||||
if(nzuimm == 0):
|
||||
# ill = 1
|
||||
ill = 2 # temperarily exclude this condition
|
||||
expanded = 0x0000007F
|
||||
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x8001:
|
||||
fun6 = (rvc_instr_16bit>>10) & 0x3F
|
||||
fun2 = (rvc_instr_16bit>>5 ) & 0x3
|
||||
fun3 = ((rvc_instr_16bit >> 2) & 0x7)
|
||||
rd = 8+((rvc_instr_16bit >> 7) & 0x7)
|
||||
rs2 = 8+((rvc_instr_16bit >> 2) & 0x7)
|
||||
nzuimm = (rvc_instr_16bit>>2)&0x1F
|
||||
if(fun6 == 0x20):#SRLI
|
||||
expanded = 0x00000013 | (rd << 7) |0b101<<12| (rd << 15)| (nzuimm<<20)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x24):#SRLI
|
||||
expanded = 0x02000013 | (rd << 7) |0b101<<12| (rd << 15)| (nzuimm<<20)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x21):#SRAI
|
||||
expanded = 0x00000013 | (rd << 7) |0b101<<12| (rd << 15)| (nzuimm<<20)|(0b0100000<<25)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x25):#SRAI
|
||||
expanded = 0x00000013 | (rd << 7) |0b101<<12| (rd << 15)| (nzuimm<<20)|(0b0100001<<25)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x22):#andi
|
||||
expanded = 0x00000013 | (rd << 7) |0b111<<12| (rd << 15)| (nzuimm<<20)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x26):#andi
|
||||
expanded = 0x00000013 | (rd << 7) |0b111<<12| (rd << 15)| (nzuimm<<20)|(0b1111111<<25)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x23):#sub/xor/or/and
|
||||
if(fun2 == 0b00):#sub
|
||||
expanded = 0x00000033 | (rd << 7) |0b000<<12| (rd << 15)| (rs2<<20)|(0b0100000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b01):#xor
|
||||
expanded = 0x00000033 | (rd << 7) |0b100<<12| (rd << 15)| (rs2<<20)|(0b0000000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b10):#or
|
||||
expanded = 0x00000033 | (rd << 7) |0b110<<12| (rd << 15)| (rs2<<20)|(0b0000000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11):
|
||||
expanded = 0x00000033 | (rd << 7) |0b111<<12| (rd << 15)| (rs2<<20)|(0b0000000<<25)
|
||||
return expanded,ill
|
||||
elif(fun6 == 0x27):# C.subw/addw/mul/not/zext.b/sext.b/zext.h/sext.h/zext.w/
|
||||
if(fun2 == 0b00):#subw
|
||||
expanded = 0x0000003B | (rd << 7) |0b000<<12| (rd << 15)| (rs2<<20)|(0b0100000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b01):#addw
|
||||
expanded = 0x0000003B | (rd << 7) |0b000<<12| (rd << 15)| (rs2<<20)|(0b0000000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b10):#mul
|
||||
expanded = 0x00000033 | (rd << 7) |0b000<<12| (rd << 15)| (rs2<<20)|(0b0000001<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11)&(fun3==0b000):#zext.b
|
||||
expanded = 0x0ff00013 | (rd << 7) |0b111<<12| (rd << 15)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11)&(fun3==0b001):#sext.b
|
||||
expanded = 0x00000013 | (rd << 7) |0b001<<12| (rd << 15)|(0b00100<<20)|(0b0110000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11)&(fun3==0b010):#zext.h
|
||||
expanded = 0x0000003B | (rd << 7) |0b100<<12| (rd << 15)|(0b00000<<20)|(0b0000100<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11)&(fun3==0b011):#sext.h
|
||||
expanded = 0x00000013 | (rd << 7) |0b001<<12| (rd << 15)|(0b00101<<20)|(0b0110000<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11)&(fun3==0b100):#zext.w
|
||||
expanded = 0x0000003B | (rd << 7) |0b000<<12| (rd << 15)|(0b00000<<20)|(0b0000100<<25)
|
||||
return expanded,ill
|
||||
elif(fun2 == 0b11)&(fun3==0b101):#not
|
||||
expanded = 0xfff00013 | (rd << 7) |0b100<<12| (rd << 15)|(0b00000<<20)
|
||||
return expanded,ill
|
||||
else:
|
||||
ill =2
|
||||
return expanded,ill
|
||||
else:
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xa001:
|
||||
nzuimm = 0xFFFE0000|(((rvc_instr_16bit>>2)&0x1)<<5)|(((rvc_instr_16bit>>2)&0xe))|(((rvc_instr_16bit>>2)&0x10)<<3)|(((rvc_instr_16bit>>2)&0x20)<<1)|(((rvc_instr_16bit>>2)&0x40)<<4)|(((rvc_instr_16bit>>2)&0x180)<<1)|(((rvc_instr_16bit>>2)&0x200)>>5)|(((rvc_instr_16bit>>2)&0x400)<<1)
|
||||
if(((rvc_instr_16bit>>2)&0x400)>>10):
|
||||
expanded = 0x800FF06F|(0b00000 << 7)|((nzuimm &0x7fe) <<20)|((nzuimm &0x800) <<9)#
|
||||
else:
|
||||
expanded = 0x0000006F|(0b00000 << 7)|((nzuimm &0x7fe) <<20)|((nzuimm &0x800) <<9)#
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xc001:
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x7)+8
|
||||
nzuimm = 0xFF & ((((rvc_instr_16bit>>2)&0x1)<<4)|((((rvc_instr_16bit>>2)&0x6)>>1))|(((rvc_instr_16bit>>2)&0x18)<<2)|(((rvc_instr_16bit>>2)&0x300)>>6)|(((rvc_instr_16bit>>2)&0x400)>>3))
|
||||
if((((rvc_instr_16bit>>2)&0x400)>>10)):
|
||||
expanded = 0xF00000E3|((nzuimm&0x0F)<<8)|rs1<<15|((nzuimm&0xF0)<<21)
|
||||
else:
|
||||
expanded = 0x00000063|((nzuimm&0x0F)<<8)|rs1<<15|((nzuimm&0xF0)<<21)
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xe001:
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x7)+8
|
||||
nzuimm = 0xFF & ((((rvc_instr_16bit>>2)&0x1)<<4)|((((rvc_instr_16bit>>2)&0x6)>>1))|(((rvc_instr_16bit>>2)&0x18)<<2)|(((rvc_instr_16bit>>2)&0x300)>>6)|(((rvc_instr_16bit>>2)&0x400)>>3))
|
||||
if((((rvc_instr_16bit>>2)&0x400)>>10)):
|
||||
expanded = 0xF00000E3|((nzuimm&0x0F)<<8)|0x001<<12|rs1<<15|((nzuimm&0xF0)<<21)
|
||||
else:
|
||||
expanded = 0x00000063|((nzuimm&0x0F)<<8)|0x001<<12|rs1<<15|((nzuimm&0xF0)<<21)
|
||||
return expanded,ill
|
||||
elif opcode == 0b10:
|
||||
if (rvc_instr_16bit & 0xE003) == 0x0002:
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
|
||||
nzuimm = 0x000 | ((rvc_instr_16bit >> 2) & 0x1F) | ((rvc_instr_16bit >> 7) & 0x20)
|
||||
expanded = 0x00000013 | (rd << 7) | (0b001 << 12) |(rs1 << 15) | (nzuimm << 20) #
|
||||
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x2002:#fldsp
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
|
||||
nzuimm = (((rvc_instr_16bit >> 2) & 0x7) <<6) | ((rvc_instr_16bit >> 7) & 0x20) | ((rvc_instr_16bit >> 2) & 0x18)
|
||||
expanded = 0x00000007 | (rd << 7) | (0b011 << 12) |(0b00010 << 15) | (nzuimm << 20) #
|
||||
if(fsIsOff==True):
|
||||
ill=1
|
||||
else:
|
||||
ill=0
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x4002:#lwsp
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
|
||||
nzuimm = (((rvc_instr_16bit >> 2) & 0x3) <<6) | ((rvc_instr_16bit >> 7) & 0x20) | ((rvc_instr_16bit >> 2) & 0x1c)
|
||||
expanded = 0x00000003 | (rd << 7) | (0b010 << 12) |(0b00010 << 15) | (nzuimm << 20) #
|
||||
if (rd == 0):
|
||||
ill = 1
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x6002:#ldsp
|
||||
rd = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
|
||||
nzuimm = (((rvc_instr_16bit >> 2) & 0x7) <<6) | ((rvc_instr_16bit >> 7) & 0x20) | ((rvc_instr_16bit >> 2) & 0x18)
|
||||
expanded = 0x00000003 | (rd << 7) | (0b011 << 12) |(0b00010 << 15) | (nzuimm << 20) #
|
||||
if (rd == 0):
|
||||
ill = 1
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0x8002:#JR/MV/EBREAK/JALR/ADD
|
||||
rs1 = ((rvc_instr_16bit >> 7) & 0x1F)
|
||||
rs2 = ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
funct4 = (rvc_instr_16bit>>12)&0x1
|
||||
nzuimm = (((rvc_instr_16bit >> 2) & 0x7) <<6) | ((rvc_instr_16bit >> 7) & 0x20) | ((rvc_instr_16bit >> 2) & 0x18)
|
||||
if((funct4==0)&(rs2==0)&(rs1!=0)): #JR
|
||||
expanded = 0x00000067 | (0b00000 << 7) | (0b000 << 12) |(rs1 << 15) #
|
||||
elif(funct4==0)&(rs2!=0):#&(rs1!=0)):#MV 0000000 rs2 rs1 000 rd 0110011 ADD
|
||||
expanded = 0x00000013 | (rs1 << 7) | (0b000 << 12) |(rs2 << 15) #
|
||||
elif((funct4==1)&(rs2==0)&(rs1==0)): #ebreak
|
||||
expanded = 0b00000000000100000000000001110011
|
||||
elif((funct4==1)&(rs2==0)&(rs1!=0)): #jalr
|
||||
expanded = 0x00000067 | (0b00001 << 7) | (0b000 << 12) |(rs1 << 15) #
|
||||
elif(funct4==1)&(rs2!=0):#&(rs1!=0)): #add
|
||||
expanded = 0x00000033 | (rs1 << 7) | (0b000 << 12) |(rs1 << 15) |(rs2 << 20) #
|
||||
else:
|
||||
ill = 1
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xa002:#fsdsp
|
||||
rs2 = ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
nzuimm = ((rvc_instr_16bit >> 1) & 0x1C0) | ((rvc_instr_16bit >> 7) & 0x38)
|
||||
expanded = 0x00000027 |((nzuimm & 0x1F)<<7)| (0b011 << 12 ) | (0b00010 << 15)| (rs2 << 20)| ((nzuimm&0xFE0)<< 20) #
|
||||
if(fsIsOff==True):
|
||||
ill=1
|
||||
else:
|
||||
ill=0
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xc002:#swsp
|
||||
rs2 = ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
nzuimm = ((rvc_instr_16bit >> 1) & 0xC0) | ((rvc_instr_16bit >> 7) & 0x3C)
|
||||
expanded = 0x00000023 |((nzuimm & 0x1F)<<7)| (0b010 << 12 ) | (0b00010 << 15)| (rs2 << 20)| ((nzuimm&0xFE0)<< 20) #
|
||||
|
||||
return expanded,ill
|
||||
elif (rvc_instr_16bit & 0xE003) == 0xE002:#sdsp
|
||||
rs2 = ((rvc_instr_16bit >> 2) & 0x1F)
|
||||
nzuimm = ((rvc_instr_16bit >> 1) & 0x1C0) | ((rvc_instr_16bit >> 7) & 0x38)
|
||||
expanded = 0x00000023 |((nzuimm & 0x1F)<<7)| (0b011 << 12 ) | (0b00010 << 15)| (rs2 << 20)| ((nzuimm&0xFE0)<< 20) #
|
||||
|
||||
return expanded,ill
|
||||
else:
|
||||
return expanded,ill
|
||||
else:
|
||||
return rvc_instr, False
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
from typing import TypeVar, Generic, Optional
|
||||
T=TypeVar("T")
|
||||
|
||||
class FakeReg(Generic[T]):
|
||||
def __init__(self, init_val: T=0, default_ret_cur=True):
|
||||
self.cur:T = init_val
|
||||
self.next:T = init_val
|
||||
self.default_ret_cur = default_ret_cur
|
||||
|
||||
def fresh(self):
|
||||
self.cur = self.next
|
||||
|
||||
def get_cur(self) -> T:
|
||||
return self.cur
|
||||
|
||||
def get_next(self) -> T:
|
||||
return self.next
|
||||
|
||||
def set(self, val):
|
||||
self.next = val
|
||||
|
||||
def get(self) -> T:
|
||||
if self.default_ret_cur:
|
||||
return self.get_cur()
|
||||
return self.get_next()
|
||||
|
||||
|
||||
# class StagesReg():
|
||||
# def __init__(self, start=0, end=4, init_val=0):
|
||||
# self.regs : dict[int, FakeReg] = {}
|
||||
# self.start = start
|
||||
# self.end = end
|
||||
# for i in range(start, end+1):
|
||||
# self.regs[i] = FakeReg(init_val=init_val)
|
||||
|
||||
# def set(self, val):
|
||||
# self.regs[self.start].set(val)
|
||||
|
||||
# def fresh(self, fires: dict[int, bool]):
|
||||
# for i in range(self.end+1, self.start-1, -1):
|
||||
# if (i > self.start) and fires[i]:
|
||||
# self.regs[i].set(self.regs[i-1].get_cur())
|
||||
# # self.regs[i].fresh()
|
||||
|
||||
# def get(self, idx):
|
||||
# if idx not in self.regs.keys():
|
||||
# print("key err! please check!")
|
||||
# return None
|
||||
|
||||
# return self.regs[idx].get()
|
||||
|
||||
|
||||
class StagesWire(Generic[T]):
|
||||
|
||||
|
||||
def __init__(self, start: int = 0, end: int = 4, init_val: T = None):
|
||||
self.wires: dict[int, T] = {}
|
||||
self.start: int = start
|
||||
self.end: int = end
|
||||
for i in range(start, end+1):
|
||||
self.wires[i] = init_val
|
||||
|
||||
|
||||
def set(self, val: T) -> None:
|
||||
self.wires[self.start] = val
|
||||
|
||||
def fresh(self, fires: dict[int, bool]) -> None:
|
||||
# 从高到低搬运(i <- i-1),只在该级 fire 时搬
|
||||
for i in range(self.end, self.start, -1):
|
||||
if fires.get(i, False):
|
||||
self.wires[i] = self.wires[i - 1]
|
||||
|
||||
def get(self, idx: int) -> T:
|
||||
if idx not in self.wires:
|
||||
raise KeyError(f"idx {idx} not in [{self.start}, {self.end}]")
|
||||
return self.wires[idx]
|
||||
|
||||
|
||||
class StagesWireManager(Generic[T]):
|
||||
def __init__(self):
|
||||
self.wires: list[StagesWire] = []
|
||||
|
||||
def create(self, start: int = 0, end: int = 4, init_val: Optional[T] = None) -> StagesWire[T]:
|
||||
new_wire = StagesWire(start=start, end=end, init_val=init_val)
|
||||
self.wires.append(new_wire)
|
||||
return new_wire
|
||||
|
||||
def fresh_all(self, fires: dict[int, bool]):
|
||||
for wire in self.wires:
|
||||
wire.fresh(fires)
|
||||
|
||||
class StagesReg(Generic[T]):
|
||||
def __init__(self, start: int = 0, end: int = 4, init_val: T = None): # type: ignore[assignment]
|
||||
self.regs: dict[int, FakeReg[T]] = {}
|
||||
self.start: int = start
|
||||
self.end: int = end
|
||||
for i in range(start, end + 1):
|
||||
self.regs[i] = FakeReg[T](init_val)
|
||||
|
||||
def set(self, val: T) -> None:
|
||||
self.regs[self.start].set(val)
|
||||
|
||||
def fresh(self, fires: dict[int, bool]) -> None:
|
||||
# 从高到低搬运(i <- i-1),只在该级 fire 时搬
|
||||
for i in range(self.end, self.start, -1):
|
||||
if fires.get(i, False):
|
||||
self.regs[i].set(self.regs[i - 1].get_cur())
|
||||
# 统一提交
|
||||
# for r in self.regs.values():
|
||||
# r.fresh()
|
||||
|
||||
def get(self, idx: int) -> T:
|
||||
if idx not in self.regs:
|
||||
raise KeyError(f"idx {idx} not in [{self.start}, {self.end}]")
|
||||
return self.regs[idx].get()
|
||||
Loading…
Reference in New Issue