Instantiating FPGA components


I’m experimenting for a couple of days now with MyHDL but cannot find a way to instantiate specific/dedicated, for Xilinx, components as MMCM, PLL, URAM, …

  • Is it at all possible to instantiate those components?
  • If yes:
    • How can this be done?
    • How are those components be hooked up in the Python design/code?
      • Simply use the signal names?
  • If no:
    • MyHDL can thus only be used to convert to regular/standard VHDL?
    • If specific FPGA features as MMCM and other components are needed a VHDL description is still necessary. That VHDL description can then contain MyHDL converted modules. Correct?


We do this quite a bit. For ip blocks (the ones you select in the block diagram), you can use Ovenbird. For lower level primitives, it’s a bit more subtle to get right (though Ovenbird could be extended to do it without too much work).

The problem is how to make it work seamlessly and for arbitrary number of primitives. For a one off, it’s not too hard. And it’s easier in Verilog then VHDL.


I’m using iCE40 parts, and also want seamless transition from sim to synth. I pass ‘SynType’ as an optional parameter through the design to select simulation or conversion for use in library parts etc.

I do not like the extra level of nesting, but have not recently found a way to work without it. Having some working code is good for now.

"""      """

from myhdl import * 

def SB_RGBA_DRV_Sim(   \
    RGB0, RGB1, RGB2, 

    def PWMsimLogic(): = RGB0PWM = RGB1PWM = RGB2PWM

    return PWMsimLogic

def SB_RGBA_DRV_Inst(   \
    RGB0, RGB1, RGB2, 
    ''' Instantiation of library part SB_RGBA_DRV '''
    RGB0_CURRENT = "0b000001"
    RGB1_CURRENT = "0b000001"
    RGB2_CURRENT = "0b000001"
    def logic():

    RGB0.driven = "wire"  
    RGB1.driven = "wire"  
    RGB2.driven = "wire" = True = True = True

    return logic
SB_RGBA_DRV_Inst.verilog_code =   \
// Instantiation of library part 
  .RGBLEDEN (1'b1),
  .RGB0PWM  ($RGB0PWM),  // green
  .RGB1PWM  ($RGB1PWM),  // blue
  .RGB2PWM  ($RGB2PWM),  // red
  .CURREN   (1'b1), 
  .RGB0     (GRNn),		// green on UPDuino v2.0 Board
  .RGB1     (BLUn),     // blue
  .RGB2     (REDn)      // red  
defparam SB_RGBA_DRV_01.RGB0_CURRENT = "$RGB0_CURRENT";  // "0b000001";
SB_RGBA_DRV_Inst.VHDL_code = """  \
-- Instantiation of library part 
--generic map(
--    RGB0_CURRENT => "$RGB0_CURRENT";  -- "0b000001",
port map( 
   RGBLEDEN -> (1'b1),
   RGB0PWM  -> ($RGB0PWM),  -- green
   RGB1PWM  -> ($RGB1PWM),  -- blue
   RGB2PWM  -> ($RGB2PWM),  -- red
   CURREN   -> (1'b1), 
   RGB0     -> (GRNn),   -- green on UPDuino v2.0 Board
   RGB1     -> (BLUn),    -- blue
   RGB2     -> (REDn)     -- red  

def SB_RGBA_DRV(   \
    RGB0, RGB1, RGB2, 
    SynType ): 
    ''' SiBlu library part SB_RGBA_DRV '''

    if SynType=="Sim":  mySB_RGBA_DRV = SB_RGBA_DRV_Sim
    else:               mySB_RGBA_DRV = SB_RGBA_DRV_Inst
    RGBdrv01 = mySB_RGBA_DRV( \
        1, RGB0PWM, RGB1PWM, RGB2PWM, 
        1, RGB0, RGB1, RGB2,  )

    return RGBdrv01

This is working, but incomplete: the LED is fixed at minimum drive current. Also, the project VHDL export is not working.

This uninitialized RAM model works without extra symbolic indirection, and the demo project exports Verilog and VHDL. (No hardware test yet)


2018-11-02 jc changed "(% s)" substitution to "$" type

from myhdl import * 
from random import randint

RdLatency = 3

                        WADDR, WCLK, WCLKE, WDATA, WE, MASK, SynType ): 
    ''' sim & synth version of iCE40 block RAM '''
    mem = [ Signal(intbv(0x5555)[16:]) for ii in range(256)]
    RData_RClk = Signal(intbv(0)[16:])

    def RData_RClkLogic():
        if ((RCLKE==1) and (RE==1)):
   = mem[int(RADDR)]

    def RDATAlogic(): = RData_RClk

    WData_WClk = Signal(intbv(0)[16:])
    WAddr_WClk = Signal(intbv(0)[8:])
    WEtm1, WEtm2 = [Signal(bool(0)) for ii in range(2)]
    def WEtm1Logic():
        ''' WEtm1 WEtm2 write process timing ''' = WE & WCLKE = WEtm1 
    def WData_WClkLogic():
        if WCLKE & WEtm1:
   = WDATA
   = WADDR
    def WriteLogic():
        if WEtm1 & WEtm2 & WCLKE & WE:
            mem[int(WADDR)].next =  \
                    (~MASK & WDATA) | (MASK & mem[WADDR])
            #mem[int(WADDR)].next = WDATA

    def NoLogic():
        ''' empty logic '''
    ''' connection assurance '''
    RDATA.driven = "wire" = True = True = True = True = True = True = True = True = True = True  # may cause trouble?
    SB_RAM256X16.verilog_code =  \
"""// iCE40 Library Part \\\\
SB_RAM256x16 SB_RAM256X16inst(

    SB_RAM256X16.vhdl_code =  \
"""-- iCE40 Library Part --
RAM256X16: SB_RAM256X16
    port map(
      RDATA => $RDATA,
      RADDR => $RADDR,
      RCLK => $RCLK,
      RCLKE => $RCLKE,
      RE => $RE,
      WADDR => $WADDR,
      WCLK=> $WCLK,
      WCLKE => $WCLKE,
      WDATA => $WDATA,
      MASK => $MASK,
      WE => $WE  
    if SynType=='Sim':
        return  RData_RClkLogic, RDATAlogic, WEtm1Logic, \
        WData_WClkLogic, WriteLogic   
        return NoLogic

There are other library parts which are working but incomplete, including an initialized RAM.

Jan Coombs


Thus without extras, puzzling things together with other tools and/or additions it seems not possible to go from MyHDL, via intermediary VHDL or verilog, to a direct implementable design.

The way to go, seems to, is to create a hierarchical design were some of the hierarchy is written and simulated in python, translated to a form of HDL. Then that VHDL/verilog is assembled with VHDL/verilog sources dealing with specifics of the FPGA (Hardware blocks (MMCM, PLL, DSP,…), IP, IO, constraints and etcetera …). Then all that is passed through the synthesis and implementation kitchen of the FPGA brand used.

Since most of my designs always need to be as compact as possible and stretch the speed boundaries this route might not be the best for me. VHDL-2008 still seems the best suited. The MyHDL way looks nice for implementation of general behaviour designs.

My 0.02 euro

What extras or other tools? ( I find additions and puzzling a normal part of design :–)

The parts you mentioned are documented in Libraries Guides, eg [1], along with instantiation templates, as I used for my MyHDL models above; copy & paste.

The MMCM looks a bit of a beast, but you only need to include the functionality you are using in the MyHDL simulation model.

I have stopped using BRAM instantiation because yosys [2], in the icestorm toolchain [3], is hot on implicit block RAM instantiation.

Which chip library part do you need to use?

What subset of functionality will you initially want for this?

Jan Coombs


You can try

Puzzling is fo rthe design, not for the tools. Tools just need to work, I can’t spend days finding out how a tool works. But I give it a second, third try.

Thanks for this!
Makes my next trials tick.