diff --git a/dev/sim/coco/A2L2.py b/dev/sim/coco/A2L2.py index dedd779..8226373 100755 --- a/dev/sim/coco/A2L2.py +++ b/dev/sim/coco/A2L2.py @@ -9,6 +9,8 @@ from cocotb.handle import Release from dotmap import DotMap import itertools +from OPEnv import * + # ------------------------------------------------------------------------------------------------ # Classes @@ -100,7 +102,8 @@ class A2L2Trans(DotMap): if self.load: self.addr = self.addr & 0xFFFFFFF0 elif self.store: - self.addr = self.addr & 0xFFFFFFE0 + #self.addr = self.addr & 0xFFFFFFE0 #wtf definitely 16B-aligned occurring + self.addr = self.addr & 0xFFFFFFF0 if self.be == None or self.data == None: raise Exception('A2L2Trans: store must have BE and data') else: @@ -196,16 +199,6 @@ class A2L2Trans(DotMap): else: raise Exception(f'A2L2Trans: unsupported store len={self.len}') - -# ------------------------------------------------------------------------------------------------ -# Functions - -def hex(n, pad=0): - if pad: - return f'000000000000000000000000{n.value.hex()[2:].upper()}'[-pad:] - else: - return n.value.hex()[2:].upper() - # ------------------------------------------------------------------------------------------------ # Tasks diff --git a/dev/sim/coco/A2O.py b/dev/sim/coco/A2O.py new file mode 100755 index 0000000..e54e865 --- /dev/null +++ b/dev/sim/coco/A2O.py @@ -0,0 +1,201 @@ +# 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 dotmap import DotMap +import itertools + +from OPEnv import * + +# ------------------------------------------------------------------------------------------------ +# Tasks + +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 = dut.c0.lq0.lsq.arb.ld_cred_err_q + creditsStErr = dut.c0.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 = dut.c0.iu_lq_i0_completed + iu0CompIFAR = dut.c0.iuq0.iuq_cpl_top0.iuq_cpl0.cp2_i0_ifar + iu1Comp = dut.c0.iu_lq_i1_completed + iu1CompIFAR = dut.c0.iuq0.iuq_cpl_top0.iuq_cpl0.cp2_i1_ifar + iuCompFlushIFAR = dut.c0.cp_t0_flush_ifar + cp3NIA = dut.c0.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(dut.c0.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(dut.c0.xu0.gpr.gpr0.loc[i].dat) + + # CR fields pool and arch map + crCompMap = [] + lastCrCompMap = [] + for i in range(8): + crCompMap.append(dut.c0.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(dut.c0.xu0.cr.entry[i].reg_latch.dout) + + # XER pool and arch map + xerCompMap = [] + lastXerCompMap = [] + for i in range(1): + xerCompMap.append(dut.c0.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(dut.c0.xu0.xer.entry[i].reg_latch.dout) + + # CTR pool and arch map + ctrCompMap = [] + lastCtrCompMap = [] + for i in range(1): + ctrCompMap.append(dut.c0.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(dut.c0.xu0.ctr.entry[i].reg_latch.dout) + + # LR pool and arch map + lrCompMap = [] + lastLrCompMap = [] + for i in range(1): + lrCompMap.append(dut.c0.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(dut.c0.xu0.lr.entry[i].reg_latch.dout) + + while ok: + + await RisingEdge(dut.clk_1x) + + if not sim.resetDone: + continue + + 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 != '': + comp = f'{comp}{sim.safeint(iuCompFlushIFAR.value.binstr + "00", 2):016X}' + sim.msg(f'C0: CP {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 + +# ------------------------------------------------------------------------------------------------ +# Classes + +class A2O: + driver = A2ODriver + checker = A2OChecker + monitor = A2OMonitor + + def __init__(self, sim): + pass + +class A2OCore(DotMap): + def __init__(self, sim): + super().__init__() + self.sim = sim + self.traceFacUpdates = False \ No newline at end of file diff --git a/dev/sim/coco/OPEnv.py b/dev/sim/coco/OPEnv.py index fc1db51..ccbc145 100755 --- a/dev/sim/coco/OPEnv.py +++ b/dev/sim/coco/OPEnv.py @@ -18,6 +18,8 @@ class Sim(DotMap): def __init__(self, dut, cfg=None): super().__init__() self.dut = dut + self.resetDone = False + # defaults self.memFiles = ['../mem/boot_ieq1.bin.hex'] #wtf cmdline parm self.threads = None @@ -30,10 +32,13 @@ class Sim(DotMap): self.maxCycles = 500 self.memFiles = None self.config = DotMap() + # these should be in a2 core class self.config.core = DotMap({ 'creditsLd': None, 'creditsSt': None, - 'creditsLdStSingle': False + 'creditsLdStSingle': None, + 'lsDataForward' : None, + 'cpcr4_sq_cnt' : None }) self.config.a2l2 = DotMap({ 'badAddr': [('E0','E0', 'IRW')] @@ -56,6 +61,25 @@ class Sim(DotMap): self.threads = 1 self.msg(f'Set threads={self.threads}.') + # helpers + # wtf: assertFail doesn't work??#@#!! + def safeint(self, v, n=10, assertFail=True, rc=False): + try: + res = int(v, n) + ok = True + except: + self.ok = False + self.fail = f'Bad integer conversion: {v},{n}' + if assertFail: + assert(False, self.fail) + res = 0 + ok = False + if rc: + return (ok, res) + else: + return res + + class TransQ(DotMap): def __init__(self): super().__init__() @@ -115,3 +139,12 @@ class Memory(DotMap): else: self.sim.msg(f'Mem Update: @{addr:08X} {self.data[addr]:08X}->{data:08X}') self.data[addr] = data + +# ------------------------------------------------------------------------------------------------ +# Functions + +def hex(n, pad=0): + if pad: + return f'000000000000000000000000{n.value.hex()[2:].upper()}'[-pad:] + else: + return n.value.hex()[2:].upper() diff --git a/dev/sim/coco/tb.py b/dev/sim/coco/tb.py index 9e66f9a..33b8896 100755 --- a/dev/sim/coco/tb.py +++ b/dev/sim/coco/tb.py @@ -11,6 +11,7 @@ import itertools from dotmap import DotMap from OPEnv import * +from A2O import * from A2L2 import * # ------------------------------------------------------------------------------------------------ @@ -92,9 +93,17 @@ async def config(dut, sim): creditsLdMax = dut.c0.lq0.lsq.arb.ld_cred_max # hdw check creditsSt = dut.c0.lq0.lsq.arb.store_cred_cnt_d # 32 max creditsStMax = dut.c0.lq0.lsq.arb.st_cred_max # hdw check - creditsLdStSingle = dut.c0.lq0.lsq.arb.spr_xucr0_cred_d.value # 1 total credit + creditsLdStSingle = dut.c0.lq0.lsq.arb.spr_xucr0_cred_d # 1 total credit #wtf this affects A2L2 - default=1 - #creditsLdStSingle = dut.c0.lq0.lsq.arb.spr_lsucr0_b2b_q.value # 0=crit first, every other 1=crit first, b2b **the a2l2 spec does not say crit must be first** + # dut.c0.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 = dut.c0.lq0.ctl.spr.lq_spr_cspr.lsucr0_d + lsucr0_q = dut.c0.lq0.ctl.spr.lq_spr_cspr.lsucr0_q + cpcr2_d = dut.c0.iuq0.iuq_ifetch0.iuq_spr0.cpcr2_d + cpcr2_q = dut.c0.iuq0.iuq_ifetch0.iuq_spr0.cpcr2_l2 + cpcr2_act = dut.c0.iuq0.iuq_ifetch0.iuq_spr0.cpcr2_wren + cpcr4_d = dut.c0.iuq0.iuq_ifetch0.iuq_spr0.cpcr4_d + cpcr4_q = dut.c0.iuq0.iuq_ifetch0.iuq_spr0.cpcr4_l2 + cpcr4_act = dut.c0.iuq0.iuq_ifetch0.iuq_spr0.cpcr4_wren await RisingEdge(dut.clk_1x) @@ -112,58 +121,41 @@ async def config(dut, sim): await RisingEdge(dut.clk_1x) creditsSt.value = Release() - if sim.config.core.creditsLdStSingle: - creditsLdStSingle = Force(1) + if sim.config.core.creditsLdStSingle is not None: + v = 1 if sim.config.core.creditsLdStSingle else 0 + creditsLdStSingle.value = Force(v) sim.msg(f'A2L2: only one load OR store allowed when credits=1/1.') await RisingEdge(dut.clk_1x) creditsLdStSingle.value = Release() - await RisingEdge(dut.clk_1x) - -async def coreMonitor(dut, sim): - """Watch for core events. """ - - me = 'a2oMonitor' - - # errors - creditsLdErr = dut.c0.lq0.lsq.arb.ld_cred_err_q - creditsStErr = dut.c0.lq0.lsq.arb.st_cred_err_q - - # watches - iu0Comp = dut.c0.iu_lq_i0_completed - iu0CompIFAR = dut.c0.iuq0.iuq_cpl_top0.iuq_cpl0.cp2_i0_ifar - iu1Comp = dut.c0.iu_lq_i1_completed - iu1CompIFAR = dut.c0.iuq0.iuq_cpl_top0.iuq_cpl0.cp2_i1_ifar - iuCompFlushIFAR = dut.c0.cp_t0_flush_ifar - cp3NIA = dut.c0.iuq0.iuq_cpl_top0.iuq_cpl0.iuq_cpl_ctrl.cp3_nia_q # nia after last cycle's completions - - # queue depths, etc. - - errors = [ - {'name': 'Load Credits', 'sig': creditsLdErr}, - {'name': 'Store Credits', 'sig': creditsStErr}, - ] - - done = False - - while not done: - + #wtf make a function - needs mask,thread + if sim.config.core.lsDataForward is not None: + v = 1 if sim.config.core.lsDataForward else 0 + sim.msg(f'LSUCR0 = {hex(lsucr0_q.value), 8}') + sim.msg(f'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'LSUCR0 = {hex(lsucr0_q.value), 8}') + + if sim.config.core.cpcr4_sq_cnt is not None: + v = sim.config.core.cpcr4_sq_cnt + sim.msg(f'CPCR4 = {hex(cpcr4_q[0], 8)}') + sim.msg(f'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'CPCR4 = {hex(cpcr4_q[0], 8)}') - for i in range(len(errors)): - assert errors[i]['sig'].value == 0, f'{me} Error: {errors[i]["name"]}' - - comp = '' - if iu0Comp.value == 1: - comp = f'0:{int(iu0CompIFAR.value.binstr + "00", 2):06X} ' - - if iu1Comp.value == 1: - comp = f'{comp}1:{int(iu1CompIFAR.value.binstr + "00", 2):06X} ' - - if comp != '': - comp = f'{comp}{int(iuCompFlushIFAR.value.binstr + "00", 2):016X}' - sim.msg(f'C0: CP {comp}') - + await RisingEdge(dut.clk_1x) # trilib/tri.vh:`define NCLK_WIDTH 6 // 0 1xClk, 1 Reset, 2 2xClk, 3 4xClk, 4 Even .5xClk, 5 Odd .5xClk async def genReset(dut, sim): @@ -183,6 +175,7 @@ async def genReset(dut, sim): dut._log.info(f'[{sim.cycle:08d}] Releasing reset.') dut.nclk[1].value = 0 done = True + sim.resetDone = True async def genClocks(dut, sim): """Generate 1x, 2x, 4x clock pulses, depending on parms. """ @@ -237,15 +230,22 @@ async def tb(dut): sim = Sim(dut) sim.mem = Memory(sim) - sim.maxCycles = 2000 + sim.maxCycles = 9000 + # original fpga design needed 4 cred, no fwd (set in logic currently) + #sim.config.core.creditsSt = 32 + #sim.config.core.lsDataForward = 0 # disable=1 + #sim.config.core.cpcr4_sq_cnt = 0 # default=6 ''' + # rom sim.memFiles = ['../mem/boot.bin.hex'] #wtf cmdline parm for i in range(len(sim.memFiles)): #wtf el should be object with name, format, etc. sim.mem.loadFile(sim.memFiles[i]) ''' + ''' + # rom+test; should end at 700 sim.memFiles = [ { 'addr': 0x00000000, @@ -255,7 +255,26 @@ async def tb(dut): 'addr': 0x10000000, 'file' : '../mem/test1/test.init' } - ] + ] + ''' + ''' + # rom+bios; should end at 7FC + sim.memFiles = [ + { + 'addr': 0x00000000, + 'file' : '../mem/test2/rom.init' + } + ] + ''' + + + # rom+bios+arcitst + sim.memFiles = [ + { + 'addr': 0x00000000, + 'file' : '../mem/test3/rom.init' + } + ] for i in range(len(sim.memFiles)): #wtf el should be object with name, format, etc. sim.mem.loadFile(sim.memFiles[i]['file'], addr=sim.memFiles[i]['addr']) @@ -274,10 +293,12 @@ async def tb(dut): # start interfaces await cocotb.start(scom(dut, sim)) - #wtf don't have to instantiate A2L2 first? - #await cocotb.start(A2L2Driver(dut, sim)) - #await cocotb.start(A2L2Checker(dut, sim)) - #await cocotb.start(A2L2Monitor(dut, sim)) + sim.a2o = A2OCore(sim) + sim.a2o.traceFacUpdates = True + await cocotb.start(A2O.driver(dut, sim)) + await cocotb.start(A2O.checker(dut, sim)) + await cocotb.start(A2O.monitor(dut, sim)) + await cocotb.start(A2L2.driver(dut, sim)) await cocotb.start(A2L2.checker(dut, sim)) await cocotb.start(A2L2.monitor(dut, sim)) @@ -291,7 +312,7 @@ async def tb(dut): await config(dut, sim) # monitor stuff - await cocotb.start(coreMonitor(dut, sim)) + #await cocotb.start(coreMonitor(dut, sim)) # release thread(s) dut.an_ac_pm_thread_stop.value = 0