Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
Signed-off-by: gatecat <gatecat@ds0.me>
  • Loading branch information
gatecat committed Aug 25, 2023
1 parent e08471d commit 0334dcd
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 9 deletions.
7 changes: 0 additions & 7 deletions himbaechel/chipdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,6 @@ NPNR_PACKED_STRUCT(struct TimingValue {
int32_t slow_max;
});

NPNR_PACKED_STRUCT(struct BelPinTimingPOD {
TimingValue in_cap;
TimingValue drive_res;
TimingValue delay;
});

NPNR_PACKED_STRUCT(struct PipTimingPOD {
TimingValue int_delay;
TimingValue in_cap;
Expand Down Expand Up @@ -198,7 +192,6 @@ NPNR_PACKED_STRUCT(struct CellTimingPOD {

NPNR_PACKED_STRUCT(struct SpeedGradePOD {
int32_t name;
RelSlice<BelPinTimingPOD> bel_pin_classes;
RelSlice<PipTimingPOD> pip_classes;
RelSlice<NodeTimingPOD> node_classes;
RelSlice<CellTimingPOD> cell_types;
Expand Down
121 changes: 119 additions & 2 deletions himbaechel/himbaechel_dbgen/chip.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def create_wire(self, name: str, type: str=""):
self._wire2idx[wire.name] = wire.index
self.wires.append(wire)
return wire
def create_pip(self, src: str, dst: str):
def create_pip(self, src: str, dst: str, timing_class: str=""):
# Create a pip between two tile wires in the tile type. Both wires should exist already.
src_idx = self._wire2idx[self.strs.id(src)]
dst_idx = self._wire2idx[self.strs.id(dst)]
Expand Down Expand Up @@ -291,6 +291,8 @@ def serialise(self, context: str, bba: BBAWriter):
@dataclass
class NodeShape(BBAStruct):
wires: list[TileWireRef] = field(default_factory=list)
timing_index: int = -1

def key(self):
m = hashlib.sha1()
for wire in self.wires:
Expand All @@ -307,7 +309,7 @@ def serialise_lists(self, context: str, bba: BBAWriter):
bba.u16(0) # alignment
def serialise(self, context: str, bba: BBAWriter):
bba.slice(f"{context}_wires", len(self.wires))
bba.u32(-1) # timing index (not yet used)
bba.u32(timing_index) # timing index (not yet used)

MODE_TILE_WIRE = 0x7000
MODE_IS_ROOT = 0x7001
Expand Down Expand Up @@ -371,6 +373,121 @@ def serialise(self, context: str, bba: BBAWriter):
bba.ref(f"{context}_extra_data")
else:
bba.u32(0)

class TimingValue(BBAStruct):
def __init__(self, fast_min=0, fast_max=None, slow_min=None, slow_max=None):
self.fast_min = fast_min
self.fast_max = fast_max or fast_min
self.slow_min = slow_min or self.fast_min
self.slow_max = slow_max or self.fast_max

def serialise_lists(self, context: str, bba: BBAWriter):
pass
def serialise(self, context: str, bba: BBAWriter):
bba.u32(self.fast_min)
bba.u32(self.fast_max)
bba.u32(self.slow_min)
bba.u32(self.slow_max)

@dataclass
class PipTiming(BBAStruct):
int_delay: TimingValue = field(default_factory=TimingValue) # internal fixed delay in ps
in_cap: TimingValue = field(default_factory=TimingValue) # internal capacitance in notional femtofarads
out_res: TimingValue = field(default_factory=TimingValue) # drive/output resistance in notional microohms
flags: int = 0 # is_buffered etc

@dataclass
class NodeTiming(BBAStruct):
res: TimingValue = field(default_factory=TimingValue) # wire resistance in notional microohms
cap: TimingValue = field(default_factory=TimingValue) # wire capacitance in notional femtofarads
delay: TimingValue = field(default_factory=TimingValue) # fixed wire delay in ps

@dataclass
class ClockEdge(Enum):
RISING = 0
FALLING = 1

@dataclass
class CellPinRegArc(BBAStruct):
clock: int
edge: ClockEdge
setup: TimingValue = field(default_factory=TimingValue) # setup time in ps
hold: TimingValue = field(default_factory=TimingValue) # hold time in ps
clk_q: TimingValue = field(default_factory=TimingValue) # clock to output time in ps

@dataclass
class CellPinCombArc(BBAStruct):
from_pin: int
delay: TimingValue = field(default_factory=TimingValue)

@dataclass
class CellPinTiming(BBAStruct):
pin: int
comb_arcs: list[CellPinCombArc] = field(default_factory=list) # sorted by from_pin ID index
reg_arcs: list[CellPinCombArc] = field(default_factory=list) # sorted by clock ID index

@dataclass
class CellTiming(BBAStruct):
cell_type: int
variant: int = 0
pins: list[CellPinTiming] = field(default_factory=list) # sorted by pin ID index

@dataclass
class SpeedGrade(BBAStruct):
name: int
pip_classes: list[PipTiming|None] = field(default_factory=list)
node_classes: list[NodeTiming|None] = field(default_factory=list)
cell_types: list[CellTiming] = field(default_factory=list) # sorted by (cell_type, variant) ID tuple

class TimingPool:
def __init__(self, strs: StringPool, speed_grades: list):
self.strs = strs
self.speed_grades = [SpeedGrade(name=strs.id(g)) for g in speed_grades]
self.speed_grade_idx = {g: i for i, g in enumerate(speed_grades)}
self.pip_classes = {"": -1}
self.node_classes = {"": -1}

def pip_class_idx(self, name: str):
if name in self.pip_classes:
return self.pip_classes[name]
else:
idx = len(self.pip_classes)
self.pip_classes[name] = idx
return idx

def node_class_idx(self, name: str):
if name in self.node_classes:
return self.node_classes[name]
else:
idx = len(self.node_classes)
self.node_classes[name] = idx
return idx

def set_pip_class(self, grade: str, name: str, delay: TimingValue,
in_cap: Optional[TimingValue]=None, out_res: Optional[TimingValue]=None,
is_buffered=True):
idx = self.pip_class_idx(name)
grade = self.speed_grades[self.speed_grade_idx[grade]]
if idx >= len(grade.pip_classes):
grade.pip_classes += [None for i in range(idx - len(grade.pip_classes))]
assert grade.pip_classes[idx] is None, f"attempting to set pip class {name} to speed grade {grade} twice"
grade.pip_classes[idx] = PipTiming(int_delay=delay, in_cap=in_cap, out_res=out_res, flags=(1 if is_buffered else 0))

def set_bel_pin_class(self, grade: str, name: str, delay: TimingValue,
in_cap: Optional[TimingValue]=None, out_res: Optional[TimingValue]=None):
# bel pin classes are shared with pip classes, but this alias adds a bit of extra clarity
set_pip_class(self, grade, name, delay, in_cap, out_res, is_buffered=True)

def set_node_class(self, grade: str, name: str, delay: TimingValue,
res: Optional[TimingValue]=None, cap: Optional[TimingValue]=None):
idx = self.node_class_idx(name)
grade = self.speed_grades[self.speed_grade_idx[grade]]
if idx >= len(grade.node_classes):
grade.node_classes += [None for i in range(idx - len(grade.node_classes))]
assert grade.node_classes[idx] is None, f"attempting to set node class {name} to speed grade {grade} twice"
grade.node_classes[idx] = NodeTiming(delay=delay, res=res, cap=cap)


class Chip:
def __init__(self, uarch: str, name: str, width: int, height: int):
self.strs = StringPool()
Expand Down

0 comments on commit 0334dcd

Please sign in to comment.