From: Cesar Strauss Date: Thu, 31 Dec 2020 10:42:27 +0000 (+0000) Subject: Remove previous version of the CompUnit parallel unit test X-Git-Tag: 24jan2021_ls180~58 X-Git-Url: https://git.libre-soc.org/?p=soc.git;a=commitdiff_plain;h=fc531a8d2b914cdef3e1283954b6432f501d1667;ds=sidebyside Remove previous version of the CompUnit parallel unit test It was too detailed, modeling properties which are better checked by formal verification. Other than that, the new version has reached feature parity, so the old code can finally be removed. --- diff --git a/src/soc/experiment/test/test_compalu_multi.py b/src/soc/experiment/test/test_compalu_multi.py index 5624b56c..98ffcc3e 100644 --- a/src/soc/experiment/test/test_compalu_multi.py +++ b/src/soc/experiment/test/test_compalu_multi.py @@ -549,216 +549,6 @@ def test_compunit(): sim.run() -class CompUnitParallelTest: - def __init__(self, dut): - self.dut = dut - - # Operation cycle should not take longer than this: - self.MAX_BUSY_WAIT = 50 - - # Minimum duration in which issue_i will be kept inactive, - # during which busy_o must remain low. - self.MIN_BUSY_LOW = 5 - - # Number of cycles to stall until the assertion of go. - # One value, for each port. Can be zero, for no delay. - self.RD_GO_DELAY = [0, 3] - - # store common data for the input operation of the processes - # input operation: - self.op = 0 - self.inv_a = self.zero_a = 0 - self.imm = self.imm_ok = 0 - self.imm_control = (0, 0) - self.rdmaskn = (0, 0) - # input data: - self.operands = (0, 0) - - # Indicates completion of the sub-processes - self.rd_complete = [False, False] - - def driver(self): - print("Begin parallel test.") - yield from self.operation(5, 2, MicrOp.OP_ADD) - - def operation(self, a, b, op, inv_a=0, imm=0, imm_ok=0, zero_a=0, - rdmaskn=(0, 0)): - # store data for the operation - self.operands = (a, b) - self.op = op - self.inv_a = inv_a - self.imm = imm - self.imm_ok = imm_ok - self.zero_a = zero_a - self.imm_control = (zero_a, imm_ok) - self.rdmaskn = rdmaskn - - # Initialize completion flags - self.rd_complete = [False, False] - - # trigger operation cycle - yield from self.issue() - - # check that the sub-processes completed, before the busy_o cycle ended - for completion in self.rd_complete: - assert completion - - def issue(self): - # issue_i starts inactive - yield self.dut.issue_i.eq(0) - - for n in range(self.MIN_BUSY_LOW): - yield - # busy_o must remain inactive. It cannot rise on its own. - busy_o = yield self.dut.busy_o - assert not busy_o - - # activate issue_i to begin the operation cycle - yield self.dut.issue_i.eq(1) - - # at the same time, present the operation - yield self.dut.oper_i.insn_type.eq(self.op) - yield self.dut.oper_i.invert_in.eq(self.inv_a) - yield self.dut.oper_i.imm_data.data.eq(self.imm) - yield self.dut.oper_i.imm_data.ok.eq(self.imm_ok) - yield self.dut.oper_i.zero_a.eq(self.zero_a) - rdmaskn = self.rdmaskn[0] | (self.rdmaskn[1] << 1) - yield self.dut.rdmaskn.eq(rdmaskn) - - # give one cycle for the CompUnit to latch the data - yield - - # busy_o must keep being low in this cycle, because issue_i was - # low on the previous cycle. - # It cannot rise on its own. - # Also, busy_o and issue_i must never be active at the same time, ever. - busy_o = yield self.dut.busy_o - assert not busy_o - - # Lower issue_i - yield self.dut.issue_i.eq(0) - - # deactivate inputs along with issue_i, so we can be sure the data - # was latched at the correct cycle - # note: rdmaskn must be held, while busy_o is active - # TODO: deactivate rdmaskn when the busy_o cycle ends - yield self.dut.oper_i.insn_type.eq(0) - yield self.dut.oper_i.invert_in.eq(0) - yield self.dut.oper_i.imm_data.data.eq(0) - yield self.dut.oper_i.imm_data.ok.eq(0) - yield self.dut.oper_i.zero_a.eq(0) - yield - - # wait for busy_o to lower - # timeout after self.MAX_BUSY_WAIT cycles - for n in range(self.MAX_BUSY_WAIT): - # sample busy_o in the current cycle - busy_o = yield self.dut.busy_o - if not busy_o: - # operation cycle ends when busy_o becomes inactive - break - yield - - # if busy_o is still active, a timeout has occurred - # TODO: Uncomment this, once the test is complete: - # assert not busy_o - - if busy_o: - print("If you are reading this, " - "it's because the above test failed, as expected,\n" - "with a timeout. It must pass, once the test is complete.") - return - - print("If you are reading this, " - "it's because the above test unexpectedly passed.") - - def rd(self, rd_idx): - # wait for issue_i to rise - while True: - issue_i = yield self.dut.issue_i - if issue_i: - break - # issue_i has not risen yet, so rd must keep low - rel = yield self.dut.rd.rel_o[rd_idx] - assert not rel - yield - - # we do not want rd to rise on an immediate operand - # if it is immediate, exit the process - # likewise, if the read mask is active - # TODO: don't exit the process, monitor rd instead to ensure it - # doesn't rise on its own - if self.rdmaskn[rd_idx] or self.imm_control[rd_idx]: - self.rd_complete[rd_idx] = True - return - - # issue_i has risen. rel must rise on the next cycle - rel = yield self.dut.rd.rel_o[rd_idx] - assert not rel - - # stall for additional cycles. Check that rel doesn't fall on its own - for n in range(self.RD_GO_DELAY[rd_idx]): - yield - rel = yield self.dut.rd.rel_o[rd_idx] - assert rel - - # Before asserting "go", make sure "rel" has risen. - # The use of Settle allows "go" to be set combinatorially, - # rising on the same cycle as "rel". - yield Settle() - rel = yield self.dut.rd.rel_o[rd_idx] - assert rel - - # assert go for one cycle, passing along the operand value - yield self.dut.rd.go_i[rd_idx].eq(1) - yield self.dut.src_i[rd_idx].eq(self.operands[rd_idx]) - # check that the operand was sent to the alu - # TODO: Properly check the alu protocol - yield Settle() - alu_input = yield self.dut.get_in(rd_idx) - assert alu_input == self.operands[rd_idx] - yield - - # rel must keep high, since go was inactive in the last cycle - rel = yield self.dut.rd.rel_o[rd_idx] - assert rel - - # finish the go one-clock pulse - yield self.dut.rd.go_i[rd_idx].eq(0) - yield self.dut.src_i[rd_idx].eq(0) - yield - - # rel must have gone low in response to go being high - # on the previous cycle - rel = yield self.dut.rd.rel_o[rd_idx] - assert not rel - - self.rd_complete[rd_idx] = True - - # TODO: check that rel doesn't rise again until the end of the - # busy_o cycle - - def wr(self, wr_idx): - # monitor self.dut.wr.req[rd_idx] and sets dut.wr.go[idx] for one cycle - yield - # TODO: also when dut.wr.go is set, check the output against the - # self.expected_o and assert. use dut.get_out(wr_idx) to do so. - - def run_simulation(self, vcd_name): - m = Module() - m.submodules.cu = self.dut - sim = Simulator(m) - sim.add_clock(1e-6) - - sim.add_sync_process(wrap(self.driver())) - sim.add_sync_process(wrap(self.rd(0))) - sim.add_sync_process(wrap(self.rd(1))) - sim.add_sync_process(wrap(self.wr(0))) - sim_writer = sim.write_vcd(vcd_name) - with sim_writer: - sim.run() - - def test_compunit_regspec2_fsm(): inspec = [('INT', 'data', '0:15'), @@ -926,9 +716,6 @@ def test_compunit_regspec1(): with sim_writer: sim.run() - test = CompUnitParallelTest(dut) - test.run_simulation("test_compunit_parallel.vcd") - if __name__ == '__main__': test_compunit()