-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial commit for generator exercise
- Loading branch information
Rajsekhar Setaluri
committed
Nov 8, 2019
1 parent
e059d4c
commit 2c4b9af
Showing
7 changed files
with
335 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
rajsekhar@rajsekhar-mbp.66129 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
import abc | ||
import collections | ||
import dataclasses | ||
import functools | ||
import operator | ||
import magma as m | ||
import mantle | ||
|
||
|
||
class IO: | ||
def __init__(self, **kwargs): | ||
self.interface = {} | ||
for k, v in kwargs.items(): | ||
port = v.flip()() | ||
self.interface[k] = type(port) | ||
setattr(self, k, port) | ||
|
||
def __repr__(self): | ||
return repr(self.interface) | ||
|
||
|
||
class CircuitMeta(type): | ||
def __new__(metacls, name, bases, namespace): | ||
namespace.setdefault("name", name) | ||
return super().__new__(metacls, name, bases, namespace) | ||
|
||
|
||
class Circuit(metaclass=CircuitMeta): | ||
pass | ||
|
||
|
||
class Generator1Meta(abc.ABCMeta): | ||
def __new__(metacls, name, bases, namespace): | ||
cls = super().__new__(metacls, name, bases, namespace) | ||
return dataclasses.dataclass(cls) | ||
|
||
|
||
class Generator1(metaclass=Generator1Meta): | ||
@abc.abstractmethod | ||
def generate(self): | ||
raise NotImplementedError() | ||
|
||
|
||
class Generator2Meta(abc.ABCMeta): | ||
def __new__(metacls, name, bases, namespace): | ||
cls = super().__new__(metacls, name, bases, namespace) | ||
return dataclasses.dataclass(cls) | ||
|
||
|
||
class Generator2(metaclass=Generator2Meta): | ||
@abc.abstractmethod | ||
def elaborate(self): | ||
raise NotImplementedError() | ||
|
||
def __post_init__(self): | ||
self.elaborate() | ||
if not hasattr(self, "IO"): | ||
raise Exception("Must set IO") | ||
|
||
|
||
class Optional: | ||
def __init__(self, param, typ): | ||
self.param = param | ||
self.typ = typ | ||
|
||
|
||
class IOTemplate: | ||
def __init__(self, **kwargs): | ||
self.ports = kwargs | ||
|
||
|
||
class Symbolic: | ||
def __init__(self, name, typ): | ||
self.name = name | ||
self.typ = typ | ||
|
||
|
||
class CustomNamespace(collections.UserDict): | ||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.___annotations = None | ||
|
||
def __setitem__(self, key, value): | ||
if key is "__annotations__": | ||
value = collections.UserDict() | ||
self.___annotations = value | ||
super().__setitem__(key, value) | ||
|
||
def __getitem__(self, key): | ||
if not self.___annotations or key not in self.___annotations: | ||
return super().__getitem__(key) | ||
return Symbolic(key, self.___annotations[key]) | ||
|
||
|
||
def elaborate_type(value, params): | ||
if isinstance(value, Symbolic): | ||
return getattr(params, value.name) | ||
if isinstance(value, Optional): | ||
option = elaborate_type(value.param, params) | ||
if not option: | ||
return None | ||
return elaborate_type(value.typ, params) | ||
# hacky... | ||
if isinstance(value, m.UIntKind): | ||
if not isinstance(value.N, Symbolic): | ||
return value | ||
N = elaborate_type(value.N, params) | ||
return m.UInt[N] | ||
if isinstance(value, m.BitKind): | ||
return value | ||
raise NotImplementedError(value, params) | ||
|
||
|
||
class Generator3Meta(abc.ABCMeta): | ||
def __new__(metacls, name, bases, namespace): | ||
namespace = dict(namespace) | ||
cls = super().__new__(metacls, name, bases, namespace) | ||
return dataclasses.dataclass(cls) | ||
|
||
def __call__(cls, *args, **kwargs): | ||
return super().__call__(*args, **kwargs) | ||
|
||
@classmethod | ||
def __prepare__(metacls, name, bases, **kwargs): | ||
return CustomNamespace() | ||
|
||
|
||
class Generator3(metaclass=Generator3Meta): | ||
def interface(self): | ||
ports = {} | ||
for k, v in self.template.ports.items(): | ||
typ = elaborate_type(v, self) | ||
if typ is not None: | ||
ports[k] = typ | ||
return IO(**ports) | ||
|
||
@abc.abstractmethod | ||
def elaborate(self): | ||
raise NotImplementedError() | ||
|
||
def __post_init__(self): | ||
self.elaborate() | ||
if not hasattr(self, "IO"): | ||
raise Exception("Must set IO") | ||
|
||
|
||
m.IO = IO | ||
m.Circuit = Circuit | ||
m.Optional = Optional | ||
m.IOTemplate = IOTemplate | ||
m.Generator1 = Generator1 | ||
m.Generator2 = Generator2 | ||
m.Generator3 = Generator3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import magma as m | ||
import common | ||
|
||
|
||
def generate_add(bits, has_ce): | ||
ports = dict(I0=m.In(m.UInt[bits]), | ||
I1=m.In(m.UInt[bits]), | ||
O=m.Out(m.UInt[bits])) | ||
if has_ce: | ||
ports.update(dict(CE=m.In(m.Bit))) | ||
|
||
class _Add(m.Circuit): | ||
name = f"Add_{bits}_{has_ce}" | ||
IO = m.IO(**ports) | ||
|
||
out = IO.I0 + IO.I1 | ||
if has_ce: | ||
out += m.zext(m.uint(IO.CE), bits - 1) | ||
m.wire(out, IO.O) | ||
|
||
return _Add | ||
|
||
|
||
Add16 = generate_add(16, False) | ||
Add8_CE = generate_add(8, True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import magma as m | ||
import common | ||
|
||
class Add(m.Generator2): | ||
bits: int | ||
has_ce: bool | ||
|
||
def elaborate(self): | ||
ports = dict(I0=m.In(m.UInt[self.bits]), | ||
I1=m.In(m.UInt[self.bits]), | ||
O=m.Out(m.UInt[self.bits])) | ||
if self.has_ce: | ||
ports.update(dict(CE=m.In(m.Bit))) | ||
|
||
self.name = f"Add_{self.bits}_{self.has_ce}" | ||
self.IO = m.IO(**ports) | ||
|
||
out = self.IO.I0 + self.IO.I1 | ||
if self.has_ce: | ||
out += m.zext(m.uint(self.IO.CE), self.bits - 1) | ||
m.wire(out, self.IO.O) | ||
|
||
|
||
Add16 = Add(16, False) | ||
Add8_CE = Add(8, True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import magma as m | ||
import common | ||
|
||
|
||
class Add(m.Generator3): | ||
bits: int | ||
has_ce: bool | ||
|
||
template = m.IOTemplate( | ||
I0=m.In(m.UInt[bits]), | ||
I1=m.In(m.UInt[bits]), | ||
O=m.Out(m.UInt[bits]), | ||
CE=m.Optional(has_ce, m.In(m.Bit)) | ||
) | ||
|
||
def elaborate(self): | ||
self.name = f"Add_{self.bits}_{self.has_ce}" | ||
self.IO = self.interface() | ||
|
||
out = self.IO.I0 + self.IO.I1 | ||
if self.has_ce: | ||
out += m.zext(m.uint(self.IO.CE), self.bits - 1) | ||
m.wire(out, self.IO.O) | ||
|
||
|
||
Add16 = Add(16, False) | ||
Add8_CE = Add(8, True) | ||
|
||
|
||
# Want to be able to do this! | ||
# x = m.UInt[24]() | ||
# y = m.UInt[24]() | ||
# out = Add(x, y) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import magma as m | ||
import common | ||
|
||
|
||
class Add(m.Generator1): | ||
bits: int | ||
has_ce: bool | ||
|
||
def generate(self): | ||
ports = dict(I0=m.In(m.UInt[self.bits]), | ||
I1=m.In(m.UInt[self.bits]), | ||
O=m.Out(m.UInt[self.bits])) | ||
if self.has_ce: | ||
ports.update(dict(CE=m.In(m.Bit))) | ||
|
||
class _Add(m.Circuit): | ||
name = f"Add_{self.bits}_{self.has_ce}" | ||
IO = m.IO(**ports) | ||
|
||
out = IO.I0 + IO.I1 | ||
if self.has_ce: | ||
out += m.zext(m.uint(IO.CE), self.bits - 1) | ||
m.wire(out, IO.O) | ||
|
||
return _Add | ||
|
||
|
||
Add16Gen = Add(16, False) | ||
Add16 = Add16Gen.generate() | ||
Add8_CEGen = Add(8, True) | ||
Add8_CE = Add8_CEGen.generate() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import magma as m | ||
import mantle | ||
|
||
|
||
|
||
|
||
## Current version | ||
## End Current version ## | ||
|
||
|
||
## Trivial class version | ||
## End Trivial class version ## | ||
|
||
|
||
## Slightly better class version | ||
class Add(m.Generator2): | ||
bits: int | ||
has_ce: bool | ||
|
||
def elaborate(self): | ||
ports = dict(I0=m.In(m.UInt[self.bits]), | ||
I1=m.In(m.UInt[self.bits]), | ||
O=m.Out(m.UInt[self.bits])) | ||
if self.has_ce: | ||
ports.update(dict(CE=m.In(m.Bit))) | ||
|
||
self.name = f"Add_{self.bits}_{self.has_ce}" | ||
self.IO = IO(**ports) | ||
|
||
out = self.IO.I0 + self.IO.I1 | ||
if self.has_ce: | ||
out += m.zext(m.uint(self.IO.CE), self.bits - 1) | ||
m.wire(out, self.IO.O) | ||
|
||
Add16 = Add(16, False) | ||
Add8_CE = Add(8, True) | ||
## End Slightly better class ## | ||
|
||
|
||
## Another variation version ## | ||
class Add(m.Generator3): | ||
bits: int | ||
has_ce: bool | ||
|
||
template = m.IOTemplate( | ||
I0=m.In(m.UInt[bits]), | ||
I1=m.In(m.UInt[bits]), | ||
O=m.Out(m.UInt[bits]), | ||
CE=m.Optional(has_ce, m.In(m.Bit)) | ||
) | ||
|
||
def elaborate(self): | ||
self.name = f"Add_{self.bits}_{self.has_ce}" | ||
self.IO = self.interface() | ||
|
||
out = self.IO.I0 + self.IO.I1 | ||
if self.has_ce: | ||
out += m.zext(m.uint(self.IO.CE), self.bits - 1) | ||
m.wire(out, self.IO.O) | ||
|
||
Add16 = Add(16, False) | ||
Add8_CE = Add(8, True) | ||
|
||
x = m.UInt[24]() | ||
y = m.UInt[24]() | ||
#out = Add(x, y) | ||
## End Another variation version ## |