[PyCDE] Make Values easier to name

This commit is contained in:
John Demme 2021-09-08 00:38:19 -07:00
parent bb5e79b041
commit 3634b6c6e1
4 changed files with 61 additions and 13 deletions

View File

@ -216,14 +216,14 @@ def _module_base(cls, extern: bool, params={}):
raise ConnectionError(
"`no_connect` is only valid on extern module ports")
else:
value = hw.ConstantOp.create(types.i1, 0).result
value = Value.get(hw.ConstantOp.create(types.i1, 0).result)
else:
value = obj_to_value(input, type)
else:
backedge = BackedgeBuilder.current().create(type, name, self, loc=loc)
self.backedges[idx] = backedge
value = backedge.result
input_ports_values.append(value)
value = Value.get(backedge.result)
input_ports_values.append(value.value)
# Set up the op attributes.
attributes: dict[str:mlir.ir.Attribute] = {}
@ -465,7 +465,7 @@ class _Generate:
unconnected_ports.append(name)
outputs.append(None)
else:
val = obj_to_value(gen_ret[name], port_type)
val = obj_to_value(gen_ret[name], port_type).value
outputs.append(val)
gen_ret.pop(name)
if len(unconnected_ports) > 0:

View File

@ -18,7 +18,7 @@ class _Types:
self.registered_aliases = OrderedDict()
def __getattr__(self, name: str) -> mlir.ir.Type:
return mlir.ir.Type.parse(name)
return self.wrap(mlir.ir.Type.parse(name))
def int(self, width: int, name: str = None):
return self.wrap(mlir.ir.IntegerType.get_signless(width), name)
@ -111,9 +111,12 @@ def PyCDEType(type):
else:
return self
def create(self, obj):
def create(self, obj, name: str = None):
"""Create a Value of this type from a python object."""
from .support import obj_to_value
return obj_to_value(obj, self, self)
v = obj_to_value(obj, self, self)
if name is not None:
v.name = name
return v
return _PyCDEType(type)

View File

@ -63,6 +63,7 @@ class OpOperandConnect(support.OpOperand):
def obj_to_value(x, type, result_type=None):
"""Convert a python object to a CIRCT value, given the CIRCT type."""
assert x is not None
from .value import Value
type = support.type_to_pytype(type)
if isinstance(type, hw.TypeAliasType):
@ -72,19 +73,19 @@ def obj_to_value(x, type, result_type=None):
result_type = type
else:
result_type = support.type_to_pytype(result_type)
assert isinstance(result_type, hw.TypeAliasType)
assert isinstance(result_type, hw.TypeAliasType) or result_type == type
val = support.get_value(x)
# If x is already a valid value, just return it.
if val is not None:
if val.type != result_type:
raise ValueError(f"Expected {result_type}, got {val.type}")
return val
return Value.get(val)
if isinstance(x, int):
if not isinstance(type, ir.IntegerType):
raise ValueError(f"Int can only be converted to hw int, not '{type}'")
return hw.ConstantOp.create(type, x).result
return Value.get(hw.ConstantOp.create(type, x).result)
if isinstance(x, list):
if not isinstance(type, hw.ArrayType):
@ -95,7 +96,7 @@ def obj_to_value(x, type, result_type=None):
f"{len(x)} vs {type.size}")
list_of_vals = list(map(lambda x: obj_to_value(x, elemty), x))
# CIRCT's ArrayCreate op takes the array in reverse order.
return hw.ArrayCreateOp.create(reversed(list_of_vals)).result
return Value.get(hw.ArrayCreateOp.create(reversed(list_of_vals)).result)
if isinstance(x, dict):
if not isinstance(type, hw.StructType):
@ -109,8 +110,9 @@ def obj_to_value(x, type, result_type=None):
x.pop(fname)
if len(x) > 0:
raise ValueError(f"Extra fields specified: {x}")
return hw.StructCreateOp.create(elem_name_values,
result_type=result_type).result
return Value.get(
hw.StructCreateOp.create(elem_name_values,
result_type=result_type).result)
raise ValueError(f"Unable to map object '{type(x)}' to MLIR Value")

View File

@ -0,0 +1,43 @@
# RUN: %PYTHON% %s | FileCheck %s
from pycde import (Output, Input, module, generator, types, dim, System)
@module
class WireNames:
clk = Input(types.i1)
sel = Input(types.i2)
data_in = Input(dim(32, 3))
a = Output(types.i32)
b = Output(types.i32)
@generator
def build(mod):
foo = mod.data_in[0]
foo.name = "foo"
arr_data = dim(32, 4).create([1, 2, 3, 4], "arr_data")
return {
'a': foo.reg(mod.clk).reg(mod.clk),
'b': arr_data[mod.sel],
}
sys = System([WireNames])
sys.generate()
sys.print()
# CHECK: hw.module @pycde.WireNames(%clk: i1, %data_in: !hw.array<3xi32>, %sel: i2) -> (%a: i32, %b: i32) {
# CHECK: %c0_i2 = hw.constant 0 : i2
# CHECK: %0 = hw.array_get %data_in[%c0_i2] {name = "foo"} : !hw.array<3xi32>
# CHECK: %c1_i32 = hw.constant 1 : i32
# CHECK: %c2_i32 = hw.constant 2 : i32
# CHECK: %c3_i32 = hw.constant 3 : i32
# CHECK: %c4_i32 = hw.constant 4 : i32
# CHECK: %1 = hw.array_create %c4_i32, %c3_i32, %c2_i32, %c1_i32 : i32
# CHECK: %2 = seq.compreg %0, %clk {name = "foo__reg1"} : i32
# CHECK: %3 = seq.compreg %2, %clk {name = "foo__reg2"} : i32
# CHECK: %4 = hw.array_get %1[%sel] : !hw.array<4xi32>
# CHECK: hw.output %3, %4 : i32, i32
# CHECK: }
sys.print_verilog()