Browse Source

fix sim scheduler for circuits with POs that are also used internally

devel
stefan 5 days ago
parent
commit
ed9b5c6cd6
  1. 13
      src/kyupy/sim.py
  2. 12
      tests/test_logic_sim.py

13
src/kyupy/sim.py

@ -189,7 +189,7 @@ class SimOps:
levels = [] levels = []
ppio2idx = dict((n, i) for i, n in enumerate(circuit.s_nodes(KYUPY))) ppio2idx = dict((n, i) for i, n in enumerate(circuit.s_nodes(KYUPY)))
root_nodes = set([n for n in circuit.s_nodes(KYUPY) if len(n.ins) > 0] + [n for n in circuit.nodes if len(n.outs) == 0]) # start from POs, PPOs, and any dangling nodes root_nodes = set([n for n in circuit.nodes if len(n.outs) == 0 or KYUPY.is_dff(n.kind)]) # start from POs (that are unused by circuit itself), PPOs, and any dangling nodes
readers = np.array([1 if l.reader in root_nodes else len(l.reader.outs) for l in circuit.lines], dtype=np.int32) # for ref-counting forks readers = np.array([1 if l.reader in root_nodes else len(l.reader.outs) for l in circuit.lines], dtype=np.int32) # for ref-counting forks
level_lines = [n.ins[0] for n in sorted(root_nodes, key=lambda n: n.index) if len(n.ins) > 0 ] level_lines = [n.ins[0] for n in sorted(root_nodes, key=lambda n: n.index) if len(n.ins) > 0 ]
@ -201,10 +201,14 @@ class SimOps:
for l in level_lines: for l in level_lines:
n = l.driver n = l.driver
assert len(n.ins) <= 4, f'Too many input pins for node {n}. Map circuit to KYUPY techlib first using resolce_tlib_cells().' assert len(n.ins) <= 4, f'Too many input pins for node {n}. Map circuit to KYUPY techlib first using resolve_tlib_cells().'
in_idxs = [n.ins[x].index if len(n.ins) > x and n.ins[x] is not None else self.zero_idx for x in [0,1,2,3]] in_idxs = [n.ins[x].index if len(n.ins) > x and n.ins[x] is not None else self.zero_idx for x in [0,1,2,3]]
if n in ppio2idx: if n in ppio2idx:
if 'dff' in n.kind.lower() or in_idxs[0] == self.zero_idx:
in_idxs[0] = self.ppi_offset + ppio2idx[n] in_idxs[0] = self.ppi_offset + ppio2idx[n]
else: # this is a PO that is also used within the circuit. Treat as normal fork with ref counting. TODO: check strip_forks=True case for this.
readers[n.ins[0]] -= 1
if readers[n.ins[0]] == 0: prev_level_lines.append(n.ins[0])
if l.driver_pin == 1 and 'dff' in n.kind.lower(): # second output of DFF is inverted if l.driver_pin == 1 and 'dff' in n.kind.lower(): # second output of DFF is inverted
level_ops.append((INV1, l.index, *in_idxs, *a_ctrl[l])) level_ops.append((INV1, l.index, *in_idxs, *a_ctrl[l]))
else: else:
@ -312,6 +316,11 @@ class SimOps:
if len(n.ins) > 0: if len(n.ins) > 0:
self.c_locs[self.ppo_offset + i], self.c_caps[self.ppo_offset + i] = self.c_locs[n.ins[0]], self.c_caps[n.ins[0]] self.c_locs[self.ppo_offset + i], self.c_caps[self.ppo_offset + i] = self.c_locs[n.ins[0]], self.c_caps[n.ins[0]]
# sanity check
for oidx, io in zip(*np.nonzero(self.c_locs[self.ops[:, 1:6]] < 0)):
log.error(f'unallocated {["o0","i0","i1","i2","i3"][io]} in op {self.ops[oidx]}')
assert np.min(self.c_locs[self.ops[:, 1:6]]) >= 0, "Unallocated signal lines."
# line use information # line use information
self.line_use_start = np.full(self.c_locs_len, -1, dtype=np.int32) self.line_use_start = np.full(self.c_locs_len, -1, dtype=np.int32)
self.line_use_stop = np.full(self.c_locs_len, len(self.levels), dtype=np.int32) self.line_use_stop = np.full(self.c_locs_len, len(self.levels), dtype=np.int32)

12
tests/test_logic_sim.py

@ -20,6 +20,18 @@ def test_dangling():
sim.simulate(p) sim.simulate(p)
assert p[1,0] == logic.ONE assert p[1,0] == logic.ONE
def test_used_output():
c = bench.parse('input(i0) output(o0) output(o1) o0=BUF1(i0) o1=BUF(o0)')
sim = LogicSim2V(c)
expect = mvarray('000', '111')
actual = sim.simulate(expect.copy())
np.testing.assert_array_equal(
expect[c.io_locs('o0')],
actual[c.io_locs('o0')])
np.testing.assert_array_equal(
expect[c.io_locs('o1')],
actual[c.io_locs('o1')])
def assert_equal_shape_and_contents(actual, desired): def assert_equal_shape_and_contents(actual, desired):
desired = np.array(desired, dtype=np.uint8) desired = np.array(desired, dtype=np.uint8)
assert actual.shape == desired.shape assert actual.shape == desired.shape

Loading…
Cancel
Save