5 Commits
5 changed files with 57 additions and 16 deletions

No files matched your search

+1 -1
View File
@@ -1,7 +1,7 @@
version: 2 version: 2
build: build:
os: "ubuntu-20.04" os: "ubuntu-24.04"
tools: tools:
python: "3.12" python: "3.12"
jobs: jobs:
+19 -10
View File
@@ -6,7 +6,7 @@ as an intermediate representation (:class:`DefFile` object).
from collections import defaultdict from collections import defaultdict
from lark import Lark, Transformer, Tree from lark import Lark, Transformer
from kyupy import readtext from kyupy import readtext
@@ -85,6 +85,8 @@ class DefFile:
self.pins = {} self.pins = {}
self.specialnets = {} self.specialnets = {}
self.nets = {} self.nets = {}
self.design = ""
self.diearea = 0
class DefTransformer(Transformer): class DefTransformer(Transformer):
@@ -140,9 +142,11 @@ class DefTransformer(Transformer):
def comp_stmt(self, args): def comp_stmt(self, args):
name = args[0].value name = args[0].value
kind = args[1].value kind = args[1].value
point = args[2] for aidx in range(2, len(args)):
orientation = args[3].value if args[aidx] in ('PLACED', 'FIXED'):
self.def_file.components[name] = (kind, point, orientation) point = args[aidx+1]
orientation = args[aidx+2].value
self.def_file.components[name] = (kind, point, orientation)
def pins_stmt(self, args): def pins_stmt(self, args):
pin = DefPin(args[0].value) pin = DefPin(args[0].value)
@@ -207,6 +211,7 @@ GRAMMAR = r"""
| /DIEAREA/ point+ ";" | /DIEAREA/ point+ ";"
| /ROW/ ID ID NUMBER NUMBER ID do_step ";" | /ROW/ ID ID NUMBER NUMBER ID do_step ";"
| /TRACKS/ /[XY]/ NUMBER "DO" NUMBER "STEP" NUMBER "LAYER" ID ";" | /TRACKS/ /[XY]/ NUMBER "DO" NUMBER "STEP" NUMBER "LAYER" ID ";"
| /GCELLGRID/ /[XY]/ NUMBER "DO" NUMBER "STEP" NUMBER ";"
| propdef | vias | nondef | comp | pins | pinprop | spnets | nets | propdef | vias | nondef | comp | pins | pinprop | spnets | nets
propdef: "PROPERTYDEFINITIONS" propdef_stmt* "END" "PROPERTYDEFINITIONS" propdef: "PROPERTYDEFINITIONS" propdef_stmt* "END" "PROPERTYDEFINITIONS"
@@ -228,7 +233,9 @@ GRAMMAR = r"""
| "+" /VIA/ ID )* ";" | "+" /VIA/ ID )* ";"
comp: "COMPONENTS" NUMBER ";" comp_stmt* "END" "COMPONENTS" comp: "COMPONENTS" NUMBER ";" comp_stmt* "END" "COMPONENTS"
comp_stmt: "-" ID ID "+" "PLACED" point ID ";" comp_stmt: "-" ID ID ( "+" /PLACED/ point ID
| "+" /FIXED/ point ID
| "+" /SOURCE/ ID )* ";"
pins: "PINS" NUMBER ";" pins_stmt* "END" "PINS" pins: "PINS" NUMBER ";" pins_stmt* "END" "PINS"
pins_stmt: "-" ID pins_opt* ";" pins_stmt: "-" ID pins_opt* ";"
@@ -239,6 +246,8 @@ GRAMMAR = r"""
| "+" /PORT/ | "+" /PORT/
| "+" /LAYER/ ID point point | "+" /LAYER/ ID point point
| "+" /PLACED/ point ID | "+" /PLACED/ point ID
| "+" /FIXED/ point ID
pinprop: "PINPROPERTIES" NUMBER ";" pinprop_stmt* "END" "PINPROPERTIES" pinprop: "PINPROPERTIES" NUMBER ";" pinprop_stmt* "END" "PINPROPERTIES"
pinprop_stmt: "-" "PIN" ID "+" "PROPERTY" ID STRING ";" pinprop_stmt: "-" "PIN" ID "+" "PROPERTY" ID STRING ";"
@@ -266,10 +275,10 @@ GRAMMAR = r"""
wire: ID wire_opt points wire: ID wire_opt points
wire_opt: ( "TAPER" | "TAPERRULE" ID )? ("STYLE" ID)? wire_opt: ( "TAPER" | "TAPERRULE" ID )? ("STYLE" ID)?
points: point ( point | points_via )+ points: point ( point | points_via_or_rect )+
points_via: ID ORIENTATION? points_via_or_rect: ID ( ORIENTATION? | "(" (NUMBER|SIGNED_NUMBER|/\*/) (NUMBER|SIGNED_NUMBER|/\*/) (NUMBER|SIGNED_NUMBER|/\*/) (NUMBER|SIGNED_NUMBER|/\*/) ")" )
point: "(" (NUMBER|/\*/) (NUMBER|/\*/) NUMBER? ")" point: "(" (NUMBER|SIGNED_NUMBER|/\*/) (NUMBER|SIGNED_NUMBER|/\*/) NUMBER? ")"
do_step: "DO" NUMBER "BY" NUMBER "STEP" (NUMBER|SIGNED_NUMBER) (NUMBER|SIGNED_NUMBER) do_step: "DO" NUMBER "BY" NUMBER "STEP" (NUMBER|SIGNED_NUMBER) (NUMBER|SIGNED_NUMBER)
@@ -284,9 +293,9 @@ GRAMMAR = r"""
""" """
def parse(text): def parse(text) -> DefFile:
"""Parses the given ``text`` and returns a :class:`DefFile` object.""" """Parses the given ``text`` and returns a :class:`DefFile` object."""
return Lark(GRAMMAR, parser="lalr", transformer=DefTransformer()).parse(text) return Lark(GRAMMAR, parser="lalr", transformer=DefTransformer()).parse(text) # type: ignore
def load(file): def load(file):
+2 -1
View File
@@ -51,6 +51,7 @@ class LogicSim(sim.SimOps):
nbytes = cdiv(sims, 8) nbytes = cdiv(sims, 8)
self.c = np.zeros((self.c_len, self.mdim, nbytes), dtype=np.uint8) self.c = np.zeros((self.c_len, self.mdim, nbytes), dtype=np.uint8)
self.c_dirty = np.full(self.c_len, 1, dtype=np.uint8)
self.s = np.zeros((2, self.s_len, 3, nbytes), dtype=np.uint8) self.s = np.zeros((2, self.s_len, 3, nbytes), dtype=np.uint8)
"""Logic values of the sequential elements (flip-flops) and ports. """Logic values of the sequential elements (flip-flops) and ports.
@@ -97,7 +98,7 @@ class LogicSim(sim.SimOps):
t1 = self.c_locs[self.tmp2_idx] t1 = self.c_locs[self.tmp2_idx]
if self.m == 2: if self.m == 2:
if inject_cb is None: if inject_cb is None:
c_prop_2v_cpu(self.ops, self.c_locs, self.c, int(fault_line), fault_mask, int(fault_model)) c_prop_2v_cpu(self.ops, self.c_locs, self.c, self.c_dirty, int(fault_line), fault_mask, int(fault_model))
else: else:
for op, o0l, i0l, i1l, i2l, i3l in self.ops[:,:6]: for op, o0l, i0l, i1l, i2l, i3l in self.ops[:,:6]:
o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0l, i0l, i1l, i2l, i3l)] o0, i0, i1, i2, i3 = [self.c_locs[x] for x in (o0l, i0l, i1l, i2l, i3l)]
+23 -4
View File
@@ -189,10 +189,10 @@ 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 root_nodes 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 ]
# FIXME: Should probably instanciate buffers for PPOs and attach DFF clocks # FIXME: Should probably instanciate buffers for PPOs and attach DFF clocks
while len(level_lines) > 0: # traverse the circuit level-wise back towards (P)PIs while len(level_lines) > 0: # traverse the circuit level-wise back towards (P)PIs
@@ -201,10 +201,15 @@ 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:
in_idxs[0] = self.ppi_offset + ppio2idx[n] in_idxs[1] = self.zero_idx
if 'dff' in n.kind.lower() or in_idxs[0] == self.zero_idx:
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 +317,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)
@@ -346,3 +356,12 @@ class SimOps:
self.pippi_c_locs = np.concatenate([self.pi_c_locs, self.ppi_c_locs]) self.pippi_c_locs = np.concatenate([self.pi_c_locs, self.ppi_c_locs])
self.poppo_c_locs = np.concatenate([self.po_c_locs, self.ppo_c_locs]) self.poppo_c_locs = np.concatenate([self.po_c_locs, self.ppo_c_locs])
def cone_ops(self, origin_lines: set[int]):
active_lines = {l for l in origin_lines}
ops = []
for kind, out0, in0, in1, in2, in3, *params in self.ops:
if in0 in active_lines or in1 in active_lines or in2 in active_lines or in3 in active_lines or out0 in origin_lines:
ops.append((kind, out0, in0, in1, in2, in3, *params))
active_lines.add(out0)
return np.asarray(ops, dtype=np.int32)
+12
View File
@@ -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