function update

Add async reset and some Verilog support
This commit is contained in:
201830600181@mail.scut.edu.cn 2022-01-07 14:20:15 +08:00
parent 774e5cb3ae
commit fe3d82ba44
7 changed files with 260 additions and 25 deletions

2
.gitignore vendored
View File

@ -6,7 +6,7 @@ __pycache__/
# pysv
.sv/
.build/
simlutulation/
simulation/
# firrtl
.fir/

View File

@ -1,36 +1,66 @@
from pysv import sv, DataType, Reference
import random
from pyhcl import *
from pysv import sv, DataType, Reference
from pyhcl.simulator import Simlite, DpiConfig
import random
class BBox(BlackBox):
class Add(BlackBox):
io = IO(
in1=Input(U.w(64)),
in2=Input(U.w(64)),
out1=Output(U.w(64)),
out2=Output(U.w(64)),
in1=Input(U.w(32)),
out=Output(U.w(32))
)
@sv(a=DataType.ULongInt, b=DataType.ULongInt, return_type=Reference(x=DataType.ULongInt, y=DataType.ULongInt))
def f(a, b):
return a+b, a-b
@sv(a=DataType.UInt, return_type=Reference(x=DataType.UInt))
def fn(a):
return a + 10000
addpysvmodule(BBox, f)
addpysvmodule(Add, fn)
class Rand(BlackBox):
io = IO(
in1=Input(U.w(32)),
in2=Input(U.w(32)),
out=Output(U.w(32))
)
@sv(a=DataType.UInt, b=DataType.UInt, return_type=Reference(x=DataType.UInt))
def fn2(a, b):
return random.randint(a, b)
addpysvmodule(Rand, fn2)
compile_and_binding_all()
class M(Module):
class Top(Module):
io = IO(
i = Input(U.w(64)),
o = Output(U.w(64)),
a=Input(U.w(32)),
b=Input(U.w(32)),
c=Output(U.w(32))
)
bbox = BBox()
bbox.io.in1 <<= io.i
bbox.io.in2 <<= io.i
io.o <<= bbox.io.out1 ^ bbox.io.out2
wire = Wire(U.w(32))
r = Rand()
add = Add()
r.io.in1 <<= io.a
r.io.in2 <<= io.b
wire <<= r.io.out
add.io.in1 <<= wire
io.c <<= add.io.out
if __name__ == '__main__':
Emitter.dump(Emitter.emit(M()), "bbox.fir")
cfg = DpiConfig()
# Emitter.dumpVerilog(Emitter.dump(Emitter.emit(Top()), "Top.fir"))
s = Simlite(Top(), harness_code=None, dpiconfig=cfg)
s.step([20, 20])
s.step([15, 100])
s.step([1000, 2000])
s.step([999, 2010])

View File

@ -4,7 +4,7 @@ from .condition import when, elsewhen, otherwise
from .cio import IO, Input, Output
from .infra import Wire, Reg, RegInit, Mux, LookUpTable, BitPat
from .emitter import Emitter
from .cdatatype import U, S, Bool, Clock
from .cdatatype import U, S, Bool, Clock, AsyncReset, Reset
from .vector import Vec, VecInit
from .funcs import CatVecL2H, CatVecH2L, CatBits, OneDimensionalization, Sum, Decoupled
from .memory import Mem

View File

@ -114,3 +114,11 @@ class S(CType, metaclass=SInit):
class Clock(CType):
def mapToIR(self, ctx):
return low_ir.ClockType()
class Reset(CType):
def mapToIR(self, ctx):
return low_ir.ResetType()
class AsyncReset(CType):
def mapToIR(self, ctx):
return low_ir.AsyncResetType()

View File

@ -6,7 +6,7 @@ from typing import List, Optional
from pyhcl.ir.low_node import FirrtlNode
from pyhcl.ir.low_prim import PrimOp, Bits
from pyhcl.ir.utils import indent
from pyhcl.ir.utils import backspace, indent
class Info(FirrtlNode, ABC):
@ -16,12 +16,18 @@ class Info(FirrtlNode, ABC):
"""default implementation"""
return self.__repr__()
def verilog_serialize(self) -> str:
return self.__repr__()
@dataclass(frozen=True, init=False)
class NoInfo(Info):
def serialize(self) -> str:
return ''
def verilog_serialize(self) -> str:
return ''
@dataclass(frozen=True)
class FileInfo(Info):
@ -30,6 +36,9 @@ class FileInfo(Info):
def serialize(self) -> str:
return f" @[{self.info.serialize()}]"
def verilog_serialize(self) -> str:
return f" /*[{self.info.verilog_serialize()}]*/"
@dataclass(frozen=True)
class StringLit(FirrtlNode):
@ -42,6 +51,9 @@ class StringLit(FirrtlNode):
def serialize(self) -> str:
return self.escape()[1:-1]
def verilog_serialize(self) -> str:
return self.serialize()
class Expression(FirrtlNode, ABC):
"""EXPRESSIONs"""
@ -58,6 +70,9 @@ class UnknownType(Type):
def serialize(self) -> str:
return '?'
def verilog_serialize(self) -> str:
return self.serialize()
@dataclass(frozen=True)
class Reference(Expression):
@ -67,6 +82,9 @@ class Reference(Expression):
def serialize(self) -> str:
return self.name
def verilog_serialize(self) -> str:
return self.serialize()
@dataclass(frozen=True)
class SubField(Expression):
@ -77,6 +95,9 @@ class SubField(Expression):
def serialize(self) -> str:
return f"{self.expr.serialize()}.{self.name}"
def verilog_serialize(self) -> str:
return f"{self.expr.verilog_serialize()}_{self.name}"
@dataclass(frozen=True)
class SubIndex(Expression):
@ -87,6 +108,9 @@ class SubIndex(Expression):
def serialize(self) -> str:
return f"{self.expr.serialize()}[{self.value}]"
def verilog_serialize(self) -> str:
return f"{self.expr.verilog_serialize()}[{self.value}]"
@dataclass(frozen=True)
class SubAccess(Expression):
@ -97,6 +121,9 @@ class SubAccess(Expression):
def serialize(self) -> str:
return f"{self.expr.serialize()}[{self.index.serialize()}]"
def verilog_serialize(self) -> str:
return f"{self.expr.verilog_serialize()}[{self.index.verilog_serialize()}]"
@dataclass(frozen=True)
class Mux(Expression):
@ -108,6 +135,9 @@ class Mux(Expression):
def serialize(self) -> str:
return f"mux({self.cond.serialize()}, {self.tval.serialize()}, {self.fval.serialize()})"
def verilog_serialize(self) -> str:
return f"{self.cond.serialize()} ? {self.tval.serialize()} : {self.fval.serialize()}"
@dataclass(frozen=True)
class DoPrim(Expression):
@ -120,6 +150,10 @@ class DoPrim(Expression):
sl: List[str] = [arg.serialize() for arg in self.args] + [repr(con) for con in self.consts]
return f'{self.op.serialize()}({", ".join(sl)})'
def verilog_serialize(self) -> str:
sl: List[str] = [arg.serialize() for arg in self.args] + [repr(con) for con in self.consts]
return f'{self.op.serialize().join(sl)}'
@dataclass(frozen=True)
class Width(FirrtlNode, ABC):
@ -133,6 +167,9 @@ class IntWidth(Width):
def serialize(self) -> str:
return f'<{self.width}>'
def verilog_serialize(self) -> str:
return f'[{self.width-1}:0]' if self.width - 1 else ""
@dataclass(frozen=True, init=False)
class UnknownWidth(Width):
@ -141,6 +178,9 @@ class UnknownWidth(Width):
def serialize(self) -> str:
return ""
def verilog_serialize(self) -> str:
return ""
@dataclass(frozen=True, init=False)
class UIntLiteral(Expression):
@ -159,6 +199,9 @@ class UIntLiteral(Expression):
def serialize(self) -> str:
return f'UInt{self.width.serialize()}("h{hex(self.value)[2:]}")'
def verilog_serialize(self) -> str:
return f'{self.width}\'h{hex(self.value)}'
@dataclass(frozen=True, init=False)
class SIntLiteral(Expression):
@ -177,6 +220,9 @@ class SIntLiteral(Expression):
def serialize(self) -> str:
return f'SInt{self.width.serialize()}("h{hex(self.value)[2:]}")'
def verilog_serialize(self) -> str:
return f'{self.width}\'h{hex(self.value)}'
class GroundType(Type, ABC):
...
@ -193,6 +239,9 @@ class UIntType(GroundType):
def serialize(self) -> str:
return f'UInt{self.width.serialize()}'
def verilog_serialize(self) -> str:
return f'{self.width.verilog_serialize()}'
def irWithIndex(self, index):
if isinstance(index, slice):
length = index.start - index.stop + 1
@ -219,6 +268,9 @@ class SIntType(GroundType):
def serialize(self) -> str:
return f'SInt{self.width.serialize()}'
def verilog_serialize(self) -> str:
return f'{self.width.serialize()}'
class Orientation(FirrtlNode, ABC):
"""# Orientation of [[Field]]"""
@ -230,12 +282,18 @@ class Default(Orientation):
def serialize(self) -> str:
return ''
def verilog_serialize(self) -> str:
return ''
@dataclass(frozen=True, init=False)
class Flip(Orientation):
def serialize(self) -> str:
return 'flip '
def verilog_serialize(self) -> str:
return 'flip'
@dataclass(frozen=True)
class Field(FirrtlNode):
@ -247,6 +305,9 @@ class Field(FirrtlNode):
def serialize(self) -> str:
return f'{self.flip.serialize()}{self.name} : {self.typ.serialize()}'
def verilog_serialize(self) -> str:
return f'{self.flip.verilog_serialize()}{self.typ.verilog_serialize()}\t${self.name}'
@dataclass(frozen=True)
class BundleType(AggregateType):
@ -255,6 +316,16 @@ class BundleType(AggregateType):
def serialize(self) -> str:
return '{' + ', '.join([f.serialize() for f in self.fields]) + '}'
def verilog_serialize(self) -> list:
field_list = []
for f in self.fields:
if type(f.typ.verilog_serialize()) is list:
for t in f.typ.verilog_serialize():
field_list.append(f'${f.name}{t}')
else:
field_list.append(f.verilog_serialize())
return field_list
@dataclass(frozen=True)
class VectorType(AggregateType):
@ -264,6 +335,9 @@ class VectorType(AggregateType):
def serialize(self) -> str:
return f'{self.typ.serialize()}[{self.size}]'
def verilog_serialize(self) -> list:
return [f'_{v}' for v in range(self.size)]
def irWithIndex(self, index):
if isinstance(index, int):
return lambda _: {"ir": SubIndex(_, index, self.typ)}
@ -279,6 +353,9 @@ class MemoryType(AggregateType):
def serialize(self) -> str:
return f'{self.typ.serialize()}[{self.size}]'
def verilog_serialize(self) -> str:
return [f'_{v}' for v in range(self.size)]
def irWithIndex(self, index):
return lambda _: {"ir": lambda name, mem, clk, rw: DefMemPort(name, mem, index, clk, rw), "inPort": True}
@ -290,6 +367,32 @@ class ClockType(GroundType):
def serialize(self) -> str:
return 'Clock'
def verilog_serialize(self) -> str:
# Todo
pass
@dataclass(frozen=True, init=False)
class ResetType(GroundType):
width: Width = IntWidth(1)
def serialize(self) -> str:
return "UInt<1>"
def verilog_serialize(self) -> str:
# Todo
pass
@dataclass(frozen=True, init=False)
class AsyncResetType(GroundType):
width: Width = IntWidth(1)
def serialize(self) -> str:
return "AsyncReset"
def verilog_serialize(self) -> str:
# Todo
pass
class Direction(FirrtlNode, ABC):
"""[[Port]] Direction"""
@ -301,12 +404,22 @@ class Input(Direction):
def serialize(self) -> str:
return 'input'
def verilog_serialize(self, flip = False) -> str:
if flip is True:
return 'output'
return 'input'
@dataclass(frozen=True, init=False)
class Output(Direction):
def serialize(self) -> str:
return 'output'
def verilog_serialize(self, flip = False) -> str:
if flip is True:
return 'input'
return 'output'
# [[DefModule]] Port
@dataclass(frozen=True)
@ -319,6 +432,22 @@ class Port(FirrtlNode):
def serialize(self) -> str:
return f'{self.direction.serialize()} {self.name} : {self.typ.serialize()}{self.info.serialize()}'
def verilog_serialize(self) -> str:
if type(self.typ.verilog_serialize()) is str:
return f'{self.direction.verilog_serialize()}\t{self.typ.verilog_serialize()}\t{self.name},\n'
else:
portdeclares = ''
seq = self.typ.verilog_serialize()
for s in seq:
ns = s.replace('$', f'{self.name}_')
if "flip" in ns:
ns = ns.replace('flip', "")
portdeclares += f'{self.direction.verilog_serialize(True)}\t{ns},\n'
else:
portdeclares += f'{self.direction.verilog_serialize()}\t{ns},\n'
return portdeclares
class Statement(FirrtlNode, ABC):
...
@ -329,6 +458,9 @@ class EmptyStmt(Statement):
def serialize(self) -> str:
return 'skip'
def verilog_serialize(self) -> str:
return '// skip'
@dataclass(frozen=True)
class DefWire(Statement):
@ -339,6 +471,8 @@ class DefWire(Statement):
def serialize(self) -> str:
return f'wire {self.name} : {self.typ.serialize()}{self.info.serialize()}'
def verilog_serialize(self) -> str:
return f'wire\t{self.typ.verilog_serialize()}\t{self.name}{self.info.verilog_serialize()};'
@dataclass(frozen=True)
class DefRegister(Statement):
@ -354,16 +488,26 @@ class DefRegister(Statement):
if self.init is not None else ""
return f'reg {self.name} : {self.typ.serialize()}, {self.clock.serialize()}{i}{self.info.serialize()}'
def verilog_serialize(self) -> str:
return f'reg {self.typ.verilog_serialize()}\t{self.name}{self.info.verilog_serialize()}'
@dataclass(frozen=True)
class DefInstance(Statement):
name: str
module: str
ports: List[Port]
info: Info = NoInfo()
def serialize(self) -> str:
return f'inst {self.name} of {self.module}{self.info.serialize()}'
def verilog_serialize(self) -> str:
instdeclares = ''
for p in self.ports:
instdeclares += f'\n.{p.name}({self.name}_{p.name}),'
return f'{self.module} {self.name} ({instdeclares}\n);'
# @dataclass(frozen=True)
# class DefMemory(Statement):
@ -399,6 +543,12 @@ class DefMemory(Statement):
def serialize(self) -> str:
return f'cmem {self.name} : {self.memType.serialize()}{self.info.serialize()}'
def verilog_serialize(self) -> str:
memorydeclares = ''
memorydeclares += f'{self.memType.verilog_serialize()}\n'
memorydeclares += f'{self.info.verilog_serialize()}\n'
return memorydeclares
@dataclass(frozen=True)
class DefNode(Statement):
@ -409,6 +559,9 @@ class DefNode(Statement):
def serialize(self) -> str:
return f'node {self.name} = {self.value.serialize()}{self.info.serialize()}'
def verilog_serialize(self) -> str:
return f'wire {self.name} = {self.value.verilog_serialize()}{self.info.verilog_serialize()};'
@dataclass(frozen=True)
class DefMemPort(Statement):
@ -424,6 +577,12 @@ class DefMemPort(Statement):
return f'{rw} mport {self.name} = {self.mem.serialize()}[{self.index.serialize()}], ' \
f'{self.clk.serialize()}{self.info.serialize()}'
def verilog_serialize(self) -> str:
memportdeclares = ''
memportdeclares += indent(f'{self.mem.verilog_serialize()}')
# TODO
return memportdeclares
@dataclass(frozen=True)
class Conditionally(Statement):
@ -437,6 +596,9 @@ class Conditionally(Statement):
('' if self.alt == EmptyStmt() else '\nelse :' + indent(f'\n{self.alt.serialize()}'))
return f'when {self.pred.serialize()} :{self.info.serialize()}{s}'
def verilog_serialize(self) -> str:
return ""
@dataclass(frozen=True)
class Block(Statement):
@ -445,6 +607,9 @@ class Block(Statement):
def serialize(self) -> str:
return '\n'.join([stmt.serialize() for stmt in self.stmts])
def verilog_serialize(self) -> str:
return '\n'.join([stmt.verilog_serialize() for stmt in self.stmts])
@dataclass(frozen=True)
class Connect(Statement):
@ -455,6 +620,9 @@ class Connect(Statement):
def serialize(self) -> str:
return f'{self.loc.serialize()} <= {self.expr.serialize()}{self.info.serialize()}'
def verilog_serialize(self) -> str:
return f'assign {self.loc.verilog_serialize()} = {self.expr.verilog_serialize()}{self.info.verilog_serialize()};'
# Verification
class Verification(FirrtlNode, ABC):
@ -471,6 +639,9 @@ class Assert(Verification):
def serialize(self) -> str:
return f'assert({self.clk.serialize()}, {self.pred.serialize()}, {self.en.serialize()}, \"{self.msg}\")\n'
def verilog_serialize(self) -> str:
return ""
@dataclass(frozen=True)
class Assume(Verification):
@ -482,6 +653,9 @@ class Assume(Verification):
def serialize(self) -> str:
return f'assert({self.clk.serialize()}, {self.pred.serialize()}, {self.en.serialize()},{self.msg})\n'
def verilog_serialize(self) -> str:
return ""
@dataclass(frozen=True)
class Cover(Verification):
@ -493,12 +667,19 @@ class Cover(Verification):
def serialize(self) -> str:
return f'assert({self.clk.serialize()}, {self.pred.serialize()}, {self.en.serialize()},{self.msg})\n'
def verilog_serialize(self) -> str:
return ""
# Base class for modules
class DefModule(FirrtlNode, ABC):
def serializeHeader(self, typ: str) -> str:
ps = indent(''.join([f'\n{p.serialize()}' for p in self.ports]))
return f'{typ} {self.name} :{self.info.serialize()}{ps}\n'
moduledeclares = indent(''.join([f'\n{p.serialize()}' for p in self.ports]))
return f'{typ} {self.name} :{self.info.serialize()}{moduledeclares}\n'
def verilog_serializeHeader(self, typ:str) -> str:
moduledeclares = ''.join([f'{p.verilog_serialize()}' for p in self.ports])
return f'{typ} {self.name}(\n{moduledeclares});\n'
@dataclass(frozen=True)
@ -512,6 +693,8 @@ class Module(DefModule):
def serialize(self) -> str:
return self.serializeHeader('module') + indent(f'\n{self.body.serialize()}')
def verilog_serialize(self) -> str:
return self.verilog_serializeHeader('module') + f'\n{self.body.verilog_serialize()}' + '\nendmodule'
@dataclass(frozen=True)
class ExtModule(DefModule):
@ -525,6 +708,9 @@ class ExtModule(DefModule):
s = indent(f'\ndefname = {self.defname}\n')
return f'{self.serializeHeader("extmodule")}{s}'
def verilog_serialize(self) -> str:
return f'{self.verilog_serializeHeader("module")}endmodule\n'
@dataclass(frozen=True)
@ -536,3 +722,7 @@ class Circuit(FirrtlNode):
def serialize(self) -> str:
ms = '\n'.join([indent(f'\n{m.serialize()}') for m in self.modules])
return f'circuit {self.main} :{self.info.serialize()}{ms}\n'
def verilog_serialize(self) -> str:
ms = ''.join([f'{m.verilog_serialize()}\n' for m in self.modules])
return ms

View File

@ -6,4 +6,8 @@ class FirrtlNode(ABC):
@abstractmethod
def serialize(self) -> str:
...
...
@abstractmethod
def verilog_serialize(self) -> str:
...

View File

@ -1,6 +1,9 @@
def indent(string: str) -> str:
return string.replace('\n', '\n ')
def backspace(string: str) -> str:
return string.replace('\n ', '\n')
def auto_connect(ma, mb):
from pyhcl import IO