Nic30 / hdlConvertor

Fast Verilog/VHDL parser preprocessor and code generator for C++/Python based on ANTLR4
MIT License
281 stars 66 forks source link

Question regarding VHDL to hwt #164

Closed kaidoho closed 1 year ago

kaidoho commented 2 years ago

Hi,

I' like to tranfer a larger VHDL Library to hwt. I've had a look at test_verilog_to_hwt.py, which does exactly what I need but unfortunatelly for Verilog. In analogy to the verilog case I was looking for a vhdl_to_hwt(context), but I can't find one. Is it possible to generate hwt Python from VHDL, if so - could you tell me the steps or examples I should look at?

Thanks

Nic30 commented 2 years ago

Hello kaidoho,

I do have scripts doing this but the translation is not reliable and usually requires user modifications in order to produce working result.

It is also very useful to aggregate VHDL signals to interfaces, which is another complicated task. Do you need just to generate wrappers or do you really need to translate whole library? What the mentioned library does, maybe there is already something like that for hwt? (Also note that is much more simple to plug in litex/migen, chisel3, SpinalHDL, MyHDL(basically everything) than VHDL. )

kaidoho commented 2 years ago

Hi Nic,

thx for your quick response. The library I am concerned with has grown over the last decade. It contains simple "IPs", like for example a PWM, but also complex stuff like PCIe Cores formed by other IPs within the library. Most of the code is vendor agnostic, except for BlockRAM. There are TCL - Scripts that construct the wrappers for the complex cores. At the moment I am working on the build system, which has been moved from TCL / Shell scripts to Python. Now, I'am looking for a way to construct the wrappers from Python instead of TCL. Of course I can simply port TCL code to Python, but the TCL code is in itself a bit quirky and it doesn't give us much. Having a wrapper for each component at the hwt / Python level so that I can create hierachies based on various configurations and export them VHDL would already be a great first step. Basically, that was my first idea when looking into hwt, but I haven't found something like a black-box model for the VHDL components that I can easily generate. Is there an example showing how I'd do that?

Nic30 commented 2 years ago

@kaidoho

Sorry for long response latency, but there were some issues which did hit me very hard.

Yes there is, a black box equivalent. There are decorators which can change how the component is converted to HDL. For example this is a "black box" for xilinx axi register slice IPCore.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from hwt.interfaces.std import Clk, Rst_n
from hwt.synthesizer.unit import Unit
from hwtLib.amba.axi4 import Axi4, Axi4_addr, Axi4_w, Axi4_r, Axi4_b
from hwt.serializer.mode import serializeExclude

class Axi4_addr_nosep(Axi4_addr):
    _NAME_SEPARATOR = ""

class Axi4_w_nosep(Axi4_w):
    _NAME_SEPARATOR = ""

class Axi4_r_nosep(Axi4_r):
    _NAME_SEPARATOR = ""

class Axi4_b_nosep(Axi4_b):
    _NAME_SEPARATOR = ""

class Axi4_nosep(Axi4):
    AW_CLS = Axi4_addr_nosep
    AR_CLS = Axi4_addr_nosep
    W_CLS = Axi4_w_nosep
    R_CLS = Axi4_r_nosep
    B_CLS = Axi4_b_nosep

@serializeExclude
class mem_axi_register_slice(Unit):
    """
    This is a placeholder for Xilinx AXI register slice IP
    """
    def _config(self):
        # not as Param instances as we do not want to confuse vendor tool
        self.DATA_WIDTH = 64
        self.ID_WIDTH = 4
        self.ADDR_WIDTH = 24
        self.FREQ = int(100e6)

    def _declr(self):
        self.aclk = Clk()
        self.aclk.FREQ = self.FREQ

        with self._associated(clk=self.aclk):
            self.aresetn = Rst_n()
            with self._associated(rst=self.aresetn):
                self.m_axi = Axi4_nosep()._m()
                self.s_axi = Axi4_nosep()

        for a in [self.m_axi, self.s_axi]:
            a.ID_WIDTH = self.ID_WIDTH
            a.DATA_WIDTH = self.DATA_WIDTH
            a.ADDR_WIDTH = self.ADDR_WIDTH

    def _impl(self):
        self.m_axi(self.s_axi)

if __name__ == "__main__":
    from hwt.synthesizer.utils import to_rtl_str
    u = mem_axi_register_slice()

    print(to_rtl_str(u))

The @serializeExclude causes that no HDL is produced from this component (and can be provided externally). If you inherit just from Unit you will need to provide placeholder implementation of _impl. However there is also EmptyUnit https://github.com/Nic30/hwtLib/blob/6806c28730dc1a497889cd058e650b87735063cb/hwtLib/examples/emptyUnitWithSpi.py#L11 which automatically connect the output to something.

Nic30 commented 1 year ago

closing this issue as question was answered