Skip to content

Commit c642618

Browse files
authored
GW5A. Add OSC (#379)
* GW5A. Add OSC A programmable on-chip crystal oscillator (OSCA) has been implemented for GW5A-25A. A distinctive feature of the new series is that the OSC output is no longer a conventional wire, and therefore routing it through conventional PIPs is not possible, nor is it possible to "pull" its signal to the entry point of the global clock wire system. Nextpnr has been modified to connect the OSC output via an intermediate clock wire. In addition, the OSC fuses are also "spread" across the chip like clock fuses. * GW5A. OSC divider 3 In addition to even divisors, OSC in the GW5A series also supports division by 3. Let's take this into account. --------- Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
1 parent 2cbb2c1 commit c642618

File tree

8 files changed

+120
-22
lines changed

8 files changed

+120
-22
lines changed

apycula/chipdb.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ def fse_osc(device, fse, ttyp):
461461
elif device == 'GW1N-2':
462462
bel = osc.setdefault(f"OSCO", Bel())
463463
elif device == 'GW5A-25A':
464-
bel = osc.setdefault(f"OSCO", Bel())
464+
bel = osc.setdefault(f"OSCA", Bel())
465465
else:
466466
raise Exception(f"Oscillator not yet supported on {device}")
467467
bel.portmap = {}
@@ -2247,10 +2247,7 @@ def fse_create_io16(dev, device):
22472247
('OSC', 'GW1N-9C'): ({'OSCOUT': 'Q4'}, {}),
22482248
('OSC', 'GW2A-18'): ({'OSCOUT': 'Q4'}, {}),
22492249
('OSC', 'GW2A-18C'): ({'OSCOUT': 'Q4'}, {}),
2250-
# XXX unsupported boards, pure theorizing
2251-
('OSCO', 'GW1N-2'): ({'OSCOUT': 'Q7'}, {'OSCEN': (9, 1, 'B4')}),
2252-
('OSCW', 'GW2AN-18'): ({'OSCOUT': 'Q4'}, {}),
2253-
('OSCO', 'GW5A-25A'): ({'OSCOUT': 'Q4'}, {}), # Fix me
2250+
('OSCA', 'GW5A-25A'): ({}, {'OSCOUT': (19, 91, 'OSC_O'), 'OSCEN': (19, 90, 'SEL4')}),
22542251
}
22552252

22562253
# from logic to global clocks. An interesting piece of dat['CmuxIns'], it was
@@ -2312,15 +2309,39 @@ def fse_create_logic2clk(dev, device, dat: Datfile):
23122309
dev.extra_func.setdefault((row, col), {}).setdefault('clock_gates', []).append(wnames.wirenames[wire_idx])
23132310

23142311
def fse_create_osc(dev, device, fse):
2312+
skip_nodes = False
23152313
for row, rd in enumerate(dev.grid):
23162314
for col, rc in enumerate(rd):
23172315
if 51 in fse[rc.ttyp]['shortval']:
2316+
# None of the supported chips, nor the planned TangMega138k,
2317+
# have more than one OSC. However, in the GW25 series, the
2318+
# fuses from Table 51 are found in several cells. The simplest
2319+
# way to avoid creating duplicate nodes for OSC inputs and
2320+
# outputs is to create them only in the first cell encountered.
2321+
if skip_nodes:
2322+
dev.extra_func.setdefault((row, col), {}).update({'osc_fuses_only': {}})
2323+
continue
23182324
osc_type = list(fse_osc(device, fse, rc.ttyp).keys())[0]
23192325
dev.extra_func.setdefault((row, col), {}).update(
23202326
{'osc': {'type': osc_type}})
23212327
_, aliases = _osc_ports[osc_type, device]
23222328
for port, alias in aliases.items():
23232329
dev.nodes.setdefault(f'X{col}Y{row}/{port}', (port, {(row, col, port)}))[1].add(alias)
2330+
# Unlike previous series, GW5A has an OSC output as a clock
2331+
# wire, which means that, as a clock source output, it should
2332+
# be part of the clock MUX spread across the entire chip.
2333+
# Unfortunately, this is not the case—during trial
2334+
# compilations, a fuse was noticed for clock pip 520->211 and
2335+
# then 211->SPINE. This means that the OSC output is not a
2336+
# direct input to the clock MUX. So we are looking for all the
2337+
# intermediate wires and making them nodes in the hope that one
2338+
# of them will be picked up by the clock MUX.
2339+
if port == 'OSCOUT' and device in {'GW5A-25A'}:
2340+
a_row, a_col, a_wire = alias
2341+
for dest, srcs in dev.grid[a_row][a_col].clock_pips.items():
2342+
if a_wire in srcs:
2343+
add_node(dev, dest, "GLOBAL_CLK", a_row, a_col, dest)
2344+
skip_nodes = True
23242345

23252346
def fse_create_gsr(dev, device):
23262347
# Since, in the general case, there are several cells that have a

apycula/gowin_pack.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ def get_bits(init_data):
210210
_dsp_cell_types = {'ALU54D', 'MULT36X36', 'MULTALU36X18', 'MULTADDALU18X18', 'MULTALU18X18', 'MULT18X18', 'MULT9X9', 'PADD18', 'PADD9'}
211211
def get_bels(data):
212212
later = []
213-
belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWO]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|CLKDIV2|CLKDIV|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DQCE|DCS|USERFLASH|EMCU|DHCEN|MIPI_OBUF|MIPI_IBUF|DLLDLY|PINCFG)(\w*)")
213+
belre = re.compile(r"X(\d+)Y(\d+)/(?:GSR|LUT|DFF|IOB|MUX|ALU|ODDR|OSC[ZFHWOA]?|BUF[GS]|RAM16SDP4|RAM16SDP2|RAM16SDP1|PLL|IOLOGIC|CLKDIV2|CLKDIV|BSRAM|ALU|MULTALU18X18|MULTALU36X18|MULTADDALU18X18|MULT36X36|MULT18X18|MULT9X9|PADD18|PADD9|BANDGAP|DQCE|DCS|USERFLASH|EMCU|DHCEN|MIPI_OBUF|MIPI_IBUF|DLLDLY|PINCFG)(\w*)")
214214

215215
for cellname, cell in data['modules']['top']['cells'].items():
216216
if cell['type'].startswith('DUMMY_') or cell['type'] in {'OSER16', 'IDES16'} or 'NEXTPNR_BEL' not in cell['attributes']:
@@ -2018,18 +2018,22 @@ def set_osc_attrs(db, typ, params):
20182018
if param == 'FREQ_DIV':
20192019
fdiv = int(val, 2)
20202020
if fdiv % 2 == 1:
2021-
raise Exception(f"Divisor of {typ} must be even")
2021+
if fdiv == 3 and device in {'GW5A-25A'}:
2022+
fdiv = 0
2023+
else:
2024+
raise Exception(f"Divisor of {typ} must be even")
20222025
osc_attrs['MCLKCIB'] = fdiv
20232026
osc_attrs['MCLKCIB_EN'] = "ENABLE"
2024-
osc_attrs['NORMAL'] = "ENABLE"
2025-
if typ not in {'OSC', 'OSCW'}:
2026-
osc_attrs['USERPOWER_SAVE'] = 'ENABLE'
20272027
continue
20282028
if param == 'REGULATOR_EN':
20292029
reg = int(val, 2)
20302030
if reg == 1:
20312031
osc_attrs['OSCREG'] = "ENABLE"
20322032
continue
2033+
if typ not in {'OSCA'}:
2034+
osc_attrs['NORMAL'] = "ENABLE"
2035+
if typ not in {'OSC', 'OSCW'}:
2036+
osc_attrs['USERPOWER_SAVE'] = 'ENABLE'
20332037

20342038
fin_attrs = set()
20352039
for attr, val in osc_attrs.items():
@@ -2511,7 +2515,7 @@ def place(db, tilemap, bels, cst, args, slice_attrvals):
25112515
elif typ.startswith("BUFG"):
25122516
continue
25132517

2514-
elif typ in {'OSC', 'OSCZ', 'OSCF', 'OSCH', 'OSCW', 'OSCO'}:
2518+
elif typ in {'OSC', 'OSCZ', 'OSCF', 'OSCH', 'OSCW', 'OSCO', 'OSCA'}:
25152519
# XXX turn on (GW1NZ-1)
25162520
if device == 'GW1NZ-1':
25172521
en_tiledata = db.grid[db.rows - 1][db.cols - 1]
@@ -2526,9 +2530,21 @@ def place(db, tilemap, bels, cst, args, slice_attrvals):
25262530
tile[r][c] = 0
25272531

25282532
osc_attrs = set_osc_attrs(db, typ, parms)
2529-
bits = get_shortval_fuses(db, tiledata.ttyp, osc_attrs, 'OSC')
2530-
for r, c in bits:
2531-
tile[r][c] = 1
2533+
if device in {'GW5A-25A'}:
2534+
# set the fuses in all cells
2535+
for row_col, func_desc in db.extra_func.items():
2536+
if 'osc' in func_desc or 'osc_fuses_only' in func_desc:
2537+
osc_row, osc_col = row_col
2538+
osc_tile = tilemap[osc_row, osc_col]
2539+
bits = get_shortval_fuses(db, db.grid[osc_row][osc_col].ttyp, osc_attrs, 'OSC')
2540+
#print(osc_row, osc_col, osc_attrs)
2541+
for r, c in bits:
2542+
osc_tile[r][c] = 1
2543+
else:
2544+
bits = get_shortval_fuses(db, tiledata.ttyp, osc_attrs, 'OSC')
2545+
for r, c in bits:
2546+
tile[r][c] = 1
2547+
25322548
elif typ.startswith("DFF"):
25332549
mode = typ.strip('E')
25342550
place_dff(db, tiledata, tile, parms, num, mode, row, col, slice_attrvals)
@@ -2974,7 +2990,7 @@ def is_clock_pip(src, dest):
29742990
if dest not in wnames.clknumbers:
29752991
return False
29762992
if device in {'GW5A-25A'}:
2977-
return wnames.clknumbers[src] < wnames.clknumbers['UNK212']
2993+
return src == 'OSC_O' or wnames.clknumbers[src] < wnames.clknumbers['UNK212']
29782994
# XXX for future
29792995
return wnames.clknumbers[src] < wnames.clknumbers['P10A']
29802996

apycula/wirenames.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@
333333

334334
clknames_5a25a.update({291: "GT00", 292: "GT10"})
335335

336-
clknames_5a25a.update({n: f"UNK{n}" for n in range(501, 570)})
336+
clknames_5a25a.update({n: f"UNK{n}" for n in range(501, 520)})
337+
clknames_5a25a[520] = 'OSC_O';
338+
clknames_5a25a.update({n: f"UNK{n}" for n in range(521, 570)})
337339

338340
# HCLK->clock network
339341
# Each HCLK can connect to other HCLKs through two MUXes in the clock system.

examples/gw5a/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ DEBUG = -v --debug
66
.DEFAULT_GOAL := all
77
all: \
88
in-out-primer25k.fs in-inv-out-primer25k.fs in-or-inv-out-primer25k.fs \
9-
lut8-primer25k.fs big-shift-primer25k.fs alu-simple-primer25k.fs lutram-primer25k.fs
9+
lut8-primer25k.fs big-shift-primer25k.fs alu-simple-primer25k.fs lutram-primer25k.fs \
10+
blinky-osc-primer25k.fs
1011

1112

1213
clean:
@@ -29,5 +30,5 @@ alu-%-primer25k.json: alu-%-primer25k-synth.json alu-%-primer25k.cst
2930
$(NEXTPNR) $(DEBUG) --top top --json $< --write $@ --device GW5A-LV25MG121NES --vopt cst=$(basename $@).cst --vopt cpu_as_gpio --vopt sspi_as_gpio
3031

3132
%-primer25k-synth.json: %.v
32-
$(YOSYS) -p "read_verilog $^; synth_gowin -json $@ -family gw5a"
33+
$(YOSYS) -D INV_BTN=1 -D LEDS_NR=8 -D OSC_TYPE_OSCA -p "read_verilog $^; synth_gowin -json $@ -family gw5a"
3334

examples/gw5a/blinky-osc.v

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
module top (
2+
input key_i,
3+
output [`LEDS_NR-1:0] led
4+
);
5+
6+
wire clk;
7+
8+
`ifdef OSC_TYPE_OSC
9+
OSC osc(
10+
.OSCOUT(clk)
11+
);
12+
defparam osc.FREQ_DIV=32;
13+
`elsif OSC_TYPE_OSCZ
14+
OSCZ osc(
15+
.OSCEN(1'b1),
16+
.OSCOUT(clk)
17+
);
18+
defparam osc.FREQ_DIV=32;
19+
`elsif OSC_TYPE_OSCF
20+
OSCF osc(
21+
.OSCEN(1'b1),
22+
.OSCOUT(clk),
23+
.OSCOUT30M()
24+
);
25+
defparam osc.FREQ_DIV=32;
26+
`elsif OSC_TYPE_OSCH
27+
OSCH osc(
28+
.OSCOUT(clk)
29+
);
30+
defparam osc.FREQ_DIV=32;
31+
`elsif OSC_TYPE_OSCA
32+
OSCA osc(
33+
.OSCEN(1'b1),
34+
.OSCOUT(clk)
35+
);
36+
defparam osc.FREQ_DIV=64;
37+
`endif
38+
39+
wire key = key_i ^ `INV_BTN;
40+
41+
reg [25:0] ctr_q;
42+
wire [25:0] ctr_d;
43+
44+
// Sequential code (flip-flop)
45+
always @(posedge clk) begin
46+
if (key) begin
47+
ctr_q <= ctr_d;
48+
end
49+
end
50+
51+
// Combinational code (boolean logic)
52+
assign ctr_d = ctr_q + 1'b1;
53+
assign led = {ctr_q[25:25-(`LEDS_NR - 2)], |ctr_q[25-(`LEDS_NR - 1):25-(`LEDS_NR)] };
54+
55+
endmodule

examples/gw5a/in-or-inv-out.v

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
`default_nettype none
22

3-
module top(input wire resetn, input wire key, output wire [7:0]led);
3+
module top(input wire resetn, input wire key_i, output wire [7:0]led);
4+
wire key = key_i ^ `INV_BTN;
45
assign led[4] = !(resetn | key);
56
endmodule
67

examples/gw5a/lut8.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ Connect them as shown in the photo: apuicula/doc/fig/tangprimer25-lut-test.jpeg
55
`default_nettype none
66

77
(* top *)
8-
module top(input wire resetn, input wire key, input wire [7:0]pmod_keys, output wire [7:0]led);
8+
module top(input wire resetn, input wire key_i, input wire [7:0]pmod_keys, output wire [7:0]led);
9+
wire key = key_i ^ `INV_BTN;
10+
911
wire [7:0]w;
1012
assign led = {~w[5], ~w[6], ~w[4:3], ~w[1:0], ~w[2], w[7]};
1113

examples/gw5a/primer25k.cst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ IO_PORT "pmod_keys[7]" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
3434

3535
IO_LOC "resetn" H10;
3636
IO_PORT "resetn" IO_TYPE=LVCMOS33 PULL_MODE=DOWN DRIVE=OFF BANK_VCCIO=3.3;
37-
IO_LOC "key" H11;
38-
IO_PORT "key" IO_TYPE=LVCMOS33 PULL_MODE=DOWN DRIVE=OFF BANK_VCCIO=3.3;
37+
IO_LOC "key_i" H11;
38+
IO_PORT "key_i" IO_TYPE=LVCMOS33 PULL_MODE=DOWN DRIVE=OFF BANK_VCCIO=3.3;
3939

4040
IO_LOC "clk" E2;
4141
IO_PORT "clk" IO_TYPE=LVCMOS33 PULL_MODE=NONE DRIVE=OFF BANK_VCCIO=3.3;

0 commit comments

Comments
 (0)