This commit is contained in:
DingL2 2025-10-04 18:44:40 +08:00
parent 4634979680
commit 192c19c853
9 changed files with 1950 additions and 0 deletions

1
.gitignore vendored
View File

@ -143,6 +143,7 @@ celerybeat.pid
.venv
venv/
ENV/
!ut_frontend/ifu/ifu_top/env/
env.bak/
venv.bak/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

115
ut_frontend/ifu/ifu_top/env/tools.py vendored Normal file
View File

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