# Copyright 2014-2022 Olof Kindgren <olof.kindgren@gmail.com>
# SPDX-License-Identifier: Apache-2.0
class Signal(object):
    def __init__(self, name, width=0, low=0, asc=False, vec=0):
        self.name = name
        self.width=width
        self.low = low
        self.asc = asc

    def range(self):
        if self.width > 0:
            l = self.width+self.low-1
            r = self.low
            if self.asc:
                return '['+str(r)+':'+str(l)+']'
            else:
                return '['+str(l)+':'+str(r)+']'
        return ''

class Wire(Signal):
    def write(self, width):
        return 'wire{range} {name};\n'.format(range=self.range().rjust(width), name=self.name)

class Parameter:
    def __init__(self, name, value):
        self.name  = name
        self.value = value

class Port:
    def __init__(self, name="", value=""):
        self.name = name
        self.value = value
        self.wires = []

class ModulePort(Signal):
    def __init__(self, name, dir, width=0, low=0, asc=False):
        super(ModulePort, self).__init__(name, width, low, asc)
        self.dir = dir

    def write(self, range_width=0):
        return '{dir} wire {range} {name}'.format(dir=self.dir.ljust(6), range=self.range().rjust(range_width), name=self.name)

class Instance:
    def __init__(self, module, name, parameters, ports):
        self.module = module
        self.name = name
        self.parameters = parameters
        self.ports = ports

    def write(self):
        s = self.module
        if self.parameters:
            max_len = max([len(p.name) for p in self.parameters])
            s += '\n  #('
            s += ',\n    '.join(['.' + p.name.ljust(max_len) +' (' + str(p.value) + ')' for p in self.parameters])
            s += ')\n'
        s += ' ' + self.name

        def _val(p):
            if p.value:
                return p.value
            elif p.direction == 'input':
                return str(p.width) + "'d0"
            else:
                return ""
        if self.ports:
            s += '\n   ('
            max_len = max([len(p.name) for p in self.ports])
            s += ',\n    '.join(['.' + p.name.ljust(max_len) +' (' + _val(p) + ')' for p in self.ports])
            s += ')'
        s += ';\n'
        return s

class VerilogWriter:
    header = ""
    raw = ""
    def __init__(self, name):
        self.name = name
        self.instances = []
        self.ports = []
        self.wires = []

    def add(self, obj):
        if isinstance(obj, Instance):
            self.instances += [obj]
        elif isinstance(obj, ModulePort):
            self.ports += [obj]
        elif isinstance(obj, Wire):
            self.wires += [obj]
        else:
            raise Exception("Invalid type!" + str(obj))

    def write(self, file=None):
        s = self.header

        if self.ports:
            s += "`default_nettype none\n"
            s += "module {name}\n".format(name=self.name)
            max_len = max([len(p.range()) for p in self.ports])
            s += '   ('
            s += ',\n    '.join([p.write(max_len) for p in self.ports])
            s += ')'
            s += ';\n\n'
        if self.wires:
            max_len = max([len(w.range()) for w in self.wires])
            for w in self.wires:
                s += w.write(max_len + 1)
            s +='\n'
        s += self.raw
        for i in self.instances:
            s += i.write()
            s += '\n'
        if self.ports:
            s += 'endmodule\n'
        if file is None:
            return s
        else:
            f = open(file,'w')
            f.write(s)

@@ -175,13 +175,18 @@
 se, 
-vec=0
+_type=None
 ):%0A 
@@ -279,16 +279,43 @@
 sc = asc
+%0A        self._type = _type
 %0A%0A    de
@@ -643,20 +643,23 @@
 return '
-wire
+%7B_type%7D
 %7Brange%7D 
@@ -680,40 +680,160 @@
 mat(
-range=self.range().rjust(width),
+_type=self._type or %22wire%22,%0A                                              range=self.range().rjust(width),%0A                                             
  nam
@@ -1006,16 +1006,28 @@
 value=%22%22
+, _type=None
 ):%0A     
@@ -1086,26 +1086,29 @@
    self.
-wires = %5B%5D
+_type = _type
 %0A%0Aclass 
@@ -1186,16 +1186,28 @@
 sc=False
+, _type=None
 ):%0A     
@@ -1263,16 +1263,23 @@
 low, asc
+, _type
 )%0A      
@@ -1315,16 +1315,30 @@
 te(self,
+ type_width=0,
  range_w
@@ -1358,22 +1358,19 @@
     
-return
+s =
  '%7Bdir%7D 
 wire
@@ -1365,20 +1365,23 @@
  '%7Bdir%7D 
-wire
+%7B_type%7D
  %7Brange%7D
@@ -1388,16 +1388,33 @@
  %7Bname%7D'
+%0A        return s
 .format(
@@ -1435,16 +1435,112 @@
 just(6),
+%0A                        _type=(self._type or %22wire%22).ljust(type_width),%0A                       
  range=s
@@ -1570,16 +1570,40 @@
 _width),
+%0A                       
  name=se
@@ -2288,16 +2288,21 @@
 (p.width
+ or 1
 ) + %22'd0
@@ -3294,16 +3294,89 @@
 f.name)%0A
+            type_len = max(%5Blen(p._type or %22wire%22) for p in self.ports%5D)%0A
         
@@ -3492,24 +3492,34 @@
 in(%5Bp.write(
+type_len, 
 max_len) for

Support types in verilogwriter