summaryrefslogtreecommitdiff
path: root/hdl/utils.py
blob: 249167a2d9b86a213953b07a977287fc915dea24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import sys
from typing import Callable
from amaranth import *
from amaranth import Elaboratable
from amaranth.back import verilog, cxxrtl

def cmd(hdl, tb:Callable):
    '''
    Very simple command line interface
    Accepts a Elaboratable class and a testbench function
    The elaboratable class must have a ports attribute that is a dict of in and out ports {'in': [Signals()], 'out': [Signals()]}
    The testbench function should only expect one argument: path to save .vcd file
    '''

    if len(sys.argv) <= 1:
        exit()

    if sys.argv[1] == "sim":
        tb(sys.argv[0].replace('.py', '.vcd'))
        exit()

    if sys.argv[1] == "v":
        out = verilog.convert(hdl, ports=hdl.ports['in'] + hdl.ports['out'])
        with open(sys.argv[0].replace('.py', '.v'), 'w') as f:
            f.write(out)
    
    elif sys.argv[1] == "cc":
        out = cxxrtl.convert(hdl, ports=hdl.ports['in'] + hdl.ports['out'])
        with open(sys.argv[0].replace('.py', '.cc'), 'w') as f:
            f.write(out)

class DubbleBuff(Elaboratable):
    '''
    This module wraps another modules input and output with a buffer
    This is usefull for doing timeing analysis on combinational logic 

    An instance of a module should be passed, not the module itself
    '''
    def __init__(self, sub_module: Elaboratable):
        assert sub_module.ports is not None, 'sub_module must have ports'

        self.sub_module = sub_module
        ports_in = [Signal(port.width, name=port.name + '_inbuf') for port in sub_module.ports['in']]
        ports_out = [Signal(port.width, name=port.name + '_outbuf') for port in sub_module.ports['out']]
        self.ports = {'in': ports_in, 'out': ports_out}

    def elaborate(self, platform):
        m = Module()
        m.submodules.sub = self.sub_module

        for i in range(len(self.ports['in'])):
            m.d.sync += self.sub_module.ports['in'][i].eq(self.ports['in'][i])

        for i in range(len(self.ports['out'])):
            m.d.sync += self.ports['out'][i].eq(self.sub_module.ports['out'][i])

        return m