cjdrake / seqlogic

Sequential Logic
1 stars 0 forks source link

Module system #5

Closed cjdrake closed 9 months ago

cjdrake commented 11 months ago

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.

cjdrake commented 11 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:

However, we should consider using the convention for file systems:

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.

cjdrake commented 11 months ago

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.

cjdrake commented 10 months ago

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.