From 6d9ca9ca504c1efd5ed15c27cae3105bd3e5ac85 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 26 Jan 2023 22:38:41 +1000 Subject: [PATCH] Add support for GW1NR-9C PLL * Both PLLs with all attributes are supported; * Static and dynamic setting of generated frequencies; * New approach to handling multi-cell primitives: now all ports scattered over cells are represented by aliases to the main cell, auxiliary cells are simply ignored in nextpnr; * A mechanism for describing ports located in auxiliary cells was discovered. Signed-off-by: YRabbit --- apycula/chipdb.py | 79 +++++++++++++++++++++++++------------ apycula/clock_fuzzer.py | 2 + apycula/gowin_pack.py | 26 ++++++++++-- apycula/gowin_unpack.py | 37 +++++++++++------ examples/Makefile | 23 ++++++++--- examples/pll-nanolcd/TOP.v | 13 +++--- examples/pll.v | 60 +++++++++++----------------- examples/pll/GW1N-1-dyn.vh | 2 + examples/pll/GW1N-9C-dyn.vh | 22 +++++++++++ examples/pll/pllvr.v | 63 +++++++++++++++++++++++++++++ examples/pll/rpll.v | 72 +++++++++++++++++++++++++++++++++ examples/pll2.v | 72 +++++++++++++++++++++++++++++++++ examples/tangnano9k.cst | 23 +++++++++++ 13 files changed, 403 insertions(+), 91 deletions(-) create mode 100644 examples/pll/GW1N-9C-dyn.vh create mode 100644 examples/pll/pllvr.v create mode 100644 examples/pll/rpll.v create mode 100644 examples/pll2.v diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 582f003e..2b1c86ce 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -178,13 +178,18 @@ def fse_alonenode(fse, ttyp, table = 6): def fse_pll(device, fse, ttyp): bels = {} if device in {'GW1N-1', 'GW1NZ-1'}: - if ttyp == 89: - bel = bels.setdefault('RPLLB', Bel()) - else: + if ttyp == 88: bel = bels.setdefault('RPLLA', Bel()) + elif ttyp == 89: + bel = bels.setdefault('RPLLB', Bel()) elif device in {'GW1NS-4'}: if ttyp in {88, 89}: bel = bels.setdefault('PLLVR', Bel()) + elif device in {'GW1N-9C'}: + if ttyp in {86, 87}: + bel = bels.setdefault('RPLLA', Bel()) + elif ttyp in {74, 75, 76, 77, 78, 79}: + bel = bels.setdefault('RPLLB', Bel()) return bels # add the ALU mode @@ -444,11 +449,17 @@ def fse_fill_logic_tables(dev, fse): {'TRPLL0CLK0': (0, 17, 'F4'), 'TRPLL0CLK1': (0, 17, 'F5'), 'TRPLL0CLK2': (0, 17, 'F6'), 'TRPLL0CLK3': (0, 17, 'F7'), }, 'GW1NS-4': - {'TLPLL0CLK0': (0, 27, 'F4'), 'TLPLL0CLK1': (0, 27, 'F5'), - 'TLPLL0CLK2': (0, 27, 'F6'), 'TLPLL0CLK3': (0, 27, 'F7'), - 'TRPLL0CLK0': (0, 36, 'F4'), 'TRPLL0CLK1': (0, 36, 'F5'), - 'TRPLL0CLK2': (0, 36, 'F6'), 'TRPLL0CLK3': (0, 36, 'F7'), }, + {'TLPLL0CLK0': (0, 27, 'F4'), 'TLPLL0CLK1': (0, 27, 'F7'), + 'TLPLL0CLK2': (0, 27, 'F6'), 'TLPLL0CLK3': (0, 27, 'F5'), + 'TRPLL0CLK0': (0, 36, 'F4'), 'TRPLL0CLK1': (0, 36, 'F7'), + 'TRPLL0CLK2': (0, 36, 'F6'), 'TRPLL0CLK3': (0, 36, 'F5'), }, + 'GW1N-9C': + {'TLPLL0CLK0': (9, 2, 'F4'), 'TLPLL0CLK1': (9, 2, 'F7'), + 'TLPLL0CLK2': (9, 2, 'F5'), 'TLPLL0CLK3': (9, 2, 'F6'), + 'TRPLL0CLK0': (9, 44, 'F4'), 'TRPLL0CLK1': (9, 44, 'F7'), + 'TRPLL0CLK2': (9, 44, 'F5'), 'TRPLL0CLK3': (9, 44, 'F6'), }, } + def fse_create_pll_clock_aliases(db, device): # we know exactly where the PLL is and therefore know which aliases to create for row in range(db.rows): @@ -456,7 +467,7 @@ def fse_create_pll_clock_aliases(db, device): for w_dst, w_srcs in db.grid[row][col].clock_pips.items(): for w_src in w_srcs.keys(): # XXX - if device in {'GW1N-1', 'GW1NZ-1', 'GW1NS-4'}: + if device in {'GW1N-1', 'GW1NZ-1', 'GW1NS-4', 'GW1N-9C'}: if w_src in _pll_loc[device].keys(): db.aliases[(row, col, w_src)] = _pll_loc[device][w_src] @@ -476,7 +487,7 @@ def from_fse(device, fse): if 51 in fse[ttyp]['shortval']: tile.bels = fse_osc(device, fse, ttyp) # XXX GW1N(Z)-1 and GW1NS-4 for now - if ttyp in [88, 89]: + if ttyp in [74, 75, 76, 77, 78, 79, 86, 87, 88, 89]: tile.bels = fse_pll(device, fse, ttyp) tiles[ttyp] = tile @@ -622,6 +633,7 @@ def json_pinout(device): (12, 'IDSEL0'), (13, 'IDSEL1'), (14, 'IDSEL2'), (15, 'IDSEL3'), (16, 'IDSEL4'), (17, 'IDSEL5'), (18, 'ODSEL0'), (19, 'ODSEL1'), (20, 'ODSEL2'), (21, 'ODSEL3'), (22, 'ODSEL4'), + (23, 'ODSEL5'), (0, 'RESET'), (1, 'RESET_P'), (24, 'PSDA0'), (25, 'PSDA1'), (26, 'PSDA2'), (27, 'PSDA3'), (28, 'DUTYDA0'), (29, 'DUTYDA1'), (30, 'DUTYDA2'), (31, 'DUTYDA3'), (32, 'FDLY0'), (33, 'FDLY1'), (34, 'FDLY2'), (35, 'FDLY3')] @@ -656,20 +668,41 @@ def dat_portmap(dat, dev, device): tx = wirenames[dat[f'Iologic{pin}In'][27]] bel.portmap['TX'] = tx elif name == 'RPLLA': + # The PllInDlt table seems to indicate in which cell the + # inputs are actually located. + offx = 1 + if device in {'GW1N-9C'}: + # two mirrored PLLs + if col > dat['center'][1] - 1: + offx = -1 for idx, nam in _pll_inputs: wire = wirenames[dat['PllIn'][idx]] - bel.portmap[nam] = wire + off = dat['PllInDlt'][idx] * offx + if off == 0: + bel.portmap[nam] = wire + else: + # not our cell, make an alias + bel.portmap[nam] = f'rPLL{nam}{wire}' + dev.aliases[row, col, f'rPLL{nam}{wire}'] = (row, col + off, wire) for idx, nam in _pll_outputs: wire = wirenames[dat['PllOut'][idx]] + off = dat['PllOutDlt'][idx] * offx + if off == 0: + bel.portmap[nam] = wire + else: + # not our cell, make an alias + bel.portmap[nam] = f'rPLL{nam}{wire}' + dev.aliases[row, col, f'rPLL{nam}{wire}'] = (row, col + off, wire) + # clock input + nam = 'CLKIN' + wire = wirenames[dat['PllClkin'][1][0]] + off = dat['PllClkin'][1][1] * offx + if off == 0: 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 + else: + # not our cell, make an alias + bel.portmap[nam] = f'rPLL{nam}{wire}' + dev.aliases[row, col, f'rPLL{nam}{wire}'] = (row, col + off, wire) elif name == 'PLLVR': pll_idx = 0 if col != 27: @@ -686,19 +719,13 @@ def dat_portmap(dat, dev, device): # you should keep in mind that nextpnr is designed # so that it will not use such aliases. They have # to be taken care of separately. - bel.portmap[nam] = f'PLLVR{wire}' - dev.aliases[row, col, f'PLLVR{wire}'] = (9, 37, wire) + bel.portmap[nam] = f'PLLVR{nam}{wire}' + dev.aliases[row, col, f'PLLVR{nam}{wire}'] = (9, 37, wire) for idx, nam in _pll_outputs: wire = wirenames[dat[f'SpecPll{pll_idx}Outs'][idx * 3 + 2]] bel.portmap[nam] = wire bel.portmap['CLKIN'] = wirenames[124]; reset = wirenames[dat[f'SpecPll{pll_idx}Ins'][0 + 2]] - bel.portmap['RESET'] = reset - reset_p = wirenames[dat[f'SpecPll{pll_idx}Ins'][1 * 3 + 2]] - bel.portmap['RESET_P'] = reset_p - odsel5 = wirenames[dat[f'SpecPll{pll_idx}Ins'][23 * 3 + 2]] - bel.portmap['ODSEL5'] = f'PLLVR{odsel5}' - dev.aliases[row, col, f'PLLVR{odsel5}'] = (9, 37, odsel5) # VREN pin is placed in another cell if pll_idx == 0: vren = 'D0' diff --git a/apycula/clock_fuzzer.py b/apycula/clock_fuzzer.py index 6d6277ae..c19f7c9f 100644 --- a/apycula/clock_fuzzer.py +++ b/apycula/clock_fuzzer.py @@ -269,6 +269,8 @@ def add_rim(rows, cols, spine_row): rows.add(0) if tiled_fuzzer.device.startswith("GW1N-9"): rows.add(9) + else: + rows.add(spine_row - 1) if max(rows) > spine_row and spine_row != 1: rows.update({row for row in range(max(rows) + 1, db.rows)}) if tiled_fuzzer.device.startswith("GW1N-9"): diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 902bd527..acfd623c 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -33,9 +33,23 @@ def sanitize_name(name): return retname return f"\{retname} " +def extra_pll_bels(cell, row, col, num, cellname): + # rPLL can occupy several cells, add them depending on the chip + offx = 1; + if device == 'GW1N-9C': + if int(col) > 28: + offx = -1 + for off in [1, 2, 3]: + yield ('RPLLB', int(row), int(col) + offx * off, num, + cell['parameters'], cell['attributes'], sanitize_name(cellname) + f'B{off}') + elif device in {'GW1N-1', 'GW1NZ-1'}: + for off in [1]: + yield ('RPLLB', int(row), int(col) + offx * off, num, + cell['parameters'], cell['attributes'], sanitize_name(cellname) + f'B{off}') + 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|RPLL[AB]|PLLVR)(\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|PLLVR)(\w*)") for cellname, cell in data['modules']['top']['cells'].items(): if cell['type'].startswith('DUMMY_') : continue @@ -51,7 +65,11 @@ def get_bels(data): if 'DIFF' in cell['attributes'].keys(): later.append((cellname, cell, row, col, num)) continue - yield (cell['type'], int(row), int(col), num, + cell_type = cell['type'] + if cell_type == 'rPLL': + cell_type = 'RPLLA' + yield from extra_pll_bels(cell, row, col, num, cellname) + yield (cell_type, int(row), int(col), num, cell['parameters'], cell['attributes'], sanitize_name(cellname)) # diff iobs @@ -507,7 +525,9 @@ def place(db, tilemap, bels, cst, args): tile[r][c] = 1 elif typ.startswith('RPLL'): pll_attrs = set_pll_attrs(db, 'RPLL', 0, parms) - bits = get_shortval_fuses(db, tiledata.ttyp, pll_attrs, 'PLL') + bits = set() + if 'PLL' in db.shortval[tiledata.ttyp].keys(): + bits = get_shortval_fuses(db, tiledata.ttyp, pll_attrs, 'PLL') #print(typ, bits) for r, c in bits: tile[r][c] = 1 diff --git a/apycula/gowin_unpack.py b/apycula/gowin_unpack.py index 7fdffecc..4e11e85a 100644 --- a/apycula/gowin_unpack.py +++ b/apycula/gowin_unpack.py @@ -13,6 +13,7 @@ from apycula.bslib import read_bitstream from apycula.wirenames import wirenames +_device = "" _pinout = "" _packages = { 'GW1N-1' : 'LQFP144', 'GW1NZ-1' : 'QFN48', 'GW1N-4' : 'PBGA256', 'GW1N-9C' : 'UBGA332', @@ -161,7 +162,13 @@ def is_pos_key(key): # GW1N(Z)-1 def get_pll_A(db, row, col, typ): if typ == 'B': - col -= 1 + if _device in {"GW1N-9C"}: + if col > 28: + col = db.cols - 1 + else: + col = 0 + else: + col -= 1 return row, col, 'A' # noiostd --- this is the case when the function is called @@ -178,17 +185,18 @@ def parse_tile_(db, row, col, tile, default=True, noalias=False, noiostd = True) for name, bel in tiledata.bels.items(): 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 = set() - for attrval in attrvals: - modes.add(attrval) + modes = { f'DEVICE="{_device}"' } + if 'PLL' in db.shortval[tiledata.ttyp].keys(): + attrvals = pll_attrs_refine(parse_attrvals(tile, db.logicinfo['PLL'], db.shortval[tiledata.ttyp]['PLL'], pll_attrids)) + for attrval in attrvals: + modes.add(attrval) if modes: bels[f'{name}{idx}'] = modes continue if name == "PLLVR": idx = _pll_cells.setdefault(get_pll_A(db, row, col, 'A'), len(_pll_cells)) attrvals = pll_attrs_refine(parse_attrvals(tile, db.logicinfo['PLL'], db.shortval[tiledata.ttyp]['PLL'], pll_attrids)) - modes = set() + modes = { f'DEVICE="{_device}"' } for attrval in attrvals: modes.add(attrval) if modes: @@ -743,25 +751,32 @@ def main(): args = parser.parse_args() - device = args.device + global _device + _device = args.device # For tool integration it is allowed to pass a full part number - m = re.match("GW1N(S?)[A-Z]*-(LV|UV|UX)([0-9])C?([A-Z]{2}[0-9]+P?)(C[0-9]/I[0-9])", device) + m = re.match("GW1N(S?)[A-Z]*-(LV|UV|UX)([0-9])C?([A-Z]{2}[0-9]+P?)(C[0-9]/I[0-9])", _device) if m: mods = m.group(1) luts = m.group(3) - device = f"GW1N{mods}-{luts}" + _device = f"GW1N{mods}-{luts}" - with importlib.resources.open_binary("apycula", f"{device}.pickle") as f: + with importlib.resources.open_binary("apycula", f"{_device}.pickle") as f: db = pickle.load(f) global _pinout - _pinout = db.pinout[device][_packages[device]] + _pinout = db.pinout[_device][_packages[_device]] bitmap = read_bitstream(args.bitstream)[0] bm = chipdb.tile_bitmap(db, bitmap) mod = codegen.Module() cst = codegen.Constraints() + # XXX this PLLs have empty main cell + if _device in {'GW1N-9C'}: + bm_pll = chipdb.tile_bitmap(db, bitmap, empty = True) + bm[(9, 0)] = bm_pll[(9, 0)] + bm[(9, 46)] = bm_pll[(9, 46)] + for (drow, dcol, dname), (srow, scol, sname) in db.aliases.items(): src = f"R{srow+1}C{scol+1}_{sname}" dest = f"R{drow+1}C{dcol+1}_{dname}" diff --git a/examples/Makefile b/examples/Makefile index 2a32e44e..25e0f800 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -19,7 +19,8 @@ all: attosoc-tec0117.fs nanolcd-tangnano.fs blinky-tec0117.fs blinky-runber.fs \ pll-52-tangnano.fs pll-80-tangnano.fs \ pll-54-tangnano1k.fs pll-81-tangnano1k.fs \ pll-dyn-tangnano.fs pll-dyn-tangnano1k.fs \ - pll-nanolcd-tangnano.fs pll-tangnano4k.fs + pll-tangnano4k.fs pll2-tangnano9k.fs \ + pll-nanolcd-tangnano.fs pll-nanolcd-tangnano9k.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 \ @@ -38,7 +39,8 @@ unpacked: attosoc-tec0117-unpacked.v nanolcd-tangnano-unpacked.v blinky-tec0117- pll-52-tangnano-unpacked.v pll-80-tangnano-unpacked.v \ pll-54-tangnano1k-unpacked.v pll-81-tangnano1k-unpacked.v \ pll-dyn-tangnano-unpacked.v pll-dyn-tangnano1k-unpacked.v \ - pll-nanolcd-tangnano-unpacked.v pll-tangnano4k-unpacked.v + pll2-tangnano9k-unpacked.v \ + pll-nanolcd-tangnano-unpacked.v pll-nanolcd-tangnano9k-unpacked.v pll-tangnano4k-unpacked.v clean: rm -f *.json *.fs *-unpacked.v @@ -84,6 +86,9 @@ pll-tangnano4k.json: pll-tangnano4k-synth.json tangnano4k.cst %-tangnano9k.fs: %-tangnano9k.json gowin_pack -d GW1N-9C -o $@ $^ +pll-nanolcd-tangnano9k.fs: pll-nanolcd-tangnano9k.json + gowin_pack -d GW1N-9C --sspi_as_gpio --mspi_as_gpio -o $@ $^ + %-tangnano9k.json: %-tangnano9k-synth.json tangnano9k.cst $(NEXTPNR) --json $< --write $@ --device GW1NR-LV9QN88PC6/I5 --family GW1N-9C --cst tangnano9k.cst @@ -108,7 +113,13 @@ tonegen-tec0117-synth.json: tonegen/top.v tonegen/sddac.v tonegen/cordic.v nanolcd-tangnano-synth.json: nanolcd/TOP.v nanolcd/VGAMod.v $(YOSYS) -p "read_verilog $^; synth_gowin -json $@" -pll-nanolcd-tangnano-synth.json: pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v +pll-nanolcd-tangnano-synth.json: pll/GW1N-1-dyn.vh pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v + $(YOSYS) -p "read_verilog $^; synth_gowin -noalu -json $@" + +pll-nanolcd-tangnano9k-synth.json: pll/GW1N-9C-dyn.vh pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v + $(YOSYS) -p "read_verilog $^; synth_gowin -noalu -json $@" + +pll2-tangnano9k-synth.json: pll/GW1N-9C-dyn.vh pll2.v pll/rpll.v $(YOSYS) -p "read_verilog $^; synth_gowin -noalu -json $@" %-tec0117-synth.json: %.v @@ -117,10 +128,10 @@ pll-nanolcd-tangnano-synth.json: pll-nanolcd/TOP.v pll-nanolcd/VGAMod.v %-runber-synth.json: %.v $(YOSYS) -D LEDS_NR=8 -D OSC_TYPE_OSC -p "read_verilog $^; synth_gowin -json $@" -pll-%-tangnano-synth.json: pll/GW1N-1-%.vh pll.v +pll-%-tangnano-synth.json: pll/GW1N-1-%.vh pll.v pll/rpll.v $(YOSYS) -D LEDS_NR=3 -p "read_verilog $^; synth_gowin -json $@" -pll-%-tangnano1k-synth.json: pll/GW1NZ-1-%.vh pll.v +pll-%-tangnano1k-synth.json: pll/GW1NZ-1-%.vh pll.v pll/rpll.v $(YOSYS) -D LEDS_NR=3 -p "read_verilog $^; synth_gowin -json $@" %-tangnano-synth.json: %.v @@ -132,7 +143,7 @@ pll-%-tangnano1k-synth.json: pll/GW1NZ-1-%.vh pll.v %-tangnano4k-synth.json: %.v $(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSCZ -p "read_verilog $^; synth_gowin -json $@" -pll-tangnano4k-synth.json: pll-tangnano4k.v pllvr.v +pll-tangnano4k-synth.json: pll-tangnano4k.v pll/pllvr.v $(YOSYS) -D LEDS_NR=6 -D OSC_TYPE_OSCZ -p "read_verilog $^; synth_gowin -json $@" %-tangnano9k-synth.json: %.v diff --git a/examples/pll-nanolcd/TOP.v b/examples/pll-nanolcd/TOP.v index f74c5be2..ba4c7f8c 100644 --- a/examples/pll-nanolcd/TOP.v +++ b/examples/pll-nanolcd/TOP.v @@ -30,19 +30,19 @@ module TOP rPLL pll( .CLKOUT(CLK_SYS), // 90MHz .CLKIN(clk), - .CLKOUTD(CLK_PIX), + .CLKOUTD(CLK_PIX), // 9MHz .CLKFB(GND), .FBDSEL({GND,GND,GND,GND,GND,GND}), .IDSEL({GND,GND,GND,GND,GND,GND}), .ODSEL({GND,GND,GND,GND,GND,GND}), .DUTYDA({GND,GND,GND,GND}), .PSDA({GND,GND,GND,GND}), - .FDLY({GND,GND,GND,GND}), + .FDLY({GND,GND,GND,GND}) ); - defparam pll.DEVICE = "GW1N-1"; - defparam pll.FCLKIN = "24"; - defparam pll.FBDIV_SEL = 29; - defparam pll.IDIV_SEL = 7; + defparam pll.DEVICE = `PLL_DEVICE; + defparam pll.FCLKIN = `PLL_FCLKIN; + defparam pll.FBDIV_SEL = `PLL_FBDIV_SEL_LCD; + defparam pll.IDIV_SEL = `PLL_IDIV_SEL_LCD; defparam pll.ODIV_SEL = 8; // 90MHz sys clock defparam pll.CLKFB_SEL="internal"; defparam pll.CLKOUTD3_SRC="CLKOUT"; @@ -54,7 +54,6 @@ rPLL pll( 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"; diff --git a/examples/pll.v b/examples/pll.v index 4f42eaf2..e805d173 100644 --- a/examples/pll.v +++ b/examples/pll.v @@ -14,48 +14,32 @@ module top(input wire clk, input wire key, output wire [`LEDS_NR-1:0]led); wire [5:0]idiv; assign idiv = 6'd0; `endif - rPLL pll( - .CLKOUT(led[0]), // connect an oscilloscope here. main freq - .CLKIN(clk), - .CLKOUTD(led[2]), // freq / SDIV = freq / 124 - .LOCK(led[1]), // this LED lights up when the PLL lock is triggered - .CLKFB(GND), - .FBDSEL(fdiv), - .IDSEL(idiv), - .ODSEL({GND,GND,GND,GND,GND,GND}), - .DUTYDA({GND,GND,GND,GND}), - .PSDA({GND,GND,GND,GND}), - .FDLY({GND,GND,GND,GND}), - .RESET(reset), + Gowin_rPLL pll0( + .clkout(led[0]), // connect an oscilloscope here. main freq + .clkfb(GND), + .clkin(clk), + .clkoutd_o(led[2]), // freq / SDIV = freq / 124 + .lock_o(led[1]), // this LED lights up when the PLL lock is triggered + .fdiv(fdiv), + .idiv(idiv), + .reset(reset), + .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="CLKOUTP"; - 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 pll0.DEVICE = `PLL_DEVICE; + defparam pll0.FCLKIN = `PLL_FCLKIN; + defparam pll0.FBDIV_SEL = `PLL_FBDIV_SEL; + defparam pll0.IDIV_SEL = `PLL_IDIV_SEL; + defparam pll0.ODIV_SEL = `PLL_ODIV_SEL; `ifdef PLL_DYN - defparam pll.DYN_FBDIV_SEL="true"; - defparam pll.DYN_IDIV_SEL="true"; + defparam pll0.DYN_FBDIV_SEL="true"; + defparam pll0.DYN_IDIV_SEL="true"; `else - defparam pll.DYN_FBDIV_SEL="false"; - defparam pll.DYN_IDIV_SEL="false"; + defparam pll0.DYN_FBDIV_SEL="false"; + defparam pll0.DYN_IDIV_SEL="false"; `endif - defparam pll.DYN_ODIV_SEL="false"; - defparam pll.DYN_SDIV_SEL=124; - defparam pll.PSDA_SEL="0000"; + defparam pll0.DYN_ODIV_SEL="false"; + defparam pll0.DYN_SDIV_SEL=124; + defparam pll0.PSDA_SEL="0000"; // dynamic `ifdef PLL_DYN diff --git a/examples/pll/GW1N-1-dyn.vh b/examples/pll/GW1N-1-dyn.vh index cb321202..ce0347d5 100644 --- a/examples/pll/GW1N-1-dyn.vh +++ b/examples/pll/GW1N-1-dyn.vh @@ -9,3 +9,5 @@ `define PLL_FBDIV_SEL_1 9 `define PLL_IDIV_SEL_1 2 +`define PLL_FBDIV_SEL_LCD 29 +`define PLL_IDIV_SEL_LCD 7 diff --git a/examples/pll/GW1N-9C-dyn.vh b/examples/pll/GW1N-9C-dyn.vh new file mode 100644 index 00000000..6c262089 --- /dev/null +++ b/examples/pll/GW1N-9C-dyn.vh @@ -0,0 +1,22 @@ +`define PLL_DYN +`define PLL_DEVICE "GW1NR-9C" +`define PLL_FCLKIN "27" +`define PLL_ODIV_SEL 8 + +`define PLL_FBDIV_SEL 12 +`define PLL_IDIV_SEL 5 + +`define PLL_FBDIV_SEL_1 9 +`define PLL_IDIV_SEL_1 2 + +// LCD +`define PLL_FBDIV_SEL_LCD 9 +`define PLL_IDIV_SEL_LCD 2 + +// two pll outputs +`define PLL_0_CLKOUT LCD_CLK +`define PLL_0_CLKOUTD LCD_DEN +`define PLL_0_LOCK LCD_HYNC +`define PLL_1_CLKOUT LCD_SYNC +`define PLL_1_CLKOUTD LCD_XR +`define PLL_1_LOCK LCD_XL diff --git a/examples/pll/pllvr.v b/examples/pll/pllvr.v new file mode 100644 index 00000000..05f567b6 --- /dev/null +++ b/examples/pll/pllvr.v @@ -0,0 +1,63 @@ +module Gowin_PLLVR (clkout, clkin, lock_o, reset, reset_p, clkfb, clkoutd_o, fdiv, idiv); + +output wire clkout; +output wire lock_o; +input wire clkin; +input wire reset; +input wire reset_p; +input wire clkfb; +output wire clkoutd_o; +input wire [5:0] fdiv; +input wire [5:0] idiv; + +wire clkoutp_o; +wire clkoutd3_o; +wire gw_gnd; +wire gw_vcc; + +assign gw_gnd = 1'b0; +assign gw_vcc = 1'b1; + +PLLVR pllvr_inst ( + .CLKOUT(clkout), + .LOCK(lock_o), + .CLKOUTP(clkoutp_o), + .CLKOUTD(clkoutd_o), + .CLKOUTD3(clkoutd3_o), + .RESET(reset), + .RESET_P(reset_p), + .CLKIN(clkin), + .CLKFB(gw_gnd), + .FBDSEL(fdiv), + .IDSEL(idiv), + .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .VREN(gw_vcc) +); + +defparam pllvr_inst.FCLKIN = "27"; +defparam pllvr_inst.DYN_IDIV_SEL = "true"; +defparam pllvr_inst.IDIV_SEL = 5; +defparam pllvr_inst.DYN_FBDIV_SEL = "true"; +defparam pllvr_inst.FBDIV_SEL = 12; +defparam pllvr_inst.DYN_ODIV_SEL = "false"; +defparam pllvr_inst.ODIV_SEL = 8; +defparam pllvr_inst.PSDA_SEL = "0000"; +defparam pllvr_inst.DYN_DA_EN = "false"; +defparam pllvr_inst.DUTYDA_SEL = "0100"; +defparam pllvr_inst.CLKOUT_FT_DIR = 1'b1; +defparam pllvr_inst.CLKOUTP_FT_DIR = 1'b1; +defparam pllvr_inst.CLKOUT_DLY_STEP = 0; +defparam pllvr_inst.CLKOUTP_DLY_STEP = 0; +defparam pllvr_inst.CLKFB_SEL = "internal"; +defparam pllvr_inst.CLKOUT_BYPASS = "false"; +defparam pllvr_inst.CLKOUTP_BYPASS = "false"; +defparam pllvr_inst.CLKOUTD_BYPASS = "false"; +defparam pllvr_inst.DYN_SDIV_SEL = 126; +defparam pllvr_inst.CLKOUTD_SRC = "CLKOUTP"; +defparam pllvr_inst.CLKOUTD3_SRC = "CLKOUTP"; +defparam pllvr_inst.DEVICE = "GW1NSR-4C"; + +endmodule //Gowin_rPLL diff --git a/examples/pll/rpll.v b/examples/pll/rpll.v new file mode 100644 index 00000000..c79b3eb1 --- /dev/null +++ b/examples/pll/rpll.v @@ -0,0 +1,72 @@ +module Gowin_rPLL (clkout, clkin, lock_o, reset, reset_p, clkfb, clkoutd_o, fdiv, idiv); +output wire clkout; +output wire lock_o; +input wire clkin; +input wire reset; +input wire reset_p; +input wire clkfb; +output wire clkoutd_o; +input wire [5:0] fdiv; +input wire [5:0] idiv; + +parameter DEVICE = "GW1N-1", + FCLKIN = "24", + FBDIV_SEL = 0, + IDIV_SEL = 0, + ODIV_SEL = 8, + DYN_ODIV_SEL="false", + DYN_FBDIV_SEL="false", + DYN_IDIV_SEL="false", + DYN_SDIV_SEL=2, + PSDA_SEL="0000"; + +wire clkoutp_o; +wire clkoutd3_o; +wire gw_gnd; +wire gw_vcc; + +assign gw_gnd = 1'b0; +assign gw_vcc = 1'b1; + +rPLL rpll_inst ( + .CLKOUT(clkout), + .LOCK(lock_o), + .CLKOUTP(clkoutp_o), + .CLKOUTD(clkoutd_o), + .CLKOUTD3(clkoutd3_o), + .RESET(reset), + .RESET_P(reset_p), + .CLKIN(clkin), + .CLKFB(gw_gnd), + .FBDSEL(fdiv), + .IDSEL(idiv), + .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), + .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}) +); + +defparam rpll_inst.DEVICE = DEVICE; +defparam rpll_inst.FCLKIN = FCLKIN; +defparam rpll_inst.FBDIV_SEL = FBDIV_SEL; +defparam rpll_inst.DYN_IDIV_SEL = DYN_IDIV_SEL; +defparam rpll_inst.IDIV_SEL = IDIV_SEL; +defparam rpll_inst.DYN_FBDIV_SEL = DYN_FBDIV_SEL; +defparam rpll_inst.DYN_ODIV_SEL = DYN_ODIV_SEL; +defparam rpll_inst.ODIV_SEL = ODIV_SEL; +defparam rpll_inst.PSDA_SEL = PSDA_SEL; +defparam rpll_inst.DYN_DA_EN = "false"; +defparam rpll_inst.DUTYDA_SEL = "0100"; +defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; +defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; +defparam rpll_inst.CLKOUT_DLY_STEP = 0; +defparam rpll_inst.CLKOUTP_DLY_STEP = 0; +defparam rpll_inst.CLKFB_SEL = "internal"; +defparam rpll_inst.CLKOUT_BYPASS = "false"; +defparam rpll_inst.CLKOUTP_BYPASS = "false"; +defparam rpll_inst.CLKOUTD_BYPASS = "false"; +defparam rpll_inst.DYN_SDIV_SEL = DYN_SDIV_SEL; +defparam rpll_inst.CLKOUTD_SRC = "CLKOUTP"; +defparam rpll_inst.CLKOUTD3_SRC = "CLKOUTP"; + +endmodule //Gowin_rPLL diff --git a/examples/pll2.v b/examples/pll2.v new file mode 100644 index 00000000..8b94ed77 --- /dev/null +++ b/examples/pll2.v @@ -0,0 +1,72 @@ +`default_nettype none +// Two PLLs, one dynamic - frequencies are switched by pressing key +// / key is pressed +// PLL_0_CLKOUT - 58.5MHz / 90MHz +// PLL_0_LOCK - PLL_0_LOCK +// PLL_0_CLKUOTD - 464KHz / 714KHz +// +// PLL_1_CLKOUT - 90MHz +// PLL_1_LOCK - PLL_1_LOCK +// PLL_1_CLKOUTD - 714KHz +module top(input wire clk, + output `PLL_0_CLKOUT, + output `PLL_0_CLKOUTD, + output `PLL_0_LOCK, + output `PLL_1_CLKOUT, + output `PLL_1_CLKOUTD, + output `PLL_1_LOCK, + input wire rst, input wire key); + wire gnd; + assign gnd = 1'b0; + wire dummy; + reg [5:0] fdiv; + reg [5:0] idiv; + Gowin_rPLL rpll_0( + .clkout(`PLL_0_CLKOUT), + .clkin(clk), + .lock_o(`PLL_0_LOCK), + .reset(gnd), + .reset_p(gnd), + .clkfb(gnd), + .clkoutd_o(`PLL_0_CLKOUTD), + .fdiv(fdiv), + .idiv(idiv) + ); + defparam rpll_0.DEVICE = `PLL_DEVICE; + defparam rpll_0.FCLKIN = `PLL_FCLKIN; + defparam rpll_0.ODIV_SEL = `PLL_ODIV_SEL; + defparam rpll_0.DYN_FBDIV_SEL = "true"; + defparam rpll_0.DYN_IDIV_SEL = "true"; + defparam rpll_0.DYN_ODIV_SEL = "false"; + defparam rpll_0.DYN_SDIV_SEL = 124; + + Gowin_rPLL rpll_1( + .clkout(`PLL_1_CLKOUT), + .clkin(clk), + .lock_o(`PLL_1_LOCK), + .reset(gnd), + .reset_p(gnd), + .clkfb(gnd), + .clkoutd_o(`PLL_1_CLKOUTD), + .fdiv(~6'd`PLL_FBDIV_SEL_1), + .idiv(~6'd`PLL_IDIV_SEL_1) + ); + defparam rpll_1.DEVICE = `PLL_DEVICE; + defparam rpll_1.FCLKIN = `PLL_FCLKIN; + defparam rpll_1.ODIV_SEL = `PLL_ODIV_SEL; + defparam rpll_1.DYN_FBDIV_SEL = "true"; + defparam rpll_1.DYN_IDIV_SEL = "true"; + defparam rpll_1.DYN_ODIV_SEL = "false"; + defparam rpll_1.DYN_SDIV_SEL = 124; + + // dynamic + always @ (posedge clk) begin + if (key) begin + fdiv <= ~6'd`PLL_FBDIV_SEL; + idiv <= ~6'd`PLL_IDIV_SEL; + end else begin + fdiv <= ~6'd`PLL_FBDIV_SEL_1; + idiv <= ~6'd`PLL_IDIV_SEL_1; + end + end +endmodule diff --git a/examples/tangnano9k.cst b/examples/tangnano9k.cst index 8f74110d..e909e36f 100644 --- a/examples/tangnano9k.cst +++ b/examples/tangnano9k.cst @@ -10,6 +10,29 @@ IO_LOC "led[5]" 16; IO_LOC "key" 3; IO_LOC "rst" 4; +IO_LOC "LCD_B[0]" 54; +IO_LOC "LCD_B[1]" 53; +IO_LOC "LCD_B[2]" 51; +IO_LOC "LCD_B[3]" 42; +IO_LOC "LCD_B[4]" 41; +IO_LOC "LCD_CLK" 35; +IO_LOC "LCD_DEN" 33; +IO_LOC "LCD_G[0]" 70; +IO_LOC "LCD_G[1]" 69; +IO_LOC "LCD_G[2]" 68; +IO_LOC "LCD_G[3]" 57; +IO_LOC "LCD_G[4]" 56; +IO_LOC "LCD_G[5]" 55; +IO_LOC "LCD_HYNC" 40; +IO_LOC "LCD_R[0]" 75; +IO_LOC "LCD_R[1]" 74; +IO_LOC "LCD_R[2]" 73; +IO_LOC "LCD_R[3]" 72; +IO_LOC "LCD_R[4]" 71; +IO_LOC "LCD_SYNC" 34; +IO_LOC "LCD_XR" 32; +IO_LOC "LCD_XL" 39; + // true LVDS pins IO_LOC "tlvds_p" 25,26;