Closed cjdrake closed 9 months ago
A design is like an N-ary tree:
root
/ \
A B
/ \ / \
C D E F
The branches are modules, and the leaves are variables. The variables implement the simulation protocol: they have a "present state", and a "next state".
It is probably useful to allow multiple top-level modules.
The normal naming convention is to use dot notation. For this example, you would have:
root.A.C
root.A.D
root.B.E
root.B.F
However, we should consider using the convention for file systems:
/A/C
/A/D
/B/E
/B/F
File systems have an implicit root directory, and it's just called /
, so you don't have to give it a name like top
, root
, or something like that.
All variables in the design should have a local name, and a fully-qualified name. Python has some conventions related to qualified names, eg https://peps.python.org/pep-3155/. Review this for ideas.
Concept brainstorming:
from something import Input, Output
from seqlogic import logicvec
class Adder(Module):
a: Input[logicvec[8]]
b: Input[logicvec[8]]
ci: Input[logic]
s: Output[logicvec[8][
co: Output[logic]
v: Output[logic]
def __init__(self, param1, param2):
# Do some build step stuff
def connect(self):
# Do some connect step stuff
Follow up thoughts. Using class-level type annotations to declare either ports or variables can be very clean an intuitive, but probably won't allow more dynamic behavior. For example, why not allow ports to be optional? A parameter such as bypass_enable
can control whether certain logic needs to be instantiated.
Also, should input/output be declared at wire level, or should we attempt protocol-level? As neat as it sounds, I'm not sure any HW design paradigm that doesn't allow designer to just pass wires around willy-nilly can possibly be successful.
Branches and leaves are a good start, but we should also have the ability to create data structures within modules as well. For example, the list
and dict
data types provide a mapping from int
or str
to the next lower level of hierarchy. So I think a list
is just a type of module with an implicit naming scheme of [0]
, [1]
, ..., and dict
is similarly ['a']
, ['b']
, ...
So something like top.foo.x[0].bar.y['a'].fiz.buz
is a legal, qualified name, where x
is the name of a list
instance, and y
is the name of a dict
instance. The indices and keys provide part of the qualname
.
For list
, the immutable tuple
might be better. There's no reason to modify a list at simulation runtime.
For dict
, I'm pretty sure a frozendict
exists, but it's not commonly used, so maybe not worth the trouble.
We need a system for the following:
Design separate modules, combine them with build/connect steps, integrate with the simulation.
Related to this, we need a debug dump system. VCD is the obvious choice, but I like the idea of using an SQLite database. Keep track of the design in a separate issue when the time comes.