-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathfpgasynth
executable file
·819 lines (793 loc) · 29.7 KB
/
fpgasynth
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
#!/bin/bash
# see below for why I made this bash instead of sh
set -o posix
# TODO:
# - support use of vhd2vl instead of ghdl (may be worse, but supports generic)
# - support mixed vhdl/verilog[/systemverilog]
# - given how bad xilinx/gowin are, maybe look into Lattice Diamond
# - document just how broken nextpnr-xilinx really is
# - document known issues w/ yosys (e.g. no tdp RAM w/ shared clock, occasional
# assertion crashes, no BSRAM with Gowin's recommended generic Verilog)
# - support iverilog as target
# - support verilator as target (include C files)
# - support partial execution/convert to makefile(-like)
# - rewrite in C/C++, since it's no longer a short wrapper script around a
# just a few tools
# - separate README
#
# Maybe, if I ever get copious amounts of free time, or at least hardware:
# - support anlogic via prjtang (not yet usable) or Tang Dynasty (undocumented)
# - support cyclone 5 (prjmistral) (about as bad as gowin/apicula)
# - make at least 1 nexus binary (requires constraints on all pins)
# (I already did this once, but I need to verify it still works)
#
# Things I won't do:
# - support f4pga. I hate conda and pip. Even though it's slightly
# less broken in some ways than nextpnr-xilinx, it's still broken.
# Fixes should go into nextpnr-xilinx. Plain nextpnr works fine with
# Lattice parts, so I see no reason to use f4pga there, either.
# - support machxo2 (too few LUTS, too rare/expensive to be of use)
# - support eoss3 (too few LUTs to be of use; probably needs f4pga)
# this is bash-specific, and I don't know how to make it portable.
# zsh doesn't work in subshell or pipe
# dash is garbage, so I haven't done any testing or research
# I don't have ksh installed
addtrap() {
tno=${2:-0}
eval "ptrap=(`trap -p $tno`)"
ptrap="${ptrap[2]}"
test x- = "x$ptrap" && ptrap=
trap "$1${ptrap:+; $ptrap}" $tno
}
arch=()
gwdev=()
icedev=()
ecp5dev=()
nexusdev=()
xdev=()
pkg=()
vhdl=
vhdl_args=(--std=08 --ieee=synopsys)
yargs=()
schem=
tr=
top=
delay=
mk_tstrig=mk_testrig.sh
doadd=
keep=
opref=
odir=
ni=
sysv=
ysysv=
defs=()
use_yosys=
libpath=("$HOME/fpga/lib")
addu() {
local arr e x g out="$1"
shift
eval "arr=(\"\${${out}[@]}\")"
for e; do
g=
for x in "${arr[@]}"; do
test "$x" = "$e" && g=y && break
done
test -z "$g" && arr=("${arr[@]}" "$e")
done
eval $out="(\"\${arr[@]}\")"
}
alias sarg='case "$1" in -??*) arg="${1#-?}" ;; *) shift; arg="$1"; esac'
while [ $# -gt 0 ]; do
case "$1" in
-a) addu arch ecp5 ice40 gowin xilinx ;;
-i) addu arch ice40 ;;
-I*) addu arch ice40; sarg; addu icedev "$arg" ;;
-e) addu arch ecp5 ;;
-E*) addu arch ecp5; sarg; addu ecp5dev "$arg" ;;
-n) addu arch nexus ;;
-N*) addu arch nexus; sarg; addu nexusdev "$arg" ;;
-g) addu arch gowin ;;
-G*) addu arch gowin; sarg; addu gwdev "$arg" ;;
-x) addu arch xilinx ;;
-X*) addu arch xilinx; sarg; addu xdev "$arg" ;;
-t*) sarg; top="$arg" ;;
-T) tr=y ;;
-d) delay=y ;;
-s) sysv=system ;;
-ni) ni=y ;;
-sv) ysysv=-sv ;;
-L*) sarg; libpath=("${libpath[@]}" "$arg") ;;
-v) vhdl=y ;;
-V) vhdl=y; while :; do
shift
case "$1" in
"") echo "Unterminated -V"; exit 1 ;;
--) ;;
*) vhdl_args=("${vhdl_args[@]}" "$1"); continue ;;
esac
break
done ;;
-D*) sarg; defs=("${defs[@]}" "$arg") ;;
-q) yargs=("${yargs[@]}" -q) ;;
-o*) sarg; opref="$arg" ;;
-A) doadd=y ;;
-S) schem=y ;;
-k) keep=y ;;
-y) use_yosys=y ;;
-h|-*) cat <<EOF; exit 0 ;;
Usage: $0 [flags] srcfile ...
flags:
-q Quieten yosys a bit
-o <prf> Prefix output files with given prefix
This excludes some side effects produced by ghdl and vendor tools.
-D <def> Add parameter definition for reading Verilog
-L <dir> Add directory to search path for includes, constraints
-ni Remove Verilog-included files from list (simple match)
-v All input files are VHDL instead of Verilog
-V .. -- Same as -v, but add .. to ghdl argument list
-s All input files are System Verilog not supported w/o yosys plugin
-sv All input files are System Verilog supported by yosys\' -sv
-t <top> Set top module name (automatic otherwise)
-A Enable adder extraction pass
-T Enable use of automatic parallel-to-serial test rig
-R <scr> Enable generation of test rig with <scr>
-d Enable generation of delay reports
-S Enable generation of schematics from yosys/nextpnr
-a Add all supported targets: ecp5 ice40 gowin xilinx
-g Add gowin
-G <dev> Add gowin w/ given device
-i Add ice40
-I <dev> Add ice40 w/ given device; append package with /pkg
-e Add ecp5
-E <dev> Add ecp5 w/ given device; append package with /pkg
-n Add nexus
-N <dev> Add nexus w/ given device
-k Keep going on yosys errors
-y Use yosys+nextpnr instead of vendor tool if applicable (gowin,xilinx)
-h Help
Any option -<x> <parm> can be given as -<x><parm> as well.
Default ghdl/VHDL args are --std=08 --ieee=synopsys
For ice40 and ecp5, use the nextpnr argument for the device. If no -- is
prepended, it is automatically added. Package is appended with trailing /.
If a gowin device doesn't start with G, it's assumed to be a number,
optionally followed by a k or K. This is converted into GW1NSR-LV4CQN48PC7/I6
for 4 and GW1N-LV<n>QN48C6/I5 for any other number <n>. For p and GW2A, it
is GW2A-LV18PG256C8/I7.
Default ice40 device is up5k. Default package is sg48.
Default ecp5 device is 85k 45k 25k. Default package is CABGA381.
Default gowin device is p 9 4 1.
Default nexus device is LIFCL-40-8SG72CES.
Default xilinx device is xc7z010, package clg400, speed 1.
EOF
*) break ;;
esac
shift
done
test $# -eq 0 && echo "No input files" && exit 1
test -z "$arch" && arch=(gowin)
test -z "$gwdev" && gwdev=(p 9 4 1)
test -z "$icedev" && icedev=(up5k)
test -z "$ecp5dev" && ecp5dev=(85k 45k 25k)
test -z "$nexusdev" && nexusdev=(LIFCL-40-8SG72CES)
test -z "$xdev" && xdev=(xc7z010)
setdo() {
cd "$wd"
case "$d" in
*"#"*) do="${d#*\#}"; d="${d%%\#*}" ;;
*) do="$opref" ;;
esac
case "$do" in
*/*) odir="${do%/*}"; do="${do##*/}" ;;
*) odir="build-$do" ;;
esac
mkdir -p "$odir" || exit 1
cd "$odir"
}
wd="$(pwd)"
f=()
vf=() # includes .sv files for now
vhdf=()
for x; do
test -n "$ni" && fgrep '`include "'"${x##*/}\"" "$@" >/dev/null && continue
case "$x" in /*) ;; *) x="$wd/$x";; esac
f=("${f[@]}" "$x")
case "$x" in
*.[vV][hH][dD]*) vhdl=y; vhdf=("${vhdf[@]}" "$x") ;;
*.[sS][vV]) vf=("${vf[@]}" "$x"); test -z "$sysv$ysysv" && ysysv=-sv ;;
*) vf=("${vf[@]}" "$x") ;;
esac
done
test -n "$vhdl" && yargs=("${yargs[@]}" -m ghdl)
test -n "$sysv" && yargs=("${yargs[@]}" -m systemverilog)
defargs=("${defs[@]/#/-D}")
yargs=("${yargs[@]}" "${defargs[@]}")
docmd() {
local ofile=
case "$1" in
-o) ofile="$2"; shift 2 ;;
esac
echo "******************************************************"
echo "**** $*${ofile:+ >$ofile}"
echo "******************************************************"
eval '"$@"' "${ofile:+>$ofile}"
}
test ${#f[@]} -eq 0 && exit 1
libpatha=()
for x in "${libpath[@]}"; do
case "$x" in
/*) libpatha=("${libpatha[@]}" "$x") ;;
*) libpatha=("${libpatha[@]}" "$wd/$x") ;;
esac
done
if [ -n "$vhdl" ]; then
rm -f work-obj??.cf
docmd ghdl -i "${vhdl_args[@]}" "${vhdf[@]}" || exit $?
# docmd ghdl -a "${vhdl_args[@]}" $(sed -n -e 's/^file \. "\([^"]*\)".*/\1/;T;p' work-obj??.cf | tac)
cmd="ghdl --latches ${vhdl_args[*]} $* -e $top" # FIXME: quote properly
fi
if [ -n "$vf" ]; then
# should I support -vlog95/-vlog2k? maybe also other options, like -D?
# should I support pre-run verification w/ iverilog for better error msgs?
cmd="read_${sysv}verilog ${ysysv} ${libpatha[*]/#/-I} ${sysv:+${defargs[*]}} ${vf[*]}" # FIXME: quote properly
fi
do_yosys() {
(
echo "$cmd"
if [ init = "$1" ]; then
if [ ${#arch[@]} = 1 ]; then
# it's very frustrating how different the synth_* routines are.
# gowin proc+flatten before coarse by default
# ice40 proc always flatten by default before coarse
# ecp5 proc+flatten in coarse always
# nexus proc+flatten in coarse always
# xilinx proc before coarse (+ a ton of other crap), flatten only w/ -flatten
# I suppose adding proc; flatten here wouldn't hurt
echo "synth_${arch[0]} -run :coarse ${top:+-top $top}; proc; flatten; proc;;;"
# proc doesn't catch somme whiteboxes (at least ecp5, xilinx), which
# should really be ignored anyway, since we're not using yosys for
# simulation.
# I'd like to drop it, but raw.json is used to obtain info on "top"
# If only there were a way to pass -nowb into the synth command..
case "${arch[0]}" in
ecp5) echo "read_verilog -nowb -lib -specify +/ecp5/cells_sim.v +/ecp5/cells_bb.v" ;;
xilinx) echo "read_verilog -nowb -lib -specify +/xilinx/cells_sim.v +/xilinx/cells_xtra.v" ;;
gowin) echo "read_verilog -nowb -specify -lib +/gowin/cells_sim.v" ;;
ice40) echo "read_verilog -nowb -D ICE40_HX -lib -specify +/ice40/cells_sim.v" ;;
esac
else
echo "prep -flatten ${top:+-top $top};;;"
fi
# ecp5 leaves processes in what should be blackbox modules
# so does xilinx
echo "write_json ${opref}raw.json"
if [ -n "$doadd" ]; then
echo "techmap; opt -full; extract_fa;;;"
echo write_json ${opref}fa.json
fi
exit 0
fi
echo "design -save raw"
for a in "${arch[@]}"; do
test -n "$pop" && echo $pop; pop="design -load raw"
case $a in
ice40) sopt=-dsp ;;
xilinx) sopt=-flatten ;; # -abc9 fails sometimes
*) sopt= ;;
esac
echo synth_$a ${sopt} ${top:+-top $top}
echo write_json ${opref}${a}.json
done
) | docmd yosys "${yargs[@]}" && return
test -n "$keep" || exit 1
}
for x in "${arch[@]}"; do
rm -f {pnr,}$x.{png,svg,json} $x.{bin,cfg,svf,asc,sdf}
done
do_yosys init
test -n "$schem" && docmd json2png ${opref}raw.json
# the default test rig bombs on extract_fa, so do it before adding the rig
if [ -n "$doadd" ]; then
cmd="read_json alu.json"
for lib in "${libpath[@]}"; do test -f "$lib"/fa2add.jq && break; done
docmd -o alu.json jq -f "$lib"/fa2add.jq fa.json
fi
# If the number of inputs/outputs is too large, reduce pin usage by
# using a serial access method, implemented by testrig.v and the
# mainline constructed below.
# Uses jq to extract data from one of the synth outputs, assuming that the
# synth outputs will all return the same set of inputs/outputs.
# Extract top module from JSON
topmod="$(jq -c < ${opref}raw.json '.modules|to_entries|
map(select(.value.attributes.top > 0))|.[]')"
xtop="$(printf %s "$topmod" | jq -r .key)"
test -n "$xtop" && top="$xtop"
echo "Top: $top"
# Extract its port list
ports="$(printf %s "$topmod" | jq -c '.value.ports|to_entries|
map(select(.value.direction=="input" or .value.direction=="output"))|
map({direction:.value.direction,name:.key,bits:(.value.bits|length)})')"
# Count ports
input=0; output=0
eval $(printf %s "$ports" | jq -r 'group_by(.direction)|
map({direction:.[0].direction,bits:map(.bits)|add})|.[]|
.direction+"="+(.bits|tostring)')
# Force use of test rig if # of ports is high, regardless of -T option
# Then again, Tang Primer has a BG256 package w/ very few unused pins
# Gowin: QN88(9): 70; QN48(1/4/Z): 40/41 PG256(4+): 207 LQ144(all):116-120
# MG64: 55 (4SR) PG484: 319 (GW2A) UG484: even more
# ice40-UltraPlus: sg48: 39
# ecp5: cabga381: 197-205 cabga756(85k): 365
# nexus: ??? not really well supported/tested
# xilinx: clg400(z): 100 ffg676(k): 400
# test $((input+output)) -gt 39 && tr=y
if [ -n "$tr" -a ! -f "$mk_tstrig" ]; then
for lib in "${libpath[@]}"; do test -f "$lib/$mk_tstrig" && break; done
mk_tstrig="$lib/$mk_tstrig"
fi
test -n "$tr" -a -f "$mk_tstrig" && . "$mk_tstrig"
for a in "${arch[@]}"; do
case "$a" in
gowin|xilinx) ;;
*) use_yosys=y ;;
esac
done
test -n "$use_yosys" && do_yosys
find_lib() {
local ret= l
for l in . "$wd" "${libpatha[@]}"; do
local f="$l/$1"
test -z "$ret" -a -f "$f" && ret="$f"
done
case "$ret" in ./*) ret="`pwd`/$ret";; esac
printf %s "$ret"
}
find_extra() {
local ext="$1" ret= p f
shift
ret="$(find_lib "$do.$ext")"
for p in "" "$do"; do
for f; do
local n="$(find_lib "$p$f.$ext")"
test -n "$n" && ret="$n"
done
done
printf %s "$ret"
}
for a in "${arch[@]}"; do
o=${opref##*/}$a
cmd=(nextpnr-$a --timing-allow-fail --json ../${o}.json ${delay:+--sdf ${o}.sdf --report ${o}-report.json} --write ${o}-pnr.json --ignore-loops)
case "$a" in
gowin)
for d in "${gwdev[@]}"; do
setdo
od="$d"
case "$d" in
9) d=GW1NR-LV9QN88PC6/I5 ;; # tang nano 9k
4|GW1NSR-LV4CQN48) d=GW1NSR-LV4CQN48PC7/I6 ;; # tang nano 4k
G*QN?8) d=${d}C6/I5 ;; # serveral devices have this speed
[zZ]*) d=GW1NZ-LV1QN48C6/I5 ;; # tang nano 1k
GW2A|[pP]*) d=GW2A-LV18PG256C8/I7 ;; # Tang Primer 20K
[^G]*) d=GW1N-LV${d%[kK]}QN48C6/I5 ;; # tang nano original
*) ;;
esac
rd="${d%%??/*}"
cst="$(find_extra cst $a{,-{"$od","$rd"}})"
sdc="$(find_extra sdc $a{,-{"$od","$rd"}})"
#######################
# Actually, forget apicula and its spinoffs. It isn't ready for
# prime time. Just use the Gowin toolset. It's free of charge.
# Missing primitives in apicula[/nextpnr-gowin/yosys' synth_gown]:
# [note: some of these may be not be real primitives on-device.
# in particular, 36x36 mul isn't, and DL* might not be]
# MUX2_MUX{8,16,32} (but equivalent to MUX2_LUT{6,7,8})
# MUX{4,8,16,32} (but maybe yosys uses LUT combiners for same effect)
# LUT{5,6,7,8} (but yosys does synthesize equivalents)
# ALU has different ALU_MODE interpretation (string vs. #)
# various DFFs have different INIT interpretation (ignored anyway?)
# DL[N]{,C,P}[E] DL{C,P}EA (latches)
# Related to DFFs/Latches: Gowin says direct access, but apicula not
# IDDR{,C,_MEM} ODDR_MEM {OSER,IDES}{{4,8}{,_MEM},10,16} {I,O}VIDEO
# (only ODDR[C])
# IODELAY{,A,B,C} IEM {,ELVDS_}I[O]BUF_R
# {E,T}LVDS_{I,O,T,IO}BUF (but maybe just {I,O,T}BUF w/ IOPORT?
# MIPI_[I][O]BUF MIPI_IBUF_{HS,LP} I3C_IOBUF
# ROM16 (but that's just an alias for LUT4)
# ROM{,X9} (but that's just SP{,X9} w/ write disabled)
# dsp: PADD{9,18} MULT{9X9,18X18,36X36} MULTALU{18,36}X18
# MULTADDALU18X18 ALU54D
# DSP56_{12X12{,SUM},27X{18,36}} (AT models?)
# MULT{12X12,27X36} (definitely AT models)
# clock: PLL (obsolete anyway) PLL{VR,O,G} DLL{,DLY} CLKDIV{,2,G}
# DHCEN[C] BUFG DCS DQCE OSC{O,W} DCCG
# DQS OTP SAMB (???)
# User Flash: FLASH{96K[A],256K,608K,128K,64K[Z]}
# [E]MCU USB20_PHY ADC SPMI I3C BANDGAP r{SDP,ROM}{,X9} MIPI_DPHY_RX
# AE350_SOC
# [S]DP{,X9}B pROM{,X9} (are these just aliases for [S]DP/ROM?)
# SPMI_DEBUG_GOWIN GW_JTAG (may not be on hw)
# GTR12_{PMAC,QUAD,UPAR}_DB MIPI_DPHY_RX_DB (debug: no hw?)
# I don't think there are primitives for the GW1NRF-4B SoC.
#
# In addition, missing support for on-chip "external" hardware:
# HyperRAM PSRAM NOR_Flash SDR/DDR_SDRAM (uses undocumented special
# port names for raw access, I guess, but indended to only be used
# with nasty encrypted ipcore modules)
#
# Also, only really supports about 6 devices at all. Then again,
# the gowin toolkit doesn't seem to support some advertised devices,
# so they may not be available for purchase. The GW2AN-X
# series are not even supported by gowin_unpack due to malformed
# (according to apicula) data.
if [ -z "$use_yosys" ]; then
if [ "${#defs[@]}" -gt 0 ]; then
deffile=/tmp/def$$.v
addtrap "rm -f $deffile"
for x in "${defs[@]}"; do
echo "\`define ${x%%=*} ${x#*=}"
done >$deffile
else
deffile=
fi
ob="${do%-*}"
(
echo "set_device -name [regsub {(^[^-]*-)[^0-9]*([0-9]*([BCDZ]|P5)?).*} {$d} {\1\2}]" "{$d}"
test -n "$top" && echo "set_option -top_module {$top}"
for x in gen_{sdf,text_timing_rpt} print_all_synthesis_warning \
use_{done,ready,mspi,sspi,i2c,reconfign}_as_gpio \
show_all_warn bit_compress bit_incl_bsram_init hotboot; do
# use_{reconfign,jtag}_as_gpio \
echo "set_option -$x 1"
done
echo "set_option -bit_security 0"
echo "set_option -cst_warn_to_error 0"
test -n "$ob" && echo "set_option -output_base_name {$ob}"
test -n "$sysv$ysysv" && echo "set_option -verilog_std sysv2017"
test -n "$vhdl" && echo "set_option -vhdl_std vhd2008"
test -n "$deffile" && echo "add_file $deffile"
for x in "${f[@]}"; do
case "$x" in
*/prim_syn.v|*/gowin_prim.v) ;;
*) echo "add_file {$x}" ;;
esac
done
for va in "${vhdl_args[@]}"; do
case "$va" in
--work=*) for x in "${vhdf[@]}"; do
# hack: skip top-level at least
# otherwise gives "not yet analyzed" error
# I need some way of filtering, I guess.
# maybe there's a better way around it
# I should at least get this from the ghdl .cf file
test "${top}.vhd" = "${x##*/}" && continue
echo "set_file_prop -lib {${va#--work=}} {$x}"
done
# echo "set_option -top_module {${va#--work=}.$top}"
;;
--std=93) echo "set_option -vhdl_std vhd1993" ;;
--std=08) echo "set_option -vhdl_std vhd2008" ;;
esac
done
test -n "$cst" && echo "add_file {$cst}"
test -n "$sdc" && echo "add_file {$sdc}"
echo "run all"
) >${do}gowin.tcl
ob="${ob:-project}"
#rm -rf impl
# Note: gw_sh on my system wraps it in nonet (no calling home for you!)
docmd $GOWINHOME/IDE/bin/gw_sh ${do}gowin.tcl | \
sed -E 's/^((ERROR|WARN|NOTE)[^:]*: )(.*)\("([^"]*)"(:[0-9]*)\)$/\4\5:\1\3/'
test -f impl/pnr/"$ob".fs || continue
find impl -type f -exec chmod -x {} \;
of="${cst%.cst}"; of="${of##*/}"; of="${of:-$a}"
of="${do}${of#$do}"
for x in fs rpt.txt; do
/bin/mv -f impl/pnr/"$ob.$x" "$of.$x"
done
cat "$of".rpt.txt
continue
fi
#######################
d="${d/R-/-}" # stupid nextpnr-gowin/apicula
d="${d/PC/C}" # stupid nextpnr-gowin/apicula
d="${d/CQN/QN}" # stupid nextpnr-gowin/apicula
docmd "${cmd[@]}" --device "$d" ${cst:+--cst} ${cst} || break
of="${cst%.cst}"; of="${of##*/}"; of="${of:-$a}"
of="${do}${of#$do}"
# -c (compress) is currently broken:
# /bslib.py", line 96, in write_bitstream
# [key8Z, key4Z, key2Z] = [i for i,val in enumerate(lst) if val==0][0:3]
# ValueError: not enough values to unpack (expected 3, got 0)
docmd gowin_pack -d "$d" -o "$of".bit ${o}-pnr.json
# openFPGALoader ...
done
;;
ice40)
for d in "${icedev[@]}"; do
setdo
case "$d" in
*/*) pkg="${d#*/}" ;;
*) pkg=sg48 ;;
esac
d="${d%%/*}"
case "$d" in
--*) ;;
*) d=--$d ;;
esac
pcf="$(find_extra pcf $a{,-{"$d#--"{,"$pkg"}}})"
of="${pcf%.pcf}"; of="${of##*/}"; of="${of:-$a}"
of="${do}${of#$do}"
docmd "${cmd[@]}" --asc "${of}.asc" "$d" --package "$pkg" ${pcf:+--pcf "$pcf"} || break
docmd icepack "${of}.asc" "${of}.bit"
done
# openFPGALoader ...
;;
ecp5)
for d in "${ecp5dev[@]}"; do
setdo
case "$d" in
*/*) pkg="${d#*/}" ;;
*) pkg=CABGA381 ;;
esac
d="${d%%/*}"
case "$d" in
--*) ;;
*) d=--$d ;;
esac
lpf="$(find_extra lpf $a{,-{"$d#--"{,"$pkg"}}})"
of="${lpf%.lpf}"; of="${of##*/}"; of="${of:-$a}"
of="${do}${of#$do}"
docmd "${cmd[@]}" "--textcfg" "${of}.cfg" "$d" --package $pkg ${lpf:+--lpf "$lpf" --lpf-allow-unconstrained} || break
docmd ecppack --svf "${of}.svf" "${of}.cfg" "${o}.bit"
done
;;
nexus)
for d in "${nexusdev[@]}"; do
setdo
pdc="$(find_extra pdc $a{,-"$d"} "$d")"
of="${pdc%.pdc}"; of="${of##*/}"; of="${of:-$a}"
of="${do}${of#$do}"
docmd "${cmd[@]}" --device "$d" --asc "${of}.asc" ${pdc:+--pdc "$pdc"} || continue
done
;;
xilinx)
for d in "${xdev[@]}"; do
setdo
case "$d" in
z) d=xc7z010 ;;
k) d=xc7k325t/ffg676-1 ;;
esac
case "$d" in
*/*) pkg="${d#*/}"; pkg="${pkg%%-*}" ;;
*) pkg=clg400 ;;
esac
case "$d" in
*-*) spd="${d#*-}" ;;
*) spd=1 ;;
esac
d="${d%%[/-]*}$pkg${spd:+-}$spd"
# Maybe if I get another Xilinx board, I'll tighten up the
# device name parsing. I only care about xc7z010 right now.
rd="$d"
case "$d" in
zynq7*) fam=zynq7; rd="xc7z${rd#zynq7}" ;;
xc7z*) fam=zynq7 ;;
artix7*) fam=zynq7; rd="xc7a${rd#zynq7}" ;;
xc7a*) fam=artix7 ;;
spartan7*) fam=zynq7; rd="xc7s${rd#zynq7}" ;;
xc7s*) fam=spartan7 ;;
kintex7*) fam=kintex7; rd="xc7k${rd#kintex7}" ;;
xc7k*) fam=kintex7 ;;
*) echo "Unsupported device $x"; exit 1 ;;
esac
bd="${d#xc7[akz]}"
bd0="${d%$bd}"
bd="$bd0${bd/[^t0-9]*/}"
xdc="$(find_extra xdc $a{,-"$bd"}{,"-$pkg"})"
sdc="$(find_extra sdc $a{,-"$bd"}{,"-$pkg"})"
of="${xdc%.xdc}"; of="${of##*/}"; of="${of:-$a}"
of="${do}${of#$do}"
#######################
# Actually, forget nextpnr-xilinx. It isn't ready for prime time.
# It doesn't support MMCME2 (and maybe others), and It won't even
# compile my HDMI demo:
#
# ERROR: Failed to route arc 0 of net 'genblk1[2].ddr_out', from SITEWIRE/OLOGIC_X0Y96/OUTFF_Q to SITEWIRE/IOB_X0Y95/O_IN.
#
# Note that f4pga is not a viable alternative. In addition to
# using the despicable conda and way too much Python, it produces
# unusable results in my HDMI tests, and doesn't support MMCME2 or
# BUFR or xc7k325t. I have removed all support for f4pga from my
# system.
#
# Just use Vivado. Unlike the Gowin toolset, it it's only partially
# free of charge, but at least it supports the EBAZ4205, my primary
# target. Too bad it doesn't also support the ZYJZGW as well
# (xc7k325t).
# is also at least missing MMCME2. It also fails to compile my
# ebaz demo with a routing error (ODDR->OBUFDS). Since it's probably
# yosys' fault that the HDMI is broken, it's probably broken with
# nextpnr-xilinx as well.
if [ -z "$use_yosys" ]; then
# Vivado
# As of now:
# Vivado 2017.2 barfs on my zynq macro library
# Vivado 2022.2 crashes in GUI on trying to start processing.
# I guess this is what finally motivated me to try a TCL script, but:
# Vivado 2022.2 crashes on completion of routing (corrupted memory?)
# This is due to my "nonet" wrapper. I guess that for now I'll
# disable it, since I don't actually see it calling home.
# Note: vivado on my system wraps it in nonet (no calling home for you!)
# It is possible to use 2017.2 anyway, if I use verilator -P -E to
# preprocess Verilog files, but I'd rather not deal with it.
# Note: vivado on my system sources the settings file internally:
#. /opt/Xilinx/Vivado/2022.2/settings64.sh
# Note: use of ${.../../..&..} is a bashism. I'm already using bash, so whatever.
# behavior of ${a[*]/...} is probably bash-specific as well.
# tf=("${vf[@]/#/read_verilog }" "${vhdf[@]/#/read_vhdl }")
v2k=-vhdl2008
vl=
for va in "${vhdl_args[@]}"; do
case "$va" in
--work=*) vl="-lib {${va#--work=}}" ;;
--std=93) v2k= ;;
--std=08) v2k=-vhdl2008 ;;
esac
done
test -n "$sysv" && ysysv=-sv
cat >build.tcl <<EOF
create_project -in_memory -part $rd
${vf[*]/*/read_verilog ${ysysv} {&\}
}
${vhdf[*]/*/read_vhdl $v2k $vl {&\}
}
${xdc:+read_xdc {$xdc\}}
${sdc:+read_xdc {$sdc\}}
synth_design ${defs[*]/*/-verilog_define {&\}} -top $top -part $rd -include_dirs {{$wd}${libpatha:+ }${libpatha[*]/*/{&\}}}
report_timing_summary -file synth_timing_summary.rpt
report_power -file synth_power.rpt
write_checkpoint -force synthesis
opt_design
place_design
phys_opt_design
report_timing_summary -file place_timing_summary.rpt
write_checkpoint -force place
# I cheat on one of the MMCMs: 1207 VCO w/ max 1200
# If there is a way to turn it into a warning, I can't find the docs
set_property IS_ENABLED FALSE [get_drc_checks PDRC-34]
# I guess if there are too many unconstrained I/O, it fails.
set_property IS_ENABLED FALSE [get_drc_checks UCIO-1]
route_design
# !!!!!!!!!!!!!!!!!!! Crash !!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Either a seg fault or:
# free(): invalid pointer
# Abnormal program termination (6)
# Probably trying 'net access, failing, and executing untested code
report_timing_summary -datasheet -file route_timing_summary.rpt
# This is a much more useful timing report to me:
report_design_analysis -complexity -logic_level_distribution -qor_summary -timing -setup -hold -show_all -congestion -file design_analysis.rpt
report_timing -sort_by group -max_paths 100 -path_type summary -file route_timing.rpt
report_clock_utilization -file clock_util.rpt
report_control_sets -force -file control_sets.rpt
report_qor_suggestions -file qor_suggestions.rpt
report_ssn -file ssn.rpt
report_utilization -force -file route_util.rpt
report_power -file route_power.rpt
report_drc -file route_drc.rpt
write_checkpoint -force route
set_property BITSTREAM.GENERAL.COMPRESS TRUE [current_design]
write_bitstream -force $do.bit
EOF
docmd vivado -mode batch -nojournal -nolog -source build.tcl
continue
fi
#######################
# nextpnr-xilinx
case "$d" in
*:*) db="${d#*:}"; d="${d%%:*}" ;;
*) db="$d" ;;
esac
db="${db%%[/-]*}"
db="${NEXTPNR_XILINX_DB:-/usr/local/prjxray}/$db"
test -f "$db" || db="${db}.bin"
test -f "$db" || db=/usr/local/prjxray/$bd
test -f "$db" || db="${db}.bin"
if [ ! -f "$db" ]; then
bdb="${db##*/}"
bdb="${bdb%.bin}"
cat <<EOF
${db%.bin}{,.bin} not found.
You can override the path with NEXTPNR_XILINX_DB.
You can override the db file name by adding :<dbname> to the dev name $d.
You can generate the database from nextpnr-xilinx after building:
python3 xilinx/python/bbaexport.py --device $d --bba ${bdb}.bba
[build/]bbasm --l ${bdb}.{bba,bin}
EOF
exit 1
fi
dbd="${PRJXRAY_DB:-/usr/local/prjxray/prjxray-db}/$fam"
if [ ! -d "$dbd" ]; then
echo "Can't find $dbd. You can clone from https://github.com/SymbiFlow/prjxray-db"
exit 1
fi
if [ ! -d "$dbd/$rd" ]; then
echo "Can't find $rd in $dbd. Invalid device name?"
exit 1
fi
# no install target for the Python crap. Expected to use pip, as usual
f2f=fasm2frames.py
type "$f2f" >/dev/null 2>&1 || f2f="${PRJXRAY_UTILS:-/usr/local/prjxray/utils}"/$f2f
# xc7frames2bit should be installed to /usr/local/bin
f2b=xc7frames2bit
type "$f2b" >/dev/null 2>&1 || f2b="${PRJXRAY_UTILS:-/usr/local/prjxray/utils}"/../tools/$f2b
if ! type "$f2f" >/dev/null 2>&1 && ! type "$f2b" >/dev/null 2>&1; then
echo "Can't find prjxray utils; set PRJXRAY_UTILS."
exit 1
fi
if grep '^[^#]*get_nets' "$xdc" >/dev/null; then
grep -v '^[^#]*get_nets' "$xdc" >"${xdc##*/}"
xdc="${xdc##*/}"
fi
docmd "${cmd[@]}" --fasm "${of}.fasm" --chipdb "$db" ${xdc:+--xdc "$xdc"} || break
docmd -o "${of}.frames" "$f2f" --db-root "$dbd" --part $rd "${of}.fasm"
docmd "$f2b" --part_file "$dbd/$rd/part.yaml" --part_name "${d%-*}" \
--frm_file "${of}.frames" --output_file "${of}.bit"
done
test zynq7 = "$fam" || continue
echo "all: { ${of}.bit }" >"${of}.bif"
docmd bootgen -w on -arch zynq -image "${of}.bif" -process_bitstream bin
if false; then
# FIXME: Add bootgen support
(
echo "all: {"
echo " // [bootimage] part // part is a generated boot image"
echo " [bootloader] fsbl.elf"
echo " [alignment=64] u-boot.elf"
echo " [init] ebaz.int"
for x in "${int[@]}"; do
echo " [init] \"$x\"" >>boot.bif
done
echo "}"
) >boot.bif
# Default register inits: clocks, ethernet, SD, UART1
# Actually, the EBAZ ROM doesn't initialize any registers, so the FSBL
# is probably sufficient.
# In any case, limited to:
#UART 1 E000_1000 to E000_1FFC
#Quad-SPI E000_D000 to E000_DFFC
#SMC E000_E000 to E000_EFFC
#SDIO 0 E010_0004 to E010_0FFC except E010_0058
#DDR Memory F800_6000 to F800_6FFC
#PLL, Peripheral, AMBA and
#CPU clock controls
# F800_0100 to F800_0234 except PS Reset Ctrl: F800_0200, Reserved: F800_01B0
#SWDT Reset F800_024C
#SWDT clock,
#TZ configuration,
#PS ID code,
#DDR configuration,
#MIO pins, SD card WP/CD
#routing F800_0304 to F800_0834
#Reserved F800_0A00 to F800_0A8C
#Reserved, GPIO and DDR I/O controls
# F800_0AB0 to F800_0B74
(
echo "// .set. 0xF8000120 = 0x1F000200;"
# note: expressions, decimal #s are allowed.
# ... up to 256 register inits
# Recommended for fast NAND boot (1st line also for SD boot):
# slcr.ARM_CLK_CTRL Both Both 0x1F000200 CPU divisor = 2 (433 MHz)
# slcr.SMC_CLK_CTRL Both Both 0x00000921 Baud rate divisor = 9 (96 MHz, 10.4 ns)
# Timing Parameters:
# smc.set_cycles Both Non-secure 0x00225133 t_rr=2, t_ar=1, t_clr=1, t_wp=2,
# t_rea=1, t_wc=3, t_rc=3
# smc.set_opmode 8-bit Non-secure 0x00000000 8-bit width
# 16-bit Non-secure 0x00000001 16-bit width
# smc.direct_cmd Both Non-secure 0x02400000 Select ModeReg and UpdateRegs
) >ebaz.int
docmd bootgen -w on -arch zynq -image boot.bif -o boot.bin
fi
;;
esac
test -f ${o}-pnr.json -a -n "$schem" && docmd json2png ${o}-pnr || :
done