diff --git a/apycula/attrids.py b/apycula/attrids.py new file mode 100644 index 00000000..a8edceef --- /dev/null +++ b/apycula/attrids.py @@ -0,0 +1,603 @@ +# These constants are used to interact with the 'logicinfo', 'shortval' and maybe 'longval' tables +# * - it seems that these attributes must always be present (XXX) +# Warning: +# - the names assigned to constants are not exact correspondence with the primitive parameter names +# - some constants are for internal use only +# - not all attribute values have names because for example naming all values from 0 to 63 is tedious. +iob_attrids = { + 'IO_TYPE': 0, + 'SLEWRATE': 1, # * + 'PULLMODE': 2, # * + 'DRIVE': 3, # * + 'OPENDRAIN': 4, # * + 'HYSTERESIS': 5, # * + 'CLAMP': 6, # * + 'DIFFRESISTOR': 7, # * + 'SINGLERESISTOR': 8, # * + 'VREF': 9, # * + 'VCCIO': 10, + 'DIFFDRIVE': 11, + 'I3C_MODE': 12, + 'MIPI_INPUT': 13, + 'MIPI_OUTPUT': 14, + 'DRIVE_LEVEL': 15, + 'LVDS_OUT': 16, # * + 'LVDS_VCCIO': 17, + 'DDR_DYNTERM': 18, + 'IO_BANK': 19, # * + 'PERSISTENT': 20, # * + 'TO': 21, + 'ODMUX': 22, + 'ODMUX_1': 23, + 'PADDI': 24, + 'PG_MUX': 25, + 'DATA_MUX': 26, + 'TRI_MUX': 27, + 'TRIMUX_PADDT': 28, + 'IOBUF_PADDI': 29, + 'USED': 30, # * + 'IOBUF_OVERDRIVE': 31, + 'IOBUF_UNDERDRIVE': 32, + 'IOBUF_LVDS25_VCCIO': 33, + 'IN12_MODE': 34, + 'OD': 35, + 'LPRX_A1': 36, + 'LPRX_A2': 37, + 'MIPI': 38, + 'LVDS_SEL': 39, + 'VLDS_ON': 40, + 'IOBUF_MIPI_LP': 41, + 'IOBUF_ODT_RESISTOR': 42, + 'IOBUF_CIB_CONTROL': 43, + 'IOBUF_INR_MODE': 44, + 'IOBUF_STDBY_LVDS_MODE': 45, + 'IOBUF_IODUTY': 46, + 'IOBUF_ODT_DYNTERM': 47, + 'MIPI_IBUF_DRIVE': 48, + 'MIPI_IBUF_DRIVE_LEVEL': 49 + } + +iob_attrvals = { + 'UNKNOWN': 0, # possible a dummy value for line 0 in logicinfo? + # standard + 'MIPI': 1, + 'BLVDS25E': 2, + 'BLVDS25': 3, + 'BLVDS_E': 4, + 'HSTL': 5, + 'HSTL_D': 6, + 'HSTL15_I': 7, + 'HSTL15D_I': 8, + 'HSTL18_I': 9, + 'HSTL18_II': 10, + 'HSTL18D_I': 11, + 'HSTL18D_II': 12, + 'SSTL': 13, + 'SSTL_D': 14, + 'SSTL15': 15, + 'SSTL15D': 16, + 'SSTL18_I': 17, + 'SSTL18_II': 18, + 'SSTL18D_I': 19, + 'SSTL18D_II': 20, + 'SSTL25_I': 21, + 'SSTL25_II': 22, + 'SSTL25D_I': 23, + 'SSTL25D_II': 24, + 'SSTL33_I': 25, + 'SSTL33_II': 26, + 'SSTL33D_I': 27, + 'SSTL33D_II': 28, + 'LVCMOS12': 29, + 'LVCMOS15': 30, + 'LVCMOS18': 31, + 'LVCMOS25': 32, + 'LVCMOS33': 33, + 'LVCMOS_D': 34, + 'LVCMOS12D': 35, + 'LVCMOS15D': 36, + 'LVCMOS18D': 37, + 'LVCMOS25D': 38, + 'LVCMOS33D': 39, + 'LVDS': 40, + 'LVDS_E': 41, + 'LVDS25': 42, + 'LVDS25E': 43, + 'LVPECL33': 44, + 'LVPECL33E': 45, + 'LVTTL33': 46, + 'MLVDS25': 47, + 'MLVDS_E': 48, + 'MLVDS25E': 49, + 'RSDS25E': 50, + 'PCI33': 51, + 'RSDS': 52, + 'RSDS25': 53, + 'RSDS_E': 54, + 'MINILVDS': 55, + 'PPLVDS': 56, + # + 'VREF1_DRIVER': 57, + 'VREF2_DRIVER': 58, + 'LVCMOS33OD25': 59, + 'LVCMOS33OD18': 60, + 'LVCMOS33OD15': 61, + 'LVCMOS25OD18': 62, + 'LVCMOS25OD15': 63, + 'LVCMOS18OD15': 64, + 'LVCMOS15OD12': 65, + 'LVCMOS25UD33': 66, + 'LVCMOS18UD25': 67, + 'LVCMOS18UD33': 68, + 'LVCMOS15UD18': 69, + 'LVCMOS15UD25': 70, + 'LVCMOS15UD33': 71, + 'LVCMOS12UD15': 72, + 'LVCMOS12UD18': 73, + 'LVCMOS12UD25': 74, + 'LVCMOS12UD33': 75, + 'VREF1_LOAD': 76, + 'VREF2_LOAD': 77, + # + 'ENABLE': 78, + 'TRIMUX': 79, + 'PADDI': 80, + 'PGBUF': 81, + '0': 82, + '1': 83, + 'SIG': 84, + 'INV': 85, + 'TO': 86, + # voltage + '1.2': 87, + '1.25': 88, + '1.5': 89, + '1.8': 90, + '2.0': 91, + '2.5': 92, + '3.3': 93, + '3.5': 94, + # mA + '2': 95, + '4': 96, + '6': 97, + '8': 98, + '12': 99, + '16': 100, + '20': 101, + '24': 102, + # XXX ? + '80': 103, + '100': 104, + '120': 105, + # + 'NA': 106, + 'ON': 107, + 'OFF': 108, + # XXX + 'PCI': 109, + # histeresis + 'HIGH': 110, + 'H2L': 111, + 'L2H': 112, + # pullmode + 'DOWN': 113, + 'KEEPER': 114, + 'NONE': 115, + 'UP': 116, + # slew + 'FAST': 117, + 'SLOW': 118, + # + 'I45': 119, + 'I50': 120, + 'I55': 121, + 'TSREG': 122, + 'TMDDR': 123, + 'OD1': 124, + 'OD2': 125, + 'OD3': 126, + 'UD1': 127, + 'UD3': 128, + # resistor? + 'INTERNAL': 129, + 'SINGLE': 130, + 'DIFF': 131, + # + 'IN12': 132, + 'UD2': 133, + 'LVPECL_E': 134, + # + '68': 135, + '3': 136, + '5': 137, + '7': 138, + '9': 139, + '10': 140, + '11': 141, + '4.5': 142, + 'MIPI_IBUF': 143, + '1.35': 144, + '5.5': 145, + '6.5': 146, + '10.5': 147, + '13.5': 148, + '14': 149, + # more standard + 'TMDS33': 150, + 'LPDDR': 151, + 'HSUL12': 152, + 'HSUL12D': 153, + 'HSTL12_I': 154, + 'HSTL15_II': 155, + 'HSTL15D_II': 156, + 'SSTL12': 157, + 'SSTL135': 158, + 'SSTL135D': 159, + 'LVCMOS10': 160, + 'LVCMOS33OD12': 161, + 'LVCMOS25OD12': 162, + 'LVCMOS18OD12': 163, + } + +# ADC +adc_attrids = { + 'EN': 0, + 'VCCX': 1, + 'IOVREF': 2, + 'VREF': 3, + 'USED_FLAG': 4, + } + +adc_attrvals = { + 'UNKNOWN': 0, + 'ENABLE': 1, + '3.3': 2, + '2.80': 3, + '2.55': 4, + '2.39': 5, + '2.23': 6, + '1.81': 7, + '1.65': 8, + '2.5': 9, + '2.12': 10, + '1.94': 11, + '1.69': 12, + '1.37': 13, + '1.25': 14, + '1.8': 15, + '1.53': 16, + '1.39': 17, + '1.30': 18, + '1.21': 19, + '0.99': 20, + '0.9': 21, + 'ON': 22 + } + + +# BSRAM +bsram_attrids = { + 'CEMUX_CEA': 0, + 'CEMUX_CEB': 1, + 'CLKMUX_CLKA': 2, + 'CLKMUX_CLKB': 3, + 'CSA2': 4, + 'CSA_0': 5, + 'CSA_1': 6, + 'CSA_2': 7, + 'CSB2': 8, + 'CSB_0': 9, + 'CSB_1': 10, + 'CSB_2': 11, + 'DBLWA': 12, + 'DBLWB': 13, + 'GSR': 14, + 'MODE': 15, + 'OUTREG_ASYNC': 16, + 'OUTREG_CEA': 17, + 'OUTREG_CEB': 18, + 'PORTB_IBEH': 19, + 'REGSET_RSTA': 20, + 'REGSET_RSTB': 21, + 'REGSET_WEB': 22, + 'SYNC': 23, + 'WEMUX_WEA': 24, + 'WEMUX_WEB': 25, + 'DPA_DATA_WIDTH': 26, + 'DPB_DATA_WIDTH': 27, + 'DPA_BEHB': 28, + 'DPA_BELB': 29, + 'DPA_MODE': 30, + 'DPA_REGMODE': 31, + 'DPB_BEHB': 32, + 'DPB_BELB': 33, + 'DPB_MODE': 34, + 'DPB_REGMODE': 35, + 'SDPA_DATA_WIDTH': 36, + 'SDPB_DATA_WIDTH': 37, + 'SDPA_BEHB': 38, + 'SDPA_BELB': 39, + 'SDPA_MODE': 40, + 'SDPA_REGMODE': 41, + 'SDPB_BEHB': 42, + 'SDPB_BELB': 43, + 'SDPB_MODE': 44, + 'SDPB_REGMODE': 45, + 'SPA_DATA_WIDTH': 46, + 'SPB_DATA_WIDTH': 47, + 'SPA_BEHB': 48, + 'SPA_BELB': 49, + 'SPB_BEHB': 50, + 'SPB_BELB': 51, + 'SPA_MODE': 52, + 'SPA_REG_MODE': 53, + 'SPB_MODE': 54, + 'SPB_REG_MODE': 55, + 'ROMA_DATA_WIDTH': 56, + 'ROMB_DATA_WIDTH': 57, + 'ROM_DATA_WIDTH': 58, + 'ROM_PORTA_BEHB': 59, + 'ROM_PORTA_BELB': 60, + 'ROM_PORTA_REGMODE':61, + 'ROM_PORTB_REGMODE':62, + 'PORTB_BELB': 63, + 'PORTA_MODE': 64, + 'PORTB_MODE': 65, + 'PORTB_BEHB': 66 + } + +bsram_attrvals = { + 'UNKNOWN': 0, + 'INV': 1, + 'ENABLE': 2, + 'SET': 3, + 'X36': 4, + '1': 5, + '2': 6, + '4': 7, + '9': 8, + '16': 9, + 'RBW': 10, + 'WT': 11, + 'OUTREG': 12, + 'DISABLE': 13, + 'RESET': 14 + } + +# slice +cls_attrids = { + 'MODE': 0, + 'REGMODE': 1, + 'SRMODE': 2, + 'GSR': 3, + 'LSRONMUX': 4, + 'CEMUX_1': 5, + 'CEMUX_CE': 6, + 'CLKMUX_1': 7, + 'CLKMUX_CLK': 8, + 'LSR_MUX_1': 9, + 'LSR_MUX_LSR': 10, + 'REG0_SD': 11, + 'REG1_SD': 12, + 'REG0_REGSET': 13, + 'REG1_REGSET': 14 + } + +cls_attrvals = { + 'UNKNOWN': 0, + '0': 1, + '1': 2, + 'SIG': 3, + 'INV': 4, + 'ENGSR': 5, + 'DISGSR': 6, + 'LSRMUX': 7, + 'LUT': 8, + 'LOGIC': 9, + 'ALU': 10, + 'SSRAM': 11, + 'FF': 12, + 'LATCH': 13, + 'ASYNC': 14, + 'LSR_OVER_CE': 15, + 'SET': 16, + 'RESET': 17 + } +# DLL +dll_attrids = { + 'CLKSEL': 0, + 'CODESCAL': 1, + 'CODESCALEN': 2, + 'DIVSEL': 3, + 'FORCE': 4, + 'GSR': 5, + 'ROSC': 6, + 'ROUNDOFF': 7, + 'RSTPOL': 8, + 'CLKMUX_SYSCLK': 9 + } + +dll_attrvals = { + 'UNKNOWN': 0, + 'HECLK0': 1, + 'HECLK1': 2, + 'HECLK2': 3, + 'HECLK3': 4, + 'SYSCLK': 5, + 'POS_22': 6, + 'POS_33': 7, + 'POS_44': 8, + 'NEG_11': 9, + 'NEG_22': 10, + 'NEG_33': 11, + 'NEG_44': 12, + 'ENABLE': 13, + 'FAST': 14, + 'DISABLE': 15, + 'NOINV': 16, + 'POS_11': 17, + 'INV': 18 + } + +# PLL +pll_attrids = { + 'BYPCK': 0, + 'BYPCKDIV': 1, + 'BYPCKPS': 2, + 'CLKOUTDIV3': 3, + 'CLKOUTDIV3SEL': 4, + 'CLKOUTDIV': 5, + 'CLKOUTDIVSEL': 6, + 'CLKOUTPS': 7, + 'CRIPPLE': 8, + 'DUTY': 9, + 'DUTYSEL': 10, + 'DPSEL': 11, + 'FBSEL': 12, + 'FDIV': 13, + 'FDIVSEL': 14, + 'FDLYPWD': 15, + 'FLDCOUNT': 16, + 'FLOCK': 17, + 'FLTOP': 18, + 'GMCGAIN': 19, + 'GMCMODE': 20, + 'GMCOUT': 21, + 'GMCVREF': 22, + 'ICPSEL': 23, + 'IDIV': 24, + 'IDIVSEL': 25, + 'INSEL': 26, + 'IRSTEN': 27, + 'KVCO': 28, + 'LPR': 29, + 'ODIV': 30, + 'ODIVSEL': 31, + 'OPDLY': 32, + 'OSDLY': 33, + 'PASEL': 34, + 'PDN': 35, + 'PHASE': 36, + 'PLOCK': 37, + 'PSDLY': 38, + 'PWDEN': 39, + 'RSTEN': 40, + 'RSTLF': 41, + 'SDIV': 42, + 'SELIN': 43, + 'SFTDLY': 44, + 'SRSTEN': 45, + 'CLKMUX_CLKIN2': 46, + 'CLKMUX_CLKIN1': 47, + 'CLKMUX_CLKFB0': 48, + 'PLLVCC0': 49, + 'PLLVCC0_BYPASS': 50, + 'PLLVCC0_TRIM0': 51, + 'PLLVCC0_TRIM1': 52, + 'PLLVCC1': 53, + 'PLLVCC1_BYPASS': 54, + 'PLLVCC1_TRIM0': 55, + 'PLLVCC1_TRIM1': 56, + 'VCOBIAS_EN_D': 57, + 'VCOBIAS_EN_U': 58, + 'DIVA': 59, + 'DIVB': 60, + 'DIVC': 61, + 'DIVD': 62, + 'DPAEN': 63, + 'DUTY_TRIM_A': 64, + 'DUTY_TRIM_B': 65, + 'ICPDYN_SEL': 66, + 'LPR_SEL': 67, + 'INTFB': 68, + 'MON': 69, + 'CKA': 70, + 'CKB': 71, + 'CKC': 72, + 'CKD': 73, + 'CKA_OUT': 74, + 'CKB_OUT': 75, + 'CKC_OUT': 76, + 'CKD_OUT': 77, + 'CKA_IN': 78, + 'CKB_IN': 79, + 'CKC_IN': 80, + 'CKD_IN': 81, + 'PSA_COARSE': 82, + 'PSB_COARSE': 83, + 'PSC_COARSE': 84, + 'PSD_COARSE': 85, + 'PSA_FINE': 86, + 'PSB_FINE': 87, + 'PSC_FINE': 88, + 'PSD_FINE': 89, + 'DTA_SEL': 90, + 'DTB_SEL': 91, + 'PSA_SEL': 92, + 'PSB_SEL': 93, + 'PSC_SEL': 94, + 'PSD_SEL': 95, + 'DIVA_SEL': 96, + 'DIVB_SEL': 97, + 'DIVC_SEL': 98, + 'DIVD_SEL': 99, + 'DTMS_ENA': 100, + 'DTMS_ENB': 101, + 'DTMS_ENC': 102, + 'DTMS_END': 103, + 'VCCREG_TRIM0': 104, + 'VCCREG_TRIM1': 105, + 'PLLREG0': 106, + } +pll_attrvals = { + 'UNKNOWN': 0, + 'BYPASS': 1, + 'DISABLE': 2, + 'ENABLE': 3, + 'CLKOUTPS': 4, + 'C1': 5, + 'C2': 6, + 'C3': 7, + 'DYN': 8, + 'PWD': 9, + 'CLKFB0': 10, + 'CLKFB1': 11, + 'CLKFB2': 12, + 'CLKFB3': 13, + 'CLKFB4': 14, + 'CLKFN0': 15, + 'FORCE0': 16, + 'FORCE1': 17, + 'CLKIN0': 18, + 'CLKIN1': 19, + 'CLKIN2': 20, + 'CLKIN3': 21, + 'CLKIN4': 22, + 'R1': 23, + 'R2': 24, + 'R3': 25, + 'R4': 26, + 'R5': 27, + 'R6': 28, + 'R7': 29, + 'RESET': 30, + 'INV': 31, + '0': 32, + 'P0': 33, + 'P50': 34, + 'P100': 35, + 'P200': 36, + 'M0': 37, + 'M50': 38, + 'M100': 39, + 'M200': 40, + 'CKB': 41, + 'CKC': 42, + 'CKD': 43, + 'VSO': 44, + 'CASCADE': 45, + 'ICLK': 46, + 'FCLK': 47, + 'CLKOUT': 48 + } diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 5f888754..d62b2351 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -1,5 +1,6 @@ from dataclasses import dataclass, field from typing import Dict, List, Set, Tuple, Union, ByteString +from itertools import chain import re from functools import reduce from collections import namedtuple @@ -64,6 +65,10 @@ class Tile: for this specific tile type""" width: int height: int + # At the time of packing/unpacking the information about the types of cells + # is already lost, it is critical to work through the 'logicinfo' table so + # store it. + ttyp: int # a mapping from dest, source wire to bit coordinates pips: Dict[str, Dict[str, Set[Coord]]] = field(default_factory=dict) clock_pips: Dict[str, Dict[str, Set[Coord]]] = field(default_factory=dict) @@ -83,6 +88,15 @@ class Device: cmd_hdr: List[ByteString] = field(default_factory=list) cmd_ftr: List[ByteString] = field(default_factory=list) template: np.ndarray = None + # allowable values of bel attributes + # {table_name: [(attr_id, attr_value)]} + logicinfo: Dict[str, List[Tuple[int, int]]] = field(default_factory=dict) + # fuses for a pair of the "features" (or pairs of parameter values) + # {ttype: {table_name: {(feature_A, feature_B): {bits}}} + shortval: Dict[int, Dict[str, Dict[Tuple[int, int], Set[Coord]]]] = field(default_factory=dict) + # fuses for 16 of the "features" + # {ttype: {table_name: {(feature_0, feature_1, ..., feature_15): {bits}}} + longval: Dict[int, Dict[str, Dict[Tuple[int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int], Set[Coord]]]] = field(default_factory=dict) # always-connected dest, src aliases aliases: Dict[Tuple[int, int, str], Tuple[int, int, str]] = field(default_factory=dict) @@ -145,6 +159,17 @@ def fse_pips(fse, ttyp, table=2, wn=wirenames): return pips +# make PLL bels +def fse_pll(device, fse, ttyp): + bels = {} + # XXX use second grid in order to find PLL ttypes + if device in ['GW1N-1', 'GW1NZ-1']: + if ttyp == 89: + bel = bels.setdefault('RPLLB', Bel()) + else: + bel = bels.setdefault('RPLLA', Bel()) + return bels + # add the ALU mode # new_mode_bits: string like "0110000010011010" def add_alu_mode(base_mode, modes, lut, new_alu_mode, new_mode_bits): @@ -319,6 +344,79 @@ def set_banks(fse, db): for rd in fse[ttyp]['longval'][37]: db.grid[row][col].bels.setdefault(f"BANK{rd[0]}", Bel()) +_known_logic_tables = { + 8: 'DCS', + 9: 'GSR', + 10: 'IOLOGIC', + 11: 'IOB', + 12: 'SLICE', + 13: 'BSRAM', + 14: 'DSP', + 15: 'PLL', + 62: 'USB', + } + +_known_tables = { + 4: 'CONST', + 5: 'LUT', + 21: 'IOLOGICA', + 22: 'IOLOGICB', + 23: 'IOBA', + 24: 'IOBB', + 25: 'CLS0', + 26: 'CLS1', + 27: 'CLS2', + 28: 'CLS3', + 35: 'PLL', + 37: 'BANK', + 40: 'IOBC', + 41: 'IOBD', + 42: 'IOBE', + 43: 'IOBF', + 44: 'IOBG', + 45: 'IOBH', + 46: 'IOBI', + 47: 'IOBJ', + 53: 'DLLDEL0', + 54: 'DLLDEL1', + 56: 'DLL0', + 64: 'USB', + 66: 'EFLASH', + 68: 'ADC', + 80: 'DLL1', + } + +def fse_fill_logic_tables(dev, fse): + # logicinfo + for ltable in fse['header']['logicinfo'].keys(): + if ltable in _known_logic_tables.keys(): + table = dev.logicinfo.setdefault(_known_logic_tables[ltable], []) + else: + table = dev.logicinfo.setdefault(f"unknown_{ltable}", []) + for attr, val, _ in fse['header']['logicinfo'][ltable]: + table.append((attr, val)) + # shortval + ttypes = {t for row in fse['header']['grid'][61] for t in row} + for ttyp in ttypes: + if 'shortval' in fse[ttyp].keys(): + ttyp_rec = dev.shortval.setdefault(ttyp, {}) + for stable in fse[ttyp]['shortval'].keys(): + if stable in _known_tables: + table = ttyp_rec.setdefault(_known_tables[stable], {}) + else: + table = ttyp_rec.setdefault(f"unknown_{stable}", {}) + for f_a, f_b, *fuses in fse[ttyp]['shortval'][stable]: + table[(f_a, f_b)] = {fuse.fuse_lookup(fse, ttyp, f) for f in unpad(fuses)} + if 'longval' in fse[ttyp].keys(): + ttyp_rec = dev.longval.setdefault(ttyp, {}) + for ltable in fse[ttyp]['longval'].keys(): + if ltable in _known_tables: + table = ttyp_rec.setdefault(_known_tables[ltable], {}) + else: + table = ttyp_rec.setdefault(f"unknown_{ltable}", {}) + for f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, *fuses in fse[ttyp]['longval'][ltable]: + table[(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15)] = {fuse.fuse_lookup(fse, ttyp, f) for f in unpad(fuses)} + def from_fse(device, fse): dev = Device() ttypes = {t for row in fse['header']['grid'][61] for t in row} @@ -326,18 +424,65 @@ def from_fse(device, fse): for ttyp in ttypes: w = fse[ttyp]['width'] h = fse[ttyp]['height'] - tile = Tile(w, h) + tile = Tile(w, h, ttyp) tile.pips = fse_pips(fse, ttyp, 2, wirenames) tile.clock_pips = fse_pips(fse, ttyp, 38, clknames) if 5 in fse[ttyp]['shortval']: tile.bels = fse_luts(fse, ttyp) if 51 in fse[ttyp]['shortval']: tile.bels = fse_osc(device, fse, ttyp) + if ttyp in [88, 89]: + tile.bels = fse_pll(device, fse, ttyp) tiles[ttyp] = tile + fse_fill_logic_tables(dev, fse) dev.grid = [[tiles[ttyp] for ttyp in row] for row in fse['header']['grid'][61]] return dev +# get fuses for attr/val set using short/longval table +# returns a bit set +def get_table_fuses(attrs, table): + bits = set() + for key, fuses in table.items(): + # all 16 "features" must be present to be able to use a set of bits from the record + have_full_key = True + for attrval in key: + if attrval == 0: # no "feature" + continue + if attrval > 0: + # this "feature" must present + if attrval not in attrs: + have_full_key = False + break + continue + if attrval < 0: + # this "feature" is set by default and can only be unset + if abs(attrval) in attrs: + have_full_key = False + break + if not have_full_key: + continue + bits.update(fuses) + return bits + +# get fuses for attr/val set using shortval table for ttyp +# returns a bit set +def get_shortval_fuses(dev, ttyp, attrs, table_name): + return get_table_fuses(attrs, dev.shortval[ttyp][table_name]) + +# get fuses for attr/val set using longval table for ttyp +# returns a bit set +def get_longval_fuses(dev, ttyp, attrs, table_name): + return get_table_fuses(attrs, dev.longval[ttyp][table_name]) + +# add the attribute/value pair into an set, which is then passed to +# get_longval_fuses() and get_shortval_fuses() +def add_attr_val(dev, logic_table, attrs, attr, val): + for idx, attr_val in enumerate(dev.logicinfo[logic_table]): + if attr_val[0] == attr and attr_val[1] == val: + attrs.add(idx) + break + def get_pins(device): if device not in {"GW1N-1", "GW1NZ-1", "GW1N-4", "GW1N-9", "GW1NR-9", "GW1N-9C", "GW1NR-9C", "GW1NS-2", "GW1NS-2C", "GW1NS-4", "GW1NSR-4C"}: raise Exception(f"unsupported device {device}") @@ -425,6 +570,16 @@ def json_pinout(device): raise Exception("unsupported device") + +_pll_inputs = [(5, 'CLKFB'), (6, 'FBDSEL0'), (7, 'FBDSEL1'), (8, 'FBDSEL2'), (9, 'FBDSEL3'), + (10, 'FBDSEL4'), (11, 'FBDSEL5'), + (12, 'IDSEL0'), (13, 'IDSEL1'), (14, 'IDSEL2'), (15, 'IDSEL3'), (16, 'IDSEL4'), + (17, 'IDSEL5'), + (18, 'ODSEL0'), (19, 'ODSEL1'), (20, 'ODSEL2'), (21, 'ODSEL3'), (22, 'ODSEL4'), + (24, 'PSDA0'), (25, 'PSDA1'), (26, 'PSDA2'), (27, 'PSDA3'), + (28, 'DUTYDA0'), (29, 'DUTYDA1'), (30, 'DUTYDA2'), (31, 'DUTYDA3'), + (32, 'FDLY0'), (33, 'FDLY1'), (34, 'FDLY2'), (35, 'FDLY3')] +_pll_outputs = [(0, 'CLKOUT'), (1, 'LOCK'), (2, 'CLKOUTP'), (3, 'CLKOUTD'), (4, 'CLKOUTD3')] def dat_portmap(dat, dev): for row in dev.grid: for tile in row: @@ -447,6 +602,28 @@ def dat_portmap(dat, dev): bel.portmap['I'] = out oe = wirenames[dat[f'Iobuf{pin}OE']] bel.portmap['OE'] = oe + elif name.startswith("ODDR"): + d0 = wirenames[dat[f'Iologic{pin}In'][1]] + bel.portmap['D0'] = d0 + d1 = wirenames[dat[f'Iologic{pin}In'][2]] + bel.portmap['D1'] = d1 + tx = wirenames[dat[f'Iologic{pin}In'][27]] + bel.portmap['TX'] = tx + elif name == 'RPLLA': + for idx, nam in _pll_inputs: + wire = wirenames[dat['PllIn'][idx]] + bel.portmap[nam] = wire + for idx, nam in _pll_outputs: + wire = wirenames[dat['PllOut'][idx]] + bel.portmap[nam] = wire + bel.portmap['CLKIN'] = wirenames[124]; + elif name == 'RPLLB': + reset = wirenames[dat['PllIn'][0]] + bel.portmap['RESET'] = reset + reset_p = wirenames[dat['PllIn'][1]] + bel.portmap['RESET_P'] = reset_p + odsel5 = wirenames[dat['PllIn'][23]] + bel.portmap['ODSEL5'] = odsel5 def dat_aliases(dat, dev): for row in dev.grid: @@ -655,3 +832,4 @@ def loc2bank(db, row, col): bank = db.pin_bank[name + 'B'] return bank + diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 44bfaac1..2c738b39 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -3,6 +3,7 @@ import re import pickle import itertools +import math import numpy as np import json import argparse @@ -10,9 +11,15 @@ from collections import namedtuple from apycula import codegen from apycula import chipdb +from apycula.chipdb import add_attr_val, get_shortval_fuses, get_longval_fuses +from apycula import attrids +from apycula.attrids import pll_attrids, pll_attrvals from apycula import bslib +from apycula import attrids from apycula.wirenames import wirenames, wirenumbers +device = "" + _verilog_name = re.compile(r"^[A-Za-z_0-9][A-Za-z_0-9$]*$") def sanitize_name(name): retname = name @@ -28,7 +35,7 @@ def sanitize_name(name): def get_bels(data): later = [] - belre = re.compile(r"R(\d+)C(\d+)_(?:GSR|SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8|ODDR|OSC[ZFH]?|BUFS|RAMW)(\w*)") + belre = re.compile(r"R(\d+)C(\d+)_(?:GSR|SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8|ODDR|OSC[ZFH]?|BUFS|RAMW|RPLL[AB])(\w*)") for cellname, cell in data['modules']['top']['cells'].items(): if cell['type'].startswith('DUMMY_') : continue @@ -68,6 +75,152 @@ def get_pips(data): def infovaluemap(infovalue, start=2): return {tuple(iv[:start]):iv[start:] for iv in infovalue} +# add the default pll attributes according to the documentation +_default_pll_inattrs = { + 'FCLKIN' : '100.00', + 'IDIV_SEL' : '0', + 'DYN_IDIV_SEL' : 'false', + 'FBDIV_SEL' : '00000000000000000000000000000010', # XXX not as in doc + 'DYN_FBDIV_SEL' : 'false', + 'ODIV_SEL' : '00000000000000000000000000001000', + 'DYN_ODIV_SEL' : 'false', + 'PSDA_SEL' : '0000 ', # XXX extra space for compatibility, but it will work with or without it in the future + 'DUTYDA_SEL' : '1000 ', # ^^^ + 'DYN_DA_EN' : 'false', + 'CLKOUT_FT_DIR' : '1', + 'CLKOUT_DLY_STEP': '00000000000000000000000000000000', + 'CLKOUTP_FT_DIR': '1', + 'CLKOUTP_DLY_STEP': '00000000000000000000000000000000', + 'DYN_SDIV_SEL' : '00000000000000000000000000000010', + 'CLKFB_SEL' : 'internal', + 'CLKOUTD_SRC' : 'CLKOUT', + 'CLKOUTD3_SRC' : 'CLKOUT', + 'CLKOUT_BYPASS' : 'false', + 'CLKOUTP_BYPASS': 'false', + 'CLKOUTD_BYPASS': 'false', + 'DEVICE' : 'GW1N-1' + + } + +def add_pll_default_attrs(attrs): + pll_inattrs = attrs.copy() + for k, v in _default_pll_inattrs.items(): + if k in pll_inattrs.keys(): + continue + pll_inattrs[k] = v + return pll_inattrs + +_default_pll_internal_attrs = { + 'INSEL': 'CLKIN1', + 'FBSEL': 'CLKFB3', + 'PLOCK': 'ENABLE', + 'FLOCK': 'ENABLE', + 'FLTOP': 'ENABLE', + 'GMCMODE': 15, + 'CLKOUTDIV3': 'ENABLE', + 'CLKOUTDIV': 'ENABLE', + 'CLKOUTPS': 'ENABLE', + 'PDN': 'ENABLE', + 'PASEL': 0, + 'IRSTEN': 'ENABLE', + 'SRSTEN': 'ENABLE', + 'PWDEN': 'ENABLE', + 'RSTEN': 'ENABLE', + 'FLDCOUNT': 16, + 'GMCGAIN': 0, + 'LPR': 'R4', + 'ICPSEL': 50, +} + +# typ - PLL type (RPLL, etc) +def set_pll_attrs(db, typ, attrs): + pll_inattrs = add_pll_default_attrs(attrs) + pll_attrs = _default_pll_internal_attrs.copy() + pll_attrs['IRSTEN'] = 'DISABLE' + pll_attrs['SRSTEN'] = 'DISABLE' + + if typ not in ['RPLL']: + raise Exception(f"PLL type {typ} is not supported for now") + + # parse attrs + for attr, val in pll_inattrs.items(): + # XXX clock in and feedback in + if attr == 'CLKOUTD_SRC': + if val == 'CLKOUTP': + pll_attrs['CLKOUTDIVSEL'] = 'CLKOUTPS' + continue + if attr == 'CLKOUTD3_SRC': + if val == 'CLKOUTP': + pll_attrs['CLKOUTDIV3SEL'] = 'CLKOUTPS' + continue + # XXX selin + if attr == 'DYN_IDIV_SEL': + if val == 'true': + pll_attrs['IDIVSEL'] = 'DYN' + continue + if attr == 'DYN_FBDIV_SEL': + if val == 'true': + pll_attrs['FDIVSEL'] = 'DYN' + continue + if attr == 'DYN_ODIV_SEL': + if val == 'true': + pll_attrs['ODIVSEL'] = 'DYN' + continue + if attr == 'CLKOUT_BYPASS': + if val == 'true': + pll_attrs['BYPCK'] = 'BYPASS' + continue + if attr == 'CLKOUTP_BYPASS': + if val == 'true': + pll_attrs['BYPCKPS'] = 'BYPASS' + continue + if attr == 'CLKOUTD_BYPASS': + if val == 'true': + pll_attrs['BYPCKDIV'] = 'BYPASS' + continue + if attr == 'IDIV_SEL': + idiv = 1 + int(val, 2) + pll_attrs['IDIV'] = idiv + continue + if attr == 'FBDIV_SEL': + fbdiv = 1 + int(val, 2) + pll_attrs['FDIV'] = fbdiv + continue + if attr == 'DYN_SDIV_SEL': + pll_attrs['SDIV'] = 2 + int(val, 2) + continue + if attr == 'ODIV_SEL': + odiv = int(val, 2) + pll_attrs['ODIV'] = odiv + continue + if attr == 'FCLKIN': + fclkin = float(val) + continue + + # XXX input is 24MHz only and output either 52MHz or 56MHz + # XXX input is 27MHz only and output either 58.5MHz or 63MHz + if device != "GW1N-1" and device != "GW1NZ-1": + raise Exception(f"PLL is not supported") + if (abs(fclkin - 24) > 0.01 and device == "GW1N-1") or (abs(fclkin - 27) > 0.01 and device == "GW1NZ-1"): + raise Exception(f"PLL input frequency {fclkin} is not supported") + if fbdiv == 13 and idiv == 6 and odiv == 8: + pll_attrs['FLDCOUNT'] = 16 + pll_attrs['ICPSEL'] = 20 + pll_attrs['LPR'] = 6 + elif fbdiv == 7 and idiv == 3 and odiv == 8: + pll_attrs['FLDCOUNT'] = 16 + pll_attrs['ICPSEL'] = 40 + pll_attrs['LPR'] = 5 + else: + raise Exception(f"PLL parameters are not supported for now") + + fin_attrs = set() + for attr, val in pll_attrs.items(): + if isinstance(val, str): + val = pll_attrvals[val] + add_attr_val(db, 'PLL', fin_attrs, pll_attrids[attr], val) + return fin_attrs + iostd_alias = { "HSTL18_II" : "HSTL18_I", "SSTL18_I" : "HSTL18_I", @@ -264,9 +417,16 @@ def place(db, tilemap, bels, cst, args): elif typ == "RAMW": bel = tiledata.bels['RAM16'] bits = bel.modes['0'] - print(bits) + #print(typ, bits) for r, c in bits: tile[r][c] = 1 + elif typ.startswith('RPLL'): + pll_attrs = set_pll_attrs(db, 'RPLL', parms) + bits = get_shortval_fuses(db, tiledata.ttyp, pll_attrs, 'PLL') + #print(typ, bits) + for r, c in bits: + tile[r][c] = 1 + else: print("unknown type", typ) @@ -359,6 +519,7 @@ def dualmode_pins(db, tilemap, args): tile[row][col] = 1 def main(): + global device pil_available = True try: from PIL import Image diff --git a/apycula/gowin_unpack.py b/apycula/gowin_unpack.py index 450bc174..82364f70 100644 --- a/apycula/gowin_unpack.py +++ b/apycula/gowin_unpack.py @@ -9,6 +9,7 @@ import importlib.resources from apycula import codegen from apycula import chipdb +from apycula.attrids import pll_attrids, pll_attrvals from apycula.bslib import read_bitstream from apycula.wirenames import wirenames @@ -39,9 +40,114 @@ def _io_mode_sort_func(mode): l += 1 return l +# +def get_attr_name(attrname_table, code): + for name, cod in attrname_table.items(): + if cod == code: + return name + return '' + +# fix names and types of the PLL attributes +# { internal_name: external_name } +_pll_attrs = { + 'IDIV' : 'IDIV_SEL', + 'IDIVSEL' : 'DYN_IDIV_SEL', + 'FDIV' : 'FBDIV_SEL', + 'FDIVSEL' : 'DYN_FBDIV_SEL', + 'ODIV' : 'ODIV_SEL', + 'ODIVSEL' : 'DYN_ODIV_SEL', + 'PHASE' : 'PSDA_SEL', + 'DUTY' : 'DUTYDA_SEL', + 'DPSEL' : 'DYN_DA_EN', + + 'OPDLY' : 'CLKOUT_DLY_STEP', + + 'OSDLY' : 'CLKOUTP_DLY_STEP', + 'SDIV' : 'DYN_SDIV_SEL', + + 'CLKOUTDIVSEL' : 'CLKOUTD_SRC', + 'CLKOUTDIV3SEL' : 'CLKOUTD3_SRC', + 'BYPCK' : 'CLKOUT_BYPASS', + 'BYPCKPS' : 'CLKOUTP_BYPASS', + 'BYPCKDIV' : 'CLKOUTD_BYPASS', + } +def pll_attrs_refine(in_attrs): + res = set() + for attr, val in in_attrs.items(): + if attr not in _pll_attrs.keys(): + continue + attr = _pll_attrs[attr] + new_val = f'"{val}"' + if attr in ['CLKOUTP_DLY_STEP', 'CLKOUT_DLY_STEP']: + new_val = val / 50 + elif attr in ['PSDA_SEL', 'DUTYDA_SEL']: + new_val = f'"{val:04b}"' + elif attr in ['IDIV_SEL', 'FBDIV_SEL']: + new_val = val - 1 + elif attr == 'DYN_SDIV_SEL': + new_val = val - 2 + elif attr == 'ODIV_SEL': + new_val = val + res.add(f'{attr}={new_val}') + return res + +# parse attributes and values use 'logicinfo' table +# returns {attr: value} +# attribute names are decoded with the attribute table, but the values are returned in raw form +def parse_attrvals(tile, logicinfo_table, fuse_table, attrname_table): + def is_neg_key(key): + for k in key: + if k < 0: + return True + return False + + def is_pos_key(key): + return not is_neg_key(key) + + res = {} + set_mask = set() + zero_mask = set() + # collect masks + for av, bits in fuse_table.items(): + if is_neg_key(av): + zero_mask.update(bits) + else: + set_mask.update(bits) + set_bits = {(row, col) for row, col in set_mask if tile[row][col] == 1} + zero_bits = {(row, col) for row, col in set_mask if tile[row][col] == 0} + # find candidates from fuse table + attrvals = set() + for raw_bits, test_fn in [(zero_bits, is_neg_key), (set_bits, is_pos_key)]: + cnd = { av: bits for av, bits in fuse_table.items() if test_fn(av) and bits.issubset(raw_bits)} + for av, bits in cnd.items(): + keep = True + for bt in cnd.values(): + if bits != bt and bits.issubset(bt): + keep = False + break + if keep: + attrvals.add(av) + + for key in attrvals: + for av in [a for a in key if a != 0]: + attr, val = logicinfo_table[av] + res[get_attr_name(attrname_table, attr)] = val + return res + +# { (row, col, type) : idx} +# type 'A'| 'B' +_pll_cells = {} + +# returns the A cell of the PLL +def get_pll_A(db, row, col, typ): + if typ == 'B': + col -= 1 + return row, col, 'A' + # noiostd --- this is the case when the function is called # with iostd by default, e.g. from the clock fuzzer # With normal gowin_unpack io standard is determined first and it is known. +# (bels, pips, clock_pips) def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True): # TLVDS takes two BUF bels, so skip the B bels. skip_bels = set() @@ -50,7 +156,15 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True) clock_pips = {} bels = {} for name, bel in tiledata.bels.items(): - if name[0:3] == "IOB": + if name.startswith("RPLL"): + idx = _pll_cells.setdefault(get_pll_A(db, row, col, name[4]), len(_pll_cells)) + attrvals = pll_attrs_refine(parse_attrvals(tile, db.logicinfo['PLL'], db.shortval[tiledata.ttyp]['PLL'], pll_attrids)) + modes = bels.setdefault(f'{name}{idx}', set()) + for attrval in attrvals: + modes.add(attrval) + print(idx, modes) + continue + if name.startswith("IOB"): #print(name) if noiostd: iostd = '' @@ -153,7 +267,6 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True) return {name: bel for name, bel in bels.items() if name not in skip_bels}, pips, clock_pips - dffmap = { "DFF": None, "DFFN": None, @@ -280,7 +393,7 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cst, db): mod.wires.update({srcg, destg}) mod.assigns.append((destg, srcg)) - belre = re.compile(r"(IOB|LUT|DFF|BANK|CFG|ALU|RAM16|ODDR|OSC[ZFH]?|BUFS)(\w*)") + belre = re.compile(r"(IOB|LUT|DFF|BANK|CFG|ALU|RAM16|ODDR|OSC[ZFH]?|BUFS|RPLL[AB])(\w*)") if have_iologic(bels): bels_items = move_iologic(bels) else: @@ -307,6 +420,16 @@ def tile2verilog(dbrow, dbcol, bels, pips, clock_pips, mod, cst, db): mod.primitives[name] = lut cst.cells[name] = (row, col, int(idx) // 2, _sides[int(idx) % 2]) make_muxes(row, col, idx, db, mod) + elif typ.startswith("RPLL"): + name = f"PLL_{idx}" + pll = mod.primitives.setdefault(name, codegen.Primitive("rPLL", name)) + for paramval in flags: + param, _, val = paramval.partition('=') + pll.params[param] = val + portmap = db.grid[dbrow][dbcol].bels[bel[:-1]].portmap + for port, wname in portmap.items(): + pll.portmap[port] = f"R{row}C{col}_{wname}" + mod.wires.update(pll.portmap.values()) elif typ == "ALU": #print(flags) kind, = flags # ALU only have one flag diff --git a/examples/Makefile b/examples/Makefile index bec1d108..f0e2e39e 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -21,7 +21,8 @@ all: attosoc-tec0117.fs nanolcd-tangnano.fs blinky-tec0117.fs blinky-runber.fs \ blinky-osc-tangnano9k.fs blinky-osc-tangnano1k.fs blinky-osc-tangnano4k.fs \ blinky-lw-tangnano.fs blinky-lw-tangnano1k.fs blinky-lw-tangnano4k.fs blinky-lw-tangnano9k.fs \ blinky-lw-honeycomb.fs blinky-lw-tec0117.fs blinky-lw-runber.fs \ - globals_all + globals_all \ + pll-tangnano.fs pll-tangnano1k.fs unpacked: attosoc-tec0117-unpacked.v nanolcd-tangnano-unpacked.v blinky-tec0117-unpacked.v blinky-runber-unpacked.v \ blinky-tangnano-unpacked.v blinky-honeycomb-unpacked.v shift-tec0117-unpacked.v shift-runber-unpacked.v \ @@ -114,10 +115,10 @@ nanolcd-tangnano-synth.json: nanolcd/TOP.v nanolcd/VGAMod.v $(YOSYS) -D LEDS_NR=8 -D OSC_TYPE_OSC -p "read_verilog $^; synth_gowin -json $@" %-tangnano-synth.json: %.v - $(YOSYS) -D LEDS_NR=3 -D OSC_TYPE_OSCH -p "read_verilog $^; synth_gowin -json $@" + $(YOSYS) -D LEDS_NR=3 -D OSC_TYPE_OSCH -p "read_verilog pll/GW1N-1.vh $^; synth_gowin -json $@" %-tangnano1k-synth.json: %.v - $(YOSYS) -D LEDS_NR=3 -D OSC_TYPE_OSCZ -p "read_verilog $^; synth_gowin -json $@" + $(YOSYS) -D LEDS_NR=3 -D OSC_TYPE_OSCZ -p "read_verilog pll/GW1NZ-1.vh $^; synth_gowin -json $@" %-tangnano4k-synth.json: %.v $(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSCZ -p "read_verilog $^; synth_gowin -json $@" diff --git a/examples/pll.v b/examples/pll.v new file mode 100644 index 00000000..83a8b65b --- /dev/null +++ b/examples/pll.v @@ -0,0 +1,48 @@ +module top(input wire clk, output wire [`LEDS_NR-1:0]led); + wire VCC; + wire GND; + wire [2:0]dummy; + assign VCC = 1'b1; + assign GND = 1'b0; + rPLL pll( + .CLKOUT(led[0]), // connect an oscilloscope here + .CLKIN(clk), + .CLKOUTP(dummy[0]), + .CLKOUTD(dummy[1]), + .CLKOUTD3(dummy[2]), + .LOCK(led[1]), // this LED lights up when the PLL lock is triggered + .CLKFB(GND), + .FBDSEL({GND,GND,GND,GND,GND,GND}), + .IDSEL({GND,GND,GND,GND,GND,GND}), + .ODSEL({VCC,GND,GND,GND,GND,GND}), + .DUTYDA({GND,GND,GND,GND}), + .PSDA({GND,GND,GND,GND}), + .FDLY({GND,GND,GND,GND}), + .RESET(GND), + .RESET_P(GND) + ); + defparam pll.DEVICE = `PLL_DEVICE; + defparam pll.FCLKIN = `PLL_FCLKIN; + defparam pll.FBDIV_SEL = `PLL_FBDIV_SEL; + defparam pll.IDIV_SEL = `PLL_IDIV_SEL; + defparam pll.ODIV_SEL = `PLL_ODIV_SEL; + defparam pll.CLKFB_SEL="internal"; + defparam pll.CLKOUTD3_SRC="CLKOUT"; + defparam pll.CLKOUTD_BYPASS="false"; + defparam pll.CLKOUTD_SRC="CLKOUT"; + defparam pll.CLKOUTP_BYPASS="false"; + defparam pll.CLKOUTP_DLY_STEP=0; + defparam pll.CLKOUTP_FT_DIR=1'b1; + defparam pll.CLKOUT_BYPASS="false"; + defparam pll.CLKOUT_DLY_STEP=0; + defparam pll.CLKOUT_FT_DIR=1'b1; + defparam pll.DEVICE="GW1N-1"; + defparam pll.DUTYDA_SEL="1000"; + defparam pll.DYN_DA_EN="false"; + defparam pll.DYN_FBDIV_SEL="false"; + defparam pll.DYN_IDIV_SEL="false"; + defparam pll.DYN_ODIV_SEL="false"; + defparam pll.DYN_SDIV_SEL=2; + defparam pll.PSDA_SEL="0000"; +endmodule + diff --git a/examples/pll/GW1N-1.vh b/examples/pll/GW1N-1.vh new file mode 100644 index 00000000..cb32733b --- /dev/null +++ b/examples/pll/GW1N-1.vh @@ -0,0 +1,6 @@ +`define PLL_DEVICE "GW1N-1" +`define PLL_FCLKIN "24" +`define PLL_FBDIV_SEL 12 // 52 MHz (12, 5, 8) 56 MHz (6, 2, 8) +`define PLL_IDIV_SEL 5 +`define PLL_ODIV_SEL 8 + diff --git a/examples/pll/GW1NZ-1.vh b/examples/pll/GW1NZ-1.vh new file mode 100644 index 00000000..d571d6dc --- /dev/null +++ b/examples/pll/GW1NZ-1.vh @@ -0,0 +1,6 @@ +`define PLL_DEVICE "GW1NZ-1" +`define PLL_FCLKIN "27" +`define PLL_FBDIV_SEL 12 // 58.5 MHz (12, 5, 8) 63 MHz (6, 2, 8) +`define PLL_IDIV_SEL 5 +`define PLL_ODIV_SEL 8 +