From bea46f9bdbec1ddeb864d5f8a91e062fcc99af01 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 20 Jul 2024 11:05:16 +1000 Subject: [PATCH 1/6] Add DHCEN primitive. Added parts necessary to generate chip databases with DHCEN support for all supported boards. The packing was made with the necessary fuses set. DHCEN is provided as a wire to disable the input MUXes of HCLK, effectively turning off everything that is "beyond" those MUXes. Most of the work happens in the nextpnr part. Signed-off-by: YRabbit --- apycula/attrids.py | 64 ++++++++++++++++++++++++++++++++++++++ apycula/chipdb.py | 71 +++++++++++++++++++++++++++++++++++++++++++ apycula/gowin_pack.py | 45 ++++++++++++++++++++++++++- 3 files changed, 179 insertions(+), 1 deletion(-) diff --git a/apycula/attrids.py b/apycula/attrids.py index bb5d45f6..294dbdf8 100644 --- a/apycula/attrids.py +++ b/apycula/attrids.py @@ -1140,6 +1140,70 @@ 'SYNC': 2, } +# HCLK +hclk_attrids = { + 'BK00DIV2_RST': 0, + 'BK01DIV2_RST': 1, + 'BK0MUX0_OUTSEL': 2, + 'BK0MUX1_OUTSEL': 3, + 'BK10DIV2_RST': 4, + 'BK11DIV2_RST': 5, + 'BK1MUX0_OUTSEL': 6, + 'BK1MUX1_OUTSEL': 7, + 'BRGMUX0_BRGOUT': 8, + 'BRGMUX0_INSEL': 9, + 'BRGMUX1_BRGOUT': 10, + 'BRGMUX1_INSEL': 11, + 'BRGMUX0_BRGSTOP': 12, + 'BRGMUX1_BRGSTOP': 13, + 'HCLKDIV0_DIV': 14, + 'HCLKDIV0_RST': 15, + 'HCLKDIV1_DIV': 16, + 'HCLKDIV1_RST': 17, + 'HSB0MUX0_HSTOP': 18, + 'HSB0MUX1_HSTOP': 19, + 'HSB1MUX0_HSTOP': 20, + 'HSB1MUX1_HSTOP': 21, + 'HCLKDCS0_SEL': 22, + 'HCLKDCS1_SEL': 23, + 'DCC0': 24, + 'DCC1': 25, + 'DLYMUX': 26, + 'HCLKDIV_DIV': 27, + 'HCLKDIV_RST': 28, + } + +hclk_attrvals = { + 'UNKNOWN': 0, + 'DIVCIBRST2': 1, + 'DIVCIBRST3': 2, + 'DIV2': 3, + 'DIVCIBRST0': 4, + 'DIVCIBRST1': 5, + 'DIVCIBRST4': 6, + 'DIVCIBRST5': 7, + 'ENABLE': 8, + 'BRGCIBSEL0': 9, + 'BRGCIBSEL1': 10, + 'BRGCIBSTOP0': 11, + 'BRGCIBSTOP1': 12, + '2': 13, + '3.5': 14, + '4': 15, + '5': 16, + 'HCLKCIBSTOP0': 17, + 'HCLKCIBSTOP1': 18, + 'HCLKCIBSTOP2': 19, + 'HCLKCIBSTOP3': 20, + 'HCLKBK10': 21, + 'HCLKBK11': 22, + '8': 23, + 'DIVCIBRST': 24, + 'NEG_80': 25, + '80': 26, + } + + # iologic iologic_attrids = { 'INMODE': 0, diff --git a/apycula/chipdb.py b/apycula/chipdb.py index ab8623d0..9c846c38 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -454,6 +454,7 @@ def set_banks(fse, db): 14: 'DSP', 15: 'PLL', 39: 'BSRAM_INIT', + 49: 'HCLK', 59: 'CFG', 62: 'OSC', 63: 'USB', @@ -487,6 +488,7 @@ def set_banks(fse, db): 45: 'IOBH', 46: 'IOBI', 47: 'IOBJ', + 50: 'HCLK', 51: 'OSC', 53: 'DLLDEL0', 54: 'DLLDEL1', @@ -1064,6 +1066,74 @@ def fse_create_hclk_nodes(dev, device, fse, dat: Datfile): if src.startswith('HCLK'): hclks[src].add((row, col, src)) +# DHCEN (as I imagine) is an additional control input of the HCLK input +# multiplexer. We have four input multiplexers - HCLK_IN0, HCLK_IN1, HCLK_IN2, +# HCLK_IN3 (GW1N-9C with its additional four multiplexers stands separately, +# but we will deal with it separately). +# Creating images using IDE where we use the maximum allowable number of DHCEN, +# the CE port of which is connected to the IO ports, then we trace the route +# from IO to the final wire, which will be the CE port of the DHCEN primitive. +# We are not interested in the CLKIN and CLKOUT ports because we are supposed +# to simply disable/enable one of the input multiplexers. +# Let's summarize the experimental data in a table. +# There are 4 multiplexers on each side of the chip (sides: Right Bottom Left Top). +_dhcen_ce = { + 'GW1N-1': + {'B' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2')]}, + 'GW1NZ-1': + {'R' : [( 0, 19, 'A2'), ( 0, 19, 'A4'), ( 0, 19, 'A3'), ( 0, 19, 'A5')], + 'T' : [(10, 19, 'A2'), (10, 19, 'A4'), (10, 19, 'A3'), (10, 19, 'A5')]}, + 'GW1NS-2': + {'R' : [(10, 19, 'A4'), (10, 19, 'A6'), (10, 19, 'A5'), (10, 19, 'A7')], + 'B' : [(11, 19, 'A4'), (11, 19, 'A6'), (11, 19, 'A5'), (11, 19, 'A7')], + 'L' : [( 9, 0, 'A0'), ( 9, 0, 'A2'), ( 9, 0, 'A1'), ( 9, 0, 'A3')], + 'T' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2')]}, + 'GW1N-4': + {'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6')], + 'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5')], + 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')]}, + 'GW1NS-4': + {'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6')], + 'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5')], + 'T' : [( 1, 0, 'B6'), ( 1, 0, 'A0'), ( 1, 0, 'B7'), ( 1, 0, 'A1')]}, + 'GW1N-9C': + {'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6')], + 'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5')], + 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')], + 'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6')]}, + 'GW1N-9C': + {'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6')], + 'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5')], + 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')], + 'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6')]}, + 'GW2A-18': + {'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3')], + 'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3')], + 'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3')], + 'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3')]}, + 'GW2A-18C': + {'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3')], + 'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3')], + 'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3')], + 'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3')]}, + } +def fse_create_dhcen(dev, device, fse, dat: Datfile): + if device not in _dhcen_ce: + print(f'No DHCEN for {device} for now.') + return + for side, ces in _dhcen_ce[device].items(): + for idx, ce_wire in enumerate(ces): + row, col, wire = ce_wire + extra = dev.extra_func.setdefault((row, col), {}) + dhcen = extra.setdefault('dhcen', []) + # use db.hclk_pips in order to find HCLK_IN cells + for hclk_loc in _hclk_to_fclk[device][side]['hclk']: + if f'HCLK_IN{idx}' in dev.hclk_pips[hclk_loc]: + hclkin = {'hclkin' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_IN{idx}', side]} + hclkin.update({ 'ce' : wire}) + dhcen.append(hclkin) + + _pll_loc = { 'GW1N-1': {'TRPLL0CLK0': (0, 17, 'F4'), 'TRPLL0CLK1': (0, 17, 'F5'), @@ -1722,6 +1792,7 @@ def from_fse(device, fse, dat: Datfile): fse_create_gsr(dev, device) fse_create_bandgap(dev, device) fse_create_logic2clk(dev, device, dat) + fse_create_dhcen(dev, device, fse, dat) disable_plls(dev, device) sync_extra_func(dev) set_chip_flags(dev, device); diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index d1a40c86..646b3128 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -185,7 +185,7 @@ def get_bits(init_data): def get_bels(data): later = [] if is_himbaechel: - belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP)(\w*)") + belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DHCEN)(\w*)") else: belre = re.compile(r"R(\d+)C(\d+)_(?:GSR|SLICE|IOB|MUX2_LUT5|MUX2_LUT6|MUX2_LUT7|MUX2_LUT8|ODDR|OSC[ZFHWO]?|BUFS|RAMW|rPLL|PLLVR|IOLOGIC)(\w*)") @@ -1968,6 +1968,41 @@ def set_osc_attrs(db, typ, params): add_attr_val(db, 'OSC', fin_attrs, attrids.osc_attrids[attr], val) return fin_attrs +_wire2attr_val = { + 'HCLK_IN0': ('HSB0MUX0_HSTOP', 'HCLKCIBSTOP0'), + 'HCLK_IN1': ('HSB1MUX0_HSTOP', 'HCLKCIBSTOP2'), + 'HCLK_IN2': ('HSB0MUX1_HSTOP', 'HCLKCIBSTOP1'), + 'HCLK_IN3': ('HSB1MUX1_HSTOP', 'HCLKCIBSTOP3'), + } +def find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side): + fin_attrs = set() + attr, attr_val = _wire2attr_val[wire] + val = attrids.hclk_attrvals[attr_val] + add_attr_val(db, 'HCLK', fin_attrs, attrids.hclk_attrids[attr], val) + + def set_fuse(): + ttyp = db.grid[row][col].ttyp + if 'HCLK' in db.shortval[ttyp]: + bits = get_shortval_fuses(db, ttyp, fin_attrs, "HCLK") + tile = tilemap[row, col] + for r, c in bits: + tile[r][c] = 1 + + if side in "TB": + if side == 'T': + row = 0 + else: + row = db.rows - 1 + for col in range(db.cols): + set_fuse() + else: + if side == 'R': + col = 0 + else: + col = db.col - 1 + for row in range(db.rows): + set_fuse() + _iologic_default_attrs = { 'DUMMY': {}, 'IOLOGIC': {}, @@ -2431,6 +2466,14 @@ def place(db, tilemap, bels, cst, args): cfg_tile = tilemap[(0, 37)] for r, c in bits: cfg_tile[r][c] = 1 + elif typ == "DHCEN": + if 'DHCEN_SIDE' not in attrs: + continue + # DHCEN as such is just a control wire and does not have a fuse + # itself, but HCLK has fuses that allow this control. Here we look + # for the corresponding HCLK and set its fuses. + _, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['hclk'] + hclk_attrs = find_and_set_dhcen_hclk_fuses(db, wire, side) else: print("unknown type", typ) From 90aaf55e112979648b6e1a3ccbee4d952bcf70f7 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sun, 21 Jul 2024 21:19:35 +1000 Subject: [PATCH 2/6] DHCEN. Add example Added an example of using DHCEN. It uses CLKDIV and CLKDIV2 so it will work on boards that support these primitives. The Tangnano9k board is currently being investigated because there are some unknowns there. Signed-off-by: YRabbit --- apycula/gowin_pack.py | 6 +- examples/himbaechel/blinky-clkdiv-dhcen.v | 83 +++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) create mode 100644 examples/himbaechel/blinky-clkdiv-dhcen.v diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 646b3128..3e9e5282 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -1996,7 +1996,7 @@ def set_fuse(): for col in range(db.cols): set_fuse() else: - if side == 'R': + if side == 'L': col = 0 else: col = db.col - 1 @@ -2472,8 +2472,8 @@ def place(db, tilemap, bels, cst, args): # DHCEN as such is just a control wire and does not have a fuse # itself, but HCLK has fuses that allow this control. Here we look # for the corresponding HCLK and set its fuses. - _, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['hclk'] - hclk_attrs = find_and_set_dhcen_hclk_fuses(db, wire, side) + _, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['hclkin'] + hclk_attrs = find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side) else: print("unknown type", typ) diff --git a/examples/himbaechel/blinky-clkdiv-dhcen.v b/examples/himbaechel/blinky-clkdiv-dhcen.v new file mode 100644 index 00000000..82df47b4 --- /dev/null +++ b/examples/himbaechel/blinky-clkdiv-dhcen.v @@ -0,0 +1,83 @@ +module top ( + input clk, + input key_i, + output [`LEDS_NR-1:0] led +); + +/* Expected Result: + - 1 or 2 LEDs blinking, depending on your board. + - The `faster` LED is associated with the input clock. + - The `slower` LED is associated with a divided clock. + - On boards with multiple CLKDIVs, the slower LED's blink rate changes as it cycles through CLKDIVs + configured with different DIV_MODES. + - If your board has only one LED, it should blink with the divided clock. + - Holding the appropriate button should stop the blinking. +*/ + +localparam /*string*/ DIV_MODE_2 = "2"; +localparam /*string*/ DIV_MODE_35 = "3.5"; +localparam /*string*/ DIV_MODE_4 = "4"; +localparam /*string*/ DIV_MODE_5 = "5"; + + +wire key = key_i ^ `INV_BTN; + +reg [25:0] ctr_q; +wire [25:0] ctr_d; +// localparam NUM_HCLKi=NUM_HCLK; + +wire [`NUM_HCLK-1:0] hclk_counts; +reg [$clog2(`NUM_HCLK)-1:0] curr_hclk_idx; +wire curr_hclk; +reg [30:0] sup_count; + + +wire managed_clk; +DHCEN dhcen( + .CLKIN(clk), + .CE(key), + .CLKOUT(managed_clk) +); + +genvar i; +generate + for (i=0; i < `NUM_HCLK; i=i+1) begin:hcount + localparam /*string*/ div_mode =(i % 4 == 0) ? DIV_MODE_5 : + (i % 4 == 1) ? DIV_MODE_4 : + (i % 4 == 2) ? DIV_MODE_35 : + DIV_MODE_2; + + wire div2_out; + wire o_clk; + + CLKDIV2 my_div2 ( + .RESETN(1'b1), + .HCLKIN(managed_clk), + .CLKOUT(div2_out) + ); + + CLKDIV #(.DIV_MODE(div_mode)) my_div ( + .RESETN(1'b1), + .HCLKIN(div2_out), + .CLKOUT(o_clk) + ); + + reg [23:0] count; + always @(posedge o_clk)begin + count <= count + 1'b1; + end + assign hclk_counts[i] = count[23]; + end +endgenerate + +always @(posedge clk) begin + sup_count <= sup_count + 1'b1; + curr_hclk_idx <= curr_hclk_idx + sup_count[29]; + if (curr_hclk_idx == `NUM_HCLK-1) + curr_hclk_idx <= 0; +end + +assign curr_hclk = hclk_counts[curr_hclk_idx]; +assign led = {curr_hclk, sup_count[23]}; + +endmodule From 68899988c80fe042b693db554833256ab79ca541 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 25 Jul 2024 15:32:45 +1000 Subject: [PATCH 3/6] HCLK. Add interbank wires An interesting mechanism for transmitting signals between HCLK banks (or otherwise parties) has been discovered. We have two points, each of which can receive a signal from any HCLK and transmit it to any other HCLK. No complex signals can be transmitted here - the input lines are limited by HCLK_INx, and we also need to see which components can use the output from these two points, but so far the tests are encouraging: it is possible to transmit a signal from the clock pin from one side of the chip to the opposite and feed CLKDIV2 there using just a couple wires! Signed-off-by: YRabbit --- apycula/chipdb.py | 90 ++++++++++++++++++++++++++----------------- apycula/gowin_pack.py | 18 ++++++++- apycula/wirenames.py | 16 +++++++- 3 files changed, 85 insertions(+), 39 deletions(-) diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 9c846c38..03969b9f 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -1023,12 +1023,19 @@ def fse_create_hclk_nodes(dev, device, fse, dat: Datfile): row, col = hclk_loc ttyp = fse['header']['grid'][61][row][col] dev.hclk_pips[(row, col)] = fse_pips(fse, ttyp, table = 48, wn = hclknames) + for dst in dev.hclk_pips[(row, col)].keys(): + # from HCLK to interbank MUX + if dst in {'HCLK_BANK_OUT0', 'HCLK_BANK_OUT1'}: + add_node(dev, f'HCLK{"TBLR".index(side)}_BANK_OUT{dst[-1]}', "GLOBAL_CLK", row, col, dst) # connect local wires like PCLKT0 etc to the global nodes for srcs in dev.hclk_pips[(row, col)].values(): for src in srcs.keys(): for pfx in _global_wire_prefixes: if src.startswith(pfx): add_node(dev, src, "HCLK", row, col, src) + # from interbank MUX to HCLK + if src in {'HCLK_BANK_IN0', 'HCLK_BANK_IN1'}: + add_node(dev, f'HCLKMUX{src[-1]}', "GLOBAL_CLK", row, col, src) # strange GW1N-9C input-input aliases for i in {0, 2}: dev.nodes.setdefault(f'X{col}Y{row}/HCLK9-{i}', ('HCLK', {(row, col, f'HCLK_IN{i}')}))[1].add((row, col, f'HCLK_9IN{i}')) @@ -1069,53 +1076,54 @@ def fse_create_hclk_nodes(dev, device, fse, dat: Datfile): # DHCEN (as I imagine) is an additional control input of the HCLK input # multiplexer. We have four input multiplexers - HCLK_IN0, HCLK_IN1, HCLK_IN2, # HCLK_IN3 (GW1N-9C with its additional four multiplexers stands separately, -# but we will deal with it separately). +# but we will deal with it later) and two interbank inputs. # Creating images using IDE where we use the maximum allowable number of DHCEN, # the CE port of which is connected to the IO ports, then we trace the route # from IO to the final wire, which will be the CE port of the DHCEN primitive. # We are not interested in the CLKIN and CLKOUT ports because we are supposed # to simply disable/enable one of the input multiplexers. # Let's summarize the experimental data in a table. -# There are 4 multiplexers on each side of the chip (sides: Right Bottom Left Top). +# There are 4 multiplexers and interbank inputs on each side of the chip +# (sides: Right Bottom Left Top). _dhcen_ce = { 'GW1N-1': - {'B' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2')]}, + {'B' : [(10, 19, 'D5'), (10, 19, 'D3'), (10, 19, 'D4'), (10, 19, 'D2'), (10, 0, 'C0'), (10, 0, 'C1')]}, 'GW1NZ-1': - {'R' : [( 0, 19, 'A2'), ( 0, 19, 'A4'), ( 0, 19, 'A3'), ( 0, 19, 'A5')], - 'T' : [(10, 19, 'A2'), (10, 19, 'A4'), (10, 19, 'A3'), (10, 19, 'A5')]}, + {'R' : [( 0, 19, 'A2'), ( 0, 19, 'A4'), ( 0, 19, 'A3'), ( 0, 19, 'A5'), ( 0, 18, 'C6'), ( 0, 18, 'C7')], + 'T' : [(10, 19, 'A2'), (10, 19, 'A4'), (10, 19, 'A3'), (10, 19, 'A5'), (10, 19, 'C6'), (10, 19, 'C7')]}, 'GW1NS-2': - {'R' : [(10, 19, 'A4'), (10, 19, 'A6'), (10, 19, 'A5'), (10, 19, 'A7')], - 'B' : [(11, 19, 'A4'), (11, 19, 'A6'), (11, 19, 'A5'), (11, 19, 'A7')], - 'L' : [( 9, 0, 'A0'), ( 9, 0, 'A2'), ( 9, 0, 'A1'), ( 9, 0, 'A3')], - 'T' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2')]}, + {'R' : [(10, 19, 'A4'), (10, 19, 'A6'), (10, 19, 'A5'), (10, 19, 'A7'), (10, 19, 'C4'), (10, 19, 'C5')], + 'B' : [(11, 19, 'A4'), (11, 19, 'A6'), (11, 19, 'A5'), (11, 19, 'A7'), (11, 19, 'C4'), (11, 19, 'C5')], + 'L' : [( 9, 0, 'A0'), ( 9, 0, 'A2'), ( 9, 0, 'A1'), ( 9, 0, 'A3'), ( 9, 0, 'C0'), ( 9, 0, 'C1')], + 'T' : [( 0, 19, 'D5'), ( 0, 19, 'D3'), ( 0, 19, 'D4'), ( 0, 19, 'D2'), ( 0, 0, 'B1'), ( 0, 0, 'B0')]}, 'GW1N-4': - {'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6')], - 'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5')], - 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')]}, + {'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6'), ( 0, 37, 'D7'), ( 0, 37, 'D6')], + 'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5'), (19, 0, 'B2'), (19, 0, 'B3')], + 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6'), (19, 0, 'A4'), ( 0, 0, 'B1')]}, 'GW1NS-4': - {'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6')], - 'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5')], - 'T' : [( 1, 0, 'B6'), ( 1, 0, 'A0'), ( 1, 0, 'B7'), ( 1, 0, 'A1')]}, + {'R' : [(18, 37, 'C6'), (18, 37, 'D7'), (18, 37, 'C7'), (18, 37, 'D6'), ( 0, 37, 'D7'), ( 0, 37, 'D6')], + 'B' : [(19, 37, 'A2'), (19, 37, 'A4'), (19, 37, 'A3'), (19, 37, 'A5'), (19, 0, 'B2'), (19, 0, 'B3')], + 'T' : [( 1, 0, 'B6'), ( 1, 0, 'A0'), ( 1, 0, 'B7'), ( 1, 0, 'A1'), ( 1, 0, 'C4'), ( 1, 0, 'C3')]}, + 'GW1N-9': + {'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6'), (18, 46, 'B6'), (18, 46, 'B7')], + 'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5'), (28, 0, 'B2'), (28, 0, 'B3')], + 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6'), (18, 0, 'B6'), (18, 0, 'B7')], + 'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6'), ( 9, 0, 'B6'), ( 9, 0, 'B7')]}, 'GW1N-9C': - {'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6')], - 'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5')], - 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')], - 'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6')]}, - 'GW1N-9C': - {'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6')], - 'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5')], - 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6')], - 'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6')]}, + {'R' : [(18, 46, 'C6'), (18, 46, 'D7'), (18, 46, 'C7'), (18, 46, 'D6'), (18, 46, 'B6'), (18, 46, 'B7')], + 'B' : [(28, 46, 'A2'), (28, 46, 'A4'), (28, 46, 'A3'), (28, 46, 'A5'), (28, 0, 'B2'), (28, 0, 'B3')], + 'L' : [(18, 0, 'C6'), (18, 0, 'D7'), (18, 0, 'C7'), (18, 0, 'D6'), (18, 0, 'B6'), (18, 0, 'B7')], + 'T' : [( 9, 0, 'C6'), ( 9, 0, 'D7'), ( 9, 0, 'C7'), ( 9, 0, 'D6'), ( 9, 0, 'B6'), ( 9, 0, 'B7')]}, 'GW2A-18': - {'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3')], - 'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3')], - 'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3')], - 'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3')]}, + {'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3'), (27, 55, 'D0'), (27, 55, 'D1')], + 'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3'), (54, 27, 'D0'), (54, 27, 'D1')], + 'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3'), (27, 0, 'D0'), (27, 0, 'D1')], + 'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3'), ( 0,27, 'D0'), ( 0, 27, 'D1')]}, 'GW2A-18C': - {'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3')], - 'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3')], - 'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3')], - 'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3')]}, + {'R' : [(27, 55, 'A2'), (27, 55, 'A3'), (27, 55, 'D2'), (27, 55, 'D3'), (27, 55, 'D0'), (27, 55, 'D1')], + 'B' : [(54, 27, 'A2'), (54, 27, 'A3'), (54, 27, 'D2'), (54, 27, 'D3'), (54, 27, 'D0'), (54, 27, 'D1')], + 'L' : [(27, 0, 'A2'), (27, 0, 'A3'), (27, 0, 'D2'), (27, 0, 'D3'), (27, 0, 'D0'), (27, 0, 'D1')], + 'T' : [( 0, 27, 'A2'), ( 0, 27, 'A3'), ( 0, 27, 'D2'), ( 0, 27, 'D3'), ( 0,27, 'D0'), ( 0, 27, 'D1')]}, } def fse_create_dhcen(dev, device, fse, dat: Datfile): if device not in _dhcen_ce: @@ -1128,8 +1136,13 @@ def fse_create_dhcen(dev, device, fse, dat: Datfile): dhcen = extra.setdefault('dhcen', []) # use db.hclk_pips in order to find HCLK_IN cells for hclk_loc in _hclk_to_fclk[device][side]['hclk']: - if f'HCLK_IN{idx}' in dev.hclk_pips[hclk_loc]: - hclkin = {'hclkin' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_IN{idx}', side]} + if idx < 4: + if f'HCLK_IN{idx}' in dev.hclk_pips[hclk_loc]: + hclkin = {'wire' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_IN{idx}', side]} + else: + if f'HCLK_BANK_OUT{idx - 4}' in dev.hclk_pips[hclk_loc]: + hclkin = {'wire' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_BANK_OUT{idx - 4}', side]} + hclkin.update({ 'ce' : wire}) dhcen.append(hclkin) @@ -1386,16 +1399,23 @@ def fse_create_clocks(dev, device, dat: Datfile, fse): spines = {f'SPINE{i}' for i in range(32)} + hclk_srcs = {f'HCLK{i}_BANK_OUT{j}' for i in range(4) for j in range(2)} for row, rd in enumerate(dev.grid): for col, rc in enumerate(rd): for dest, srcs in rc.pure_clock_pips.items(): for src in srcs.keys(): if src in spines and not dest.startswith('GT'): add_node(dev, src, "GLOBAL_CLK", row, col, src) - if dest in spines: + if dest in spines or dest in dcs_inputs: add_node(dev, dest, "GLOBAL_CLK", row, col, dest) for src in { wire for wire in srcs.keys() if wire not in {'VCC', 'VSS'}}: add_node(dev, src, "GLOBAL_CLK", row, col, src) + elif dest in {'HCLKMUX0', 'HCLKMUX1'}: + # this interbank communication between HCLKs + add_node(dev, dest, "GLOBAL_CLK", row, col, dest) + for src in {wire for wire in srcs.keys() if wire in hclk_srcs}: + add_node(dev, src, "GLOBAL_CLK", row, col, src) + # GBx0 <- GBOx for spine_pair in range(4): # GB00/GB40, GB10/GB50, GB20/GB60, GB30/GB70 tap_start = _clock_data[device]['tap_start'][0] diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 3e9e5282..6d089022 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -1973,6 +1973,8 @@ def set_osc_attrs(db, typ, params): 'HCLK_IN1': ('HSB1MUX0_HSTOP', 'HCLKCIBSTOP2'), 'HCLK_IN2': ('HSB0MUX1_HSTOP', 'HCLKCIBSTOP1'), 'HCLK_IN3': ('HSB1MUX1_HSTOP', 'HCLKCIBSTOP3'), + 'HCLK_BANK_OUT0': ('BRGMUX0_BRGSTOP', 'BRGCIBSTOP0'), + 'HCLK_BANK_OUT1': ('BRGMUX1_BRGSTOP', 'BRGCIBSTOP1'), } def find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side): fin_attrs = set() @@ -2467,12 +2469,12 @@ def place(db, tilemap, bels, cst, args): for r, c in bits: cfg_tile[r][c] = 1 elif typ == "DHCEN": - if 'DHCEN_SIDE' not in attrs: + if 'DHCEN_USED' not in attrs: continue # DHCEN as such is just a control wire and does not have a fuse # itself, but HCLK has fuses that allow this control. Here we look # for the corresponding HCLK and set its fuses. - _, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['hclkin'] + _, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['wire'] hclk_attrs = find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side) else: print("unknown type", typ) @@ -2635,6 +2637,17 @@ def secure_long_wires(db, tilemap, row, col, src, dest): for row, col in bits: tile[row][col] = 1 +# hclk interbank requires to set some non-route fuses +def do_hclk_banks(db, row, col, src, dest): + res = set() + if dest in {'HCLK_BANK_OUT0', 'HCLK_BANK_OUT1'}: + fin_attrs = set() + add_attr_val(db, 'HCLK', fin_attrs, attrids.hclk_attrids[f'BRGMUX{dest[-1]}_BRGOUT'], attrids.hclk_attrvals['ENABLE']) + + ttyp = db.grid[row][col].ttyp + if 'HCLK' in db.shortval[ttyp]: + res = get_shortval_fuses(db, ttyp, fin_attrs, "HCLK") + return res def route(db, tilemap, pips): for row, col, src, dest in pips: @@ -2646,6 +2659,7 @@ def route(db, tilemap, pips): bits = tiledata.clock_pips[dest][src] elif is_himbaechel and (row - 1, col - 1) in db.hclk_pips and dest in db.hclk_pips[row - 1, col - 1]: bits = db.hclk_pips[row - 1, col - 1][dest][src] + bits.update(do_hclk_banks(db, row - 1, col - 1, src, dest)) else: bits = tiledata.pips[dest][src] except KeyError: diff --git a/apycula/wirenames.py b/apycula/wirenames.py index 325f3a6b..6201b815 100644 --- a/apycula/wirenames.py +++ b/apycula/wirenames.py @@ -106,6 +106,18 @@ }) clknames.update({n: f"UNK{n}" for n in range(210, 261)}) + +# HCLK->clock network +# Each HCLK can connect to other HCLKs through two MUXes in the clock system. +# Here we assign numbers to these MUXes and their inputs - two per HCLK +clknames.update({ + 1000: 'HCLKMUX0', 1001: 'HCLKMUX1', + 1002: 'HCLK0_BANK_OUT0', 1003: 'HCLK0_BANK_OUT1', + 1004: 'HCLK1_BANK_OUT0', 1005: 'HCLK1_BANK_OUT1', + 1006: 'HCLK2_BANK_OUT0', 1007: 'HCLK2_BANK_OUT1', + 1008: 'HCLK3_BANK_OUT0', 1009: 'HCLK3_BANK_OUT1', +}) + clknumbers = {v: k for k, v in clknames.items()} # hclk @@ -113,12 +125,12 @@ hclknames.update({n: f"HCLK_UNK{n}" for n in range(26)}) # inputs hclknames.update({ - 2: 'HCLK_IN0', 3: 'HCLK_IN1', 4: 'HCLK_IN2', 5: 'HCLK_IN3' + 2: 'HCLK_IN0', 3: 'HCLK_IN1', 4: 'HCLK_IN2', 5: 'HCLK_IN3', 8: 'HCLK_BANK_IN0', 9: 'HCLK_BANK_IN1' }) # outputs hclknames.update({ - 10: 'HCLK_OUT0', 11: 'HCLK_OUT1', 12: 'HCLK_OUT2', 13: 'HCLK_OUT3' + 6: 'HCLK_BANK_OUT0', 7: 'HCLK_BANK_OUT1', 10: 'HCLK0_SECT0_IN', 11: 'HCLK0_SECT1_IN', 12: 'HCLK1_SECT0_IN', 13: 'HCLK1_SECT1_IN' }) # these work as inputs in GW1N-9c hclknames.update({ From efd243395f681e23fbd065ae224b0a75679cedde Mon Sep 17 00:00:00 2001 From: YRabbit Date: Tue, 13 Aug 2024 22:02:06 +1000 Subject: [PATCH 4/6] Add a DHCEN example. Signed-off-by: YRabbit --- apycula/gowin_pack.py | 2 ++ examples/himbaechel/Makefile.himbaechel | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index cf9c775a..7f7ae7ad 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -2547,6 +2547,8 @@ def place(db, tilemap, bels, cst, args): elif typ in ["CLKDIV", "CLKDIV2"]: hclk_attrs = set_hclk_attrs(db, parms, num, typ, cellname) bits = get_shortval_fuses(db, tiledata.ttyp, hclk_attrs, "HCLK") + for r, c in bits: + tile[r][c] = 1 elif typ == 'DQCE': # Himbaechel only pipre = re.compile(r"X(\d+)Y(\d+)/([\w_]+)/([\w_]+)") diff --git a/examples/himbaechel/Makefile.himbaechel b/examples/himbaechel/Makefile.himbaechel index 80925219..a4793cb0 100644 --- a/examples/himbaechel/Makefile.himbaechel +++ b/examples/himbaechel/Makefile.himbaechel @@ -6,7 +6,7 @@ NEXTPNR ?= nextpnr-himbaechel all: \ blinky-tangnano20k.fs shift-tangnano20k.fs blinky-tbuf-tangnano20k.fs blinky-oddr-tangnano20k.fs \ blinky-osc-tangnano20k.fs tlvds-tangnano20k.fs elvds-tangnano20k.fs oddr-tlvds-tangnano20k.fs \ - blinky-clkdiv-tangnano20k.fs dvi-example-tangnano20k.fs\ + blinky-clkdiv-tangnano20k.fs dvi-example-tangnano20k.fs blinky-clkdiv-dhcen-tangnano20k.fs \ oddr-elvds-tangnano20k.fs pll-nanolcd-tangnano20k.fs attosoc-tangnano20k.fs \ oser4-tangnano20k.fs ovideo-tangnano20k.fs oser8-tangnano20k.fs oser10-tangnano20k.fs \ ides4-tangnano20k.fs ivideo-tangnano20k.fs ides8-tangnano20k.fs ides10-tangnano20k.fs \ @@ -21,7 +21,7 @@ all: \ \ blinky-primer20k.fs shift-primer20k.fs blinky-tbuf-primer20k.fs blinky-oddr-primer20k.fs \ blinky-osc-primer20k.fs tlvds-primer20k.fs elvds-primer20k.fs oddr-tlvds-primer20k.fs \ - blinky-clkdiv-primer20k.fs dvi-example-primer20k.fs\ + blinky-clkdiv-primer20k.fs dvi-example-primer20k.fs blinky-clkdiv-dhcen-primer20k.fs \ oddr-elvds-primer20k.fs pll-nanolcd-primer20k.fs attosoc-primer20k.fs \ oser4-primer20k.fs ovideo-primer20k.fs oser8-primer20k.fs oser10-primer20k.fs \ ides4-primer20k.fs ivideo-primer20k.fs ides8-primer20k.fs ides10-primer20k.fs \ From 6da6ea20f8ec10f3f71e71c4d12d9bb2c9902eda Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 17 Aug 2024 16:31:30 +1000 Subject: [PATCH 5/6] DHCEN. Pass complete PIP not just wire Signed-off-by: YRabbit --- apycula/chipdb.py | 8 ++++---- apycula/gowin_pack.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apycula/chipdb.py b/apycula/chipdb.py index f5e7fe08..b6eed217 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -1307,11 +1307,11 @@ def fse_create_dhcen(dev, device, fse, dat: Datfile): # use db.hclk_pips in order to find HCLK_IN cells for hclk_loc in _hclk_to_fclk[device][side]['hclk']: if idx < 4: - if f'HCLK_IN{idx}' in dev.hclk_pips[hclk_loc]: - hclkin = {'wire' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_IN{idx}', side]} + hclk_name = f'HCLK_IN{idx}' else: - if f'HCLK_BANK_OUT{idx - 4}' in dev.hclk_pips[hclk_loc]: - hclkin = {'wire' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', f'HCLK_BANK_OUT{idx - 4}', side]} + hclk_name = f'HCLK_BANK_OUT{idx - 4}' + if hclk_name in dev.hclk_pips[hclk_loc]: + hclkin = {'pip' : [f'X{hclk_loc[1]}Y{hclk_loc[0]}', hclk_name, next(iter(dev.hclk_pips[hclk_loc][hclk_name].keys())), side]} hclkin.update({ 'ce' : wire}) dhcen.append(hclkin) diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 7f7ae7ad..332b782b 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -2542,7 +2542,7 @@ def place(db, tilemap, bels, cst, args): # DHCEN as such is just a control wire and does not have a fuse # itself, but HCLK has fuses that allow this control. Here we look # for the corresponding HCLK and set its fuses. - _, wire, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['wire'] + _, wire, _, side = db.extra_func[row - 1, col -1]['dhcen'][int(num)]['pip'] hclk_attrs = find_and_set_dhcen_hclk_fuses(db, tilemap, wire, side) elif typ in ["CLKDIV", "CLKDIV2"]: hclk_attrs = set_hclk_attrs(db, parms, num, typ, cellname) From af2975e67057763e3e0905e92614c9d13266a252 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 12 Sep 2024 08:29:32 +1000 Subject: [PATCH 6/6] HCLK. Add delays Optimistic delays for now, pending future revision. Signed-off-by: YRabbit --- apycula/chipdb.py | 2 ++ apycula/gowin_pack.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apycula/chipdb.py b/apycula/chipdb.py index 7c7617dd..734c0352 100644 --- a/apycula/chipdb.py +++ b/apycula/chipdb.py @@ -3576,6 +3576,8 @@ def fse_wire_delays(db): db.wire_delay[clknames[i]] = "CENT_SPINE_PCLK" for i in range(129, 153): # clock inputs (logic->clock) db.wire_delay[clknames[i]] = "CENT_SPINE_PCLK" + for i in range(1000, 1010): # HCLK + db.wire_delay[clknames[i]] = "X0" # XXX # assign pads with plls # for now use static table and store the bel name although it is always PLL without a number diff --git a/apycula/gowin_pack.py b/apycula/gowin_pack.py index 4b2ceeae..05fd1b23 100644 --- a/apycula/gowin_pack.py +++ b/apycula/gowin_pack.py @@ -2022,7 +2022,7 @@ def set_fuse(): if side == 'L': col = 0 else: - col = db.col - 1 + col = db.cols - 1 for row in range(db.rows): set_fuse()