PyHCL/pyhcl/dsl/infra.py

134 lines
3.7 KiB
Python

from dataclasses import dataclass, field
from typing import Type, Union
from pyhcl.core._dynamic_ctx import DynamicContext
from pyhcl.core._emit_context import EmitterContext
from pyhcl.core._repr import CType, Node, And, Eq
from pyhcl.core._interface import BundleAccessor, VecOps
from pyhcl.dsl.cdatatype import Bool, U
from pyhcl.ir import low_ir
@dataclass(eq=False)
class Wire(BundleAccessor, VecOps, CType):
typ: Union[Type[CType], CType]
def mapToIR(self, ctx: EmitterContext):
typ = ctx.getRef(self.typ)
name = ctx.getName(self)
w = low_ir.DefWire(name, typ)
ctx.appendFinalStatement(w, self.scopeId)
ref = low_ir.Reference(name, typ)
ctx.updateRef(self, ref)
return ref
@dataclass(eq=False)
class RegInit(CType):
initValue: CType
typ: CType = field(init=False, default=None)
def __post_init__(self):
super().__post_init__()
self.scopeId = DynamicContext.currentScope()
self.typ = self.initValue
from pyhcl.core._clock_manager import Clock_manager
Clock_manager.register(id(self))
def mapToIR(self, ctx: EmitterContext):
val = ctx.getRef(self.initValue)
name = ctx.getName(self)
w = low_ir.DefRegister(name, val.typ, ctx.getClock(self), ctx.getReset(self), val)
ctx.appendFinalStatement(w, self.scopeId)
ref = low_ir.Reference(name, val.typ)
ctx.updateRef(self, ref)
return ref
@dataclass(eq=False)
class Reg(BundleAccessor, VecOps, CType):
typ: CType
def __post_init__(self):
from pyhcl.core._clock_manager import Clock_manager
Clock_manager.register(id(self))
self.scopeId = DynamicContext.currentScope()
def mapToIR(self, ctx: EmitterContext):
typ = self.typ.mapToIR(ctx)
name = ctx.getName(self)
w = low_ir.DefRegister(name, typ, ctx.getClock(self), ctx.getReset(self))
ctx.appendFinalStatement(w, self.scopeId)
ref = low_ir.Reference(name, typ)
ctx.updateRef(self, ref)
return ref
@dataclass(eq=False)
class Mux(BundleAccessor, VecOps, Node):
cond: Node
conseq: Node
alt: Node
typ: CType = field(init=False, default=None)
def __post_init__(self):
super().__post_init__()
self.typ = self.conseq.typ
def mapToIR(self, ctx: EmitterContext):
name = ctx.getName(self)
cond = ctx.getRef(self.cond)
conseq = ctx.getRef(self.conseq)
alt = ctx.getRef(self.alt)
m = low_ir.Mux(cond, conseq, alt, conseq.typ)
n = low_ir.DefNode(name, m)
ctx.appendFinalStatement(n, self.scopeId)
ref = low_ir.Reference(name, conseq.typ)
ctx.updateRef(self, ref)
return ref
def LookUpTable(node: Node, table: dict):
assert len(table) > 0
t = list(table.items())
if t[-1][0] is not ...:
raise Exception("should define a default value: { ...: default value }")
i = t[-1][1]
for n, v in t[-2::-1]:
i = Mux(n == node, v, i)
return i
@dataclass(eq=False)
class BitPat(Node):
bits: str
def __post_init__(self):
super().__post_init__()
self.typ = U.w(len(self.bits))
cmp = "".join(["1" if c == "1" else "0" for c in self.bits])
mask = "".join(["0" if c == "?" else "1" for c in self.bits])
self.cmp = self.typ(int(cmp, 2))
self.mask = self.typ(int(mask, 2))
def eqFor(self, that):
if isinstance(that, BitPat):
return Bool(True) if self.bits == that.bits else Bool(False)
else:
a = And(that, self.mask)
a.scopeId = self.scopeId
b = Eq(a, self.cmp)
b.scopeId = self.scopeId
return b