|
|
|
# A2O Core
|
|
|
|
|
|
|
|
import cocotb
|
|
|
|
from cocotb.triggers import Timer, RisingEdge
|
|
|
|
from cocotb.binary import BinaryValue
|
|
|
|
from cocotb.handle import Force
|
|
|
|
from cocotb.handle import Release
|
|
|
|
from cocotb.result import TestSuccess
|
|
|
|
|
|
|
|
from dotmap import DotMap
|
|
|
|
import itertools
|
|
|
|
|
|
|
|
from OPEnv import *
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------------------------
|
|
|
|
# Tasks
|
|
|
|
|
|
|
|
async def A2OConfig(dut, sim):
|
|
|
|
"""Configure A2O. """
|
|
|
|
|
|
|
|
# A2L2 load/store credits
|
|
|
|
creditsLd = sim.a2o.root.lq0.lsq.arb.load_cred_cnt_d # 8 max
|
|
|
|
creditsLdMax = sim.a2o.root.lq0.lsq.arb.ld_cred_max # hdw check
|
|
|
|
creditsSt = sim.a2o.root.lq0.lsq.arb.store_cred_cnt_d # 32 max
|
|
|
|
creditsStMax = sim.a2o.root.lq0.lsq.arb.st_cred_max # hdw check
|
|
|
|
creditsLdStSingle = sim.a2o.root.lq0.lsq.arb.spr_xucr0_cred_d # 1 total credit
|
|
|
|
#wtf this affects A2L2 - default=1
|
|
|
|
# sim.a2o.root.lq0.lsq.arb.spr_lsucr0_b2b_q # 0=crit first, every other 1=crit first, b2b **the a2l2 spec does not say crit must be first**
|
|
|
|
lsucr0_d = sim.a2o.root.lq0.ctl.spr.lq_spr_cspr.lsucr0_d
|
|
|
|
lsucr0_q = sim.a2o.root.lq0.ctl.spr.lq_spr_cspr.lsucr0_q
|
|
|
|
cpcr2_d = sim.a2o.root.iuq0.iuq_ifetch0.iuq_spr0.cpcr2_d
|
|
|
|
cpcr2_q = sim.a2o.root.iuq0.iuq_ifetch0.iuq_spr0.cpcr2_l2
|
|
|
|
cpcr2_act = sim.a2o.root.iuq0.iuq_ifetch0.iuq_spr0.cpcr2_wren
|
|
|
|
cpcr4_d = sim.a2o.root.iuq0.iuq_ifetch0.iuq_spr0.cpcr4_d
|
|
|
|
cpcr4_q = sim.a2o.root.iuq0.iuq_ifetch0.iuq_spr0.cpcr4_l2
|
|
|
|
cpcr4_act = sim.a2o.root.iuq0.iuq_ifetch0.iuq_spr0.cpcr4_wren
|
|
|
|
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
|
|
|
|
if sim.a2o.config.creditsLd is not None:
|
|
|
|
creditsLd.value = Force(sim.a2o.config.creditsLd)
|
|
|
|
creditsLdMax.value = Force(sim.a2o.config.creditsLd)
|
|
|
|
sim.msg(f'A2O: load credits changed from {creditsLd.value.integer} to {sim.a2o.config.creditsLd}.')
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
creditsLd.value = Release()
|
|
|
|
else:
|
|
|
|
sim.msg(f'A2O: load credits = {creditsLd.value.integer}.')
|
|
|
|
|
|
|
|
if sim.a2o.config.creditsSt is not None:
|
|
|
|
creditsSt.value = Force(sim.a2o.config.creditsSt)
|
|
|
|
creditsStMax.value = Force(sim.a2o.config.creditsSt)
|
|
|
|
sim.msg(f'A2O: store credits changed from {creditsSt.value.integer} to {sim.a2o.config.creditsSt}.')
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
creditsSt.value = Release()
|
|
|
|
else:
|
|
|
|
sim.msg(f'A2O: store credits = {creditsSt.value.integer}.')
|
|
|
|
|
|
|
|
if sim.a2o.config.creditsLdStSingle is not None:
|
|
|
|
v = 1 if sim.a2o.config.creditsLdStSingle else 0
|
|
|
|
creditsLdStSingle.value = Force(v)
|
|
|
|
sim.msg(f'A2O: only one load OR store allowed when credits=1/1.')
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
#creditsLdStSingle.value = Release() # to release have to set _q with xucr0_d[51] and xucr0_act
|
|
|
|
elif sim.a2o.root.lq0.lsq.arb.load_cred_cnt_q.value.integer == 1 and sim.a2o.root.lq0.lsq.arb.store_cred_cnt_q.value.integer == 1 and sim.a2o.root.lq0.lsq.arb.spr_xucr0_cred_q.value.integer == 1:
|
|
|
|
sim.msg(f'A2O: single-credit mode is enabled.')
|
|
|
|
|
|
|
|
#wtf make a function - needs mask,thread
|
|
|
|
if sim.a2o.config.lsDataForward is not None:
|
|
|
|
v = 1 if sim.a2o.config.lsDataForward else 0
|
|
|
|
sim.msg(f'A2O: LSUCR0 = {hex(lsucr0_q.value), 8}')
|
|
|
|
sim.msg(f'A2O: Setting LSUCR0[DFWD] = {v}.')
|
|
|
|
v = v << 2
|
|
|
|
v = (lsucr0_q.value.integer & ~0x4) | v
|
|
|
|
lsucr0_d.value = Force(v)
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
lsucr0_d.value = Release()
|
|
|
|
sim.msg(f'A2O: LSUCR0 = {hex(lsucr0_q.value), 8}')
|
|
|
|
|
|
|
|
if sim.a2o.config.cpcr4_sq_cnt is not None:
|
|
|
|
v = sim.a2o.config.cpcr4_sq_cnt
|
|
|
|
sim.msg(f'A2O: CPCR4 = {hex(cpcr4_q[0], 8)}')
|
|
|
|
sim.msg(f'A2O: Setting CPCR4[SQ_CNT] = {v}.')
|
|
|
|
v = v << 0
|
|
|
|
v = (cpcr4_q[0].value.integer & ~0x1F) | v
|
|
|
|
await RisingEdge(dut.clk_1x) # need cuz of act?
|
|
|
|
cpcr4_d[0].value = Force(v)
|
|
|
|
cpcr4_act.value = Force(1)
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
await RisingEdge(dut.clk_1x) # need cuz of act?
|
|
|
|
cpcr4_d[0].value = Release()
|
|
|
|
cpcr4_act.value = Release()
|
|
|
|
sim.msg(f'A2O: CPCR4 = {hex(cpcr4_q[0], 8)}')
|
|
|
|
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
|
|
|
|
async def A2ODriver(dut, sim):
|
|
|
|
"""A2O Core Driver"""
|
|
|
|
|
|
|
|
transTypes = {
|
|
|
|
'00': 'IFETCH',
|
|
|
|
'08': 'LOAD',
|
|
|
|
'20': 'STORE'
|
|
|
|
}
|
|
|
|
|
|
|
|
ok = True
|
|
|
|
readPending = []
|
|
|
|
countReads = 0
|
|
|
|
mem = {}
|
|
|
|
sim.msg('A2O Driver: nothing to do.')
|
|
|
|
|
|
|
|
#while ok and not sim.done:
|
|
|
|
# await RisingEdge(dut.clk_1x)
|
|
|
|
|
|
|
|
|
|
|
|
# A2O Checker
|
|
|
|
# check protocol, etc.
|
|
|
|
async def A2OChecker(dut, sim):
|
|
|
|
"""A2O Core Checker """
|
|
|
|
|
|
|
|
me = 'A2O Checker'
|
|
|
|
ok = True
|
|
|
|
sim.msg(f'{me}: started.')
|
|
|
|
|
|
|
|
# errors
|
|
|
|
creditsLdErr = sim.a2o.root.lq0.lsq.arb.ld_cred_err_q
|
|
|
|
creditsStErr = sim.a2o.root.lq0.lsq.arb.st_cred_err_q
|
|
|
|
errors = [
|
|
|
|
{'name': 'Load Credits', 'sig': creditsLdErr},
|
|
|
|
{'name': 'Store Credits', 'sig': creditsStErr},
|
|
|
|
]
|
|
|
|
|
|
|
|
while ok:
|
|
|
|
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
|
|
|
|
if not sim.resetDone:
|
|
|
|
continue
|
|
|
|
|
|
|
|
for i in range(len(errors)):
|
|
|
|
assert errors[i]['sig'].value == 0, f'{me} Error: {errors[i]["name"]}'
|
|
|
|
|
|
|
|
# A2O Monitor
|
|
|
|
# count transactions, etc.
|
|
|
|
# fail on bad addresses
|
|
|
|
async def A2OMonitor(dut, sim):
|
|
|
|
"""A2O Core Monitor"""
|
|
|
|
|
|
|
|
me = 'A2O Monitor'
|
|
|
|
ok = True
|
|
|
|
sim.msg(f'{me}: started.')
|
|
|
|
|
|
|
|
# completions
|
|
|
|
iu0Comp = sim.a2o.root.iu_lq_i0_completed
|
|
|
|
iu0CompIFAR = sim.a2o.root.iuq0.iuq_cpl_top0.iuq_cpl0.cp2_i0_ifar
|
|
|
|
iu1Comp = sim.a2o.root.iu_lq_i1_completed
|
|
|
|
iu1CompIFAR = sim.a2o.root.iuq0.iuq_cpl_top0.iuq_cpl0.cp2_i1_ifar
|
|
|
|
iuCompFlushIFAR = sim.a2o.root.cp_t0_flush_ifar
|
|
|
|
cp3NIA = sim.a2o.root.iuq0.iuq_cpl_top0.iuq_cpl0.iuq_cpl_ctrl.cp3_nia_q # nia after last cycle's completions
|
|
|
|
|
|
|
|
# GPR ppol and arch map
|
|
|
|
gprCompMap = []
|
|
|
|
lastGprCompMap = []
|
|
|
|
#wtf check what 33:36 are!
|
|
|
|
for i in range(36):
|
|
|
|
gprCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.gpr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
|
|
|
|
lastGprCompMap.append(i)
|
|
|
|
|
|
|
|
gpr = []
|
|
|
|
for i in range(144):
|
|
|
|
gpr.append(sim.a2o.root.xu0.gpr.gpr0.loc[i].dat)
|
|
|
|
|
|
|
|
# CR fields pool and arch map
|
|
|
|
crCompMap = []
|
|
|
|
lastCrCompMap = []
|
|
|
|
for i in range(8):
|
|
|
|
crCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.cr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
|
|
|
|
lastCrCompMap.append(i)
|
|
|
|
|
|
|
|
cr = []
|
|
|
|
for i in range(24):
|
|
|
|
cr.append(sim.a2o.root.xu0.cr.entry[i].reg_latch.dout)
|
|
|
|
|
|
|
|
# XER pool and arch map
|
|
|
|
xerCompMap = []
|
|
|
|
lastXerCompMap = []
|
|
|
|
for i in range(1):
|
|
|
|
xerCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.xer_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
|
|
|
|
lastXerCompMap.append(i)
|
|
|
|
|
|
|
|
xer = []
|
|
|
|
for i in range(12):
|
|
|
|
xer.append(sim.a2o.root.xu0.xer.entry[i].reg_latch.dout)
|
|
|
|
|
|
|
|
# CTR pool and arch map
|
|
|
|
ctrCompMap = []
|
|
|
|
lastCtrCompMap = []
|
|
|
|
for i in range(1):
|
|
|
|
ctrCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.ctr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
|
|
|
|
lastCtrCompMap.append(i)
|
|
|
|
|
|
|
|
ctr = []
|
|
|
|
for i in range(8):
|
|
|
|
ctr.append(sim.a2o.root.xu0.ctr.entry[i].reg_latch.dout)
|
|
|
|
|
|
|
|
# LR pool and arch map
|
|
|
|
lrCompMap = []
|
|
|
|
lastLrCompMap = []
|
|
|
|
for i in range(1):
|
|
|
|
lrCompMap.append(sim.a2o.root.iuq0.iuq_slice_top0.slice0.rn_top0.fx_rn0.lr_rn_map.xhdl3.comp_map0[i].comp_map_latch.dout)
|
|
|
|
lastLrCompMap.append(i)
|
|
|
|
|
|
|
|
lr = []
|
|
|
|
for i in range(8):
|
|
|
|
lr.append(sim.a2o.root.xu0.lr.entry[i].reg_latch.dout)
|
|
|
|
|
|
|
|
lastComp = ''
|
|
|
|
lastCompCycle = 0
|
|
|
|
lastCompCount = 0
|
|
|
|
lastStack = ''
|
|
|
|
lastPrintf = ''
|
|
|
|
|
|
|
|
while ok:
|
|
|
|
|
|
|
|
await RisingEdge(dut.clk_1x)
|
|
|
|
|
|
|
|
if not sim.resetDone:
|
|
|
|
continue
|
|
|
|
|
|
|
|
# allow registered callbacks to be called here
|
|
|
|
stack = sim.mem.dump(0x1FD00, 0x1FFFF, cols=8, trimLeadingZeros=True, trimTrailingZeros=True)
|
|
|
|
if stack != lastStack:
|
|
|
|
sim.msg('Stack:\n' + stack)
|
|
|
|
lastStack = stack
|
|
|
|
|
|
|
|
printf = sim.mem.dump(0x1C000, 0x1C1FF, cols=8, trimLeadingZeros=True, trimTrailingZeros=True)
|
|
|
|
if printf != lastPrintf:
|
|
|
|
sim.msg('Print buffer:\n' + printf)
|
|
|
|
lastPrintf = printf
|
|
|
|
|
|
|
|
comp = ''
|
|
|
|
#wtf seeing something weird here
|
|
|
|
# there are cases where x's are in some bits of comp ifar's; maybe ok (predict array?) but why is completed indicated?
|
|
|
|
|
|
|
|
if iu0Comp.value == 1:
|
|
|
|
comp = f'0:{sim.safeint(iu0CompIFAR.value.binstr + "00", 2):06X} '
|
|
|
|
|
|
|
|
if iu1Comp.value == 1:
|
|
|
|
comp = f'{comp}1:{sim.safeint(iu1CompIFAR.value.binstr + "00", 2):06X} '
|
|
|
|
|
|
|
|
if comp == '':
|
|
|
|
if sim.a2o.stopOnHang != 0 and sim.cycle - lastCompCycle > sim.a2o.stopOnHang:
|
|
|
|
sim.ok = False
|
|
|
|
sim.fail = f'No completion detected in {sim.a2o.stopOnHang} cycles'
|
|
|
|
assert False, sim.fail
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
comp = f'{comp}{sim.safeint(iuCompFlushIFAR.value.binstr + "00", 2):016X}'
|
|
|
|
sim.msg(f'C0: CP {comp}')
|
|
|
|
lastCompCycle = sim.cycle
|
|
|
|
|
|
|
|
if sim.a2o.iarPass is not None:
|
|
|
|
if sim.safeint(iu0CompIFAR.value.binstr + "00", 2) == sim.a2o.iarPass:
|
|
|
|
sim.msg(f'Passing IAR detected: {sim.a2o.iarPass:08X}')
|
|
|
|
raise TestSuccess('Test passed.')
|
|
|
|
|
|
|
|
if sim.a2o.iarPass is not None:
|
|
|
|
if sim.safeint(iu0CompIFAR.value.binstr + "00", 2) == sim.a2o.iarPass:
|
|
|
|
sim.ok = False
|
|
|
|
sim.fail = 'Failing IAR detected'
|
|
|
|
assert False, sim.fail
|
|
|
|
break
|
|
|
|
|
|
|
|
if sim.a2o.stopOnLoop is not None and sim.a2o.stopOnLoop > 0:
|
|
|
|
if comp == lastComp:
|
|
|
|
lastCompCount += 1
|
|
|
|
if lastCompCount == sim.a2o.stopOnLoop:
|
|
|
|
sim.ok = False
|
|
|
|
sim.fail = 'Code hang detected'
|
|
|
|
assert False, sim.fail
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
lastCompCount = 0
|
|
|
|
lastComp = comp
|
|
|
|
|
|
|
|
if sim.a2o.traceFacUpdates:
|
|
|
|
# renamables
|
|
|
|
for i in range(36):
|
|
|
|
good, arch = sim.safeint(gprCompMap[i].value.binstr, 2, rc=True)
|
|
|
|
if good and arch != lastGprCompMap[i]:
|
|
|
|
sim.msg(f'GPR Update: R{i:02d}={hex(gpr[arch], 16)}')
|
|
|
|
lastGprCompMap[i] = arch
|
|
|
|
for i in range(8):
|
|
|
|
good, arch = sim.safeint(crCompMap[i].value.binstr, 2, rc=True)
|
|
|
|
if good and arch != lastCrCompMap[i]:
|
|
|
|
sim.msg(f'CR Update: F{i:01d}={hex(cr[arch], 1)}')
|
|
|
|
lastCrCompMap[i] = arch
|
|
|
|
for i in range(1):
|
|
|
|
good, arch = sim.safeint(xerCompMap[i].value.binstr, 2, rc=True)
|
|
|
|
if good and arch != lastXerCompMap[i]:
|
|
|
|
v = xer[arch].value.binstr
|
|
|
|
sim.msg(f'XER Update: SO/OV/CA={v[0:3]} LEN={int(v[3:],2):02X}')
|
|
|
|
lastXerCompMap[i] = arch
|
|
|
|
for i in range(1):
|
|
|
|
good, arch = sim.safeint(ctrCompMap[i].value.binstr, 2, rc=True)
|
|
|
|
if good and arch != lastCtrCompMap[i]:
|
|
|
|
sim.msg(f'CTR Update:{hex(ctr[arch], 16)}')
|
|
|
|
lastCtrCompMap[i] = arch
|
|
|
|
for i in range(1):
|
|
|
|
good, arch = sim.safeint(lrCompMap[i].value.binstr, 2, rc=True)
|
|
|
|
if good and arch != lastLrCompMap[i]:
|
|
|
|
sim.msg(f'LR Update:{hex(lr[arch], 16)}')
|
|
|
|
lastLrCompMap[i] = arch
|
|
|
|
|
|
|
|
sim.msg(f'{me}: ended.')
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------------------------
|
|
|
|
# Classes
|
|
|
|
|
|
|
|
class A2O:
|
|
|
|
config = A2OConfig
|
|
|
|
driver = A2ODriver
|
|
|
|
checker = A2OChecker
|
|
|
|
monitor = A2OMonitor
|
|
|
|
|
|
|
|
def __init__(self, sim):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class A2OCore(DotMap):
|
|
|
|
def __init__(self, sim, root=None):
|
|
|
|
super().__init__()
|
|
|
|
self.sim = sim
|
|
|
|
if root is None:
|
|
|
|
self.root = sim.dut.c0
|
|
|
|
else:
|
|
|
|
self.root = root
|
|
|
|
self.traceFacUpdates = False
|
|
|
|
self.stopOnHang = 0 # cycles of no completions; could be tuple(start cyc, hang cycs)
|
|
|
|
self.stopOnLoop = 0 # number of consecutive identical comopletions
|
|
|
|
self.iarPass = None
|
|
|
|
self.iarFail = None
|
|
|
|
self.config = DotMap({
|
|
|
|
'creditsLd': None,
|
|
|
|
'creditsSt': None,
|
|
|
|
'creditsLdStSingle': None,
|
|
|
|
'lsDataForward' : None,
|
|
|
|
'cpcr4_sq_cnt' : None
|
|
|
|
})
|