diff options
-rw-r--r-- | docs/format.html | 2 | ||||
-rw-r--r-- | docs/index.html | 16 | ||||
-rw-r--r-- | docs/logic_tile.html | 6 | ||||
-rw-r--r-- | icebox/.gitignore | 1 | ||||
-rw-r--r-- | icebox/Makefile | 10 | ||||
-rw-r--r-- | icebox/icebox.py | 495 | ||||
-rwxr-xr-x | icebox/icebox_chipdb.py | 14 | ||||
-rwxr-xr-x | icebox/icebox_vlog.py | 11 | ||||
-rw-r--r-- | icebram/icebram.cc | 16 | ||||
-rw-r--r-- | icefuzz/Makefile | 5 | ||||
-rw-r--r-- | icefuzz/fuzzconfig.py | 19 | ||||
-rw-r--r-- | icefuzz/icecube.sh | 56 | ||||
-rw-r--r-- | icefuzz/tests/colbuf_io_lm4k.sh | 41 | ||||
-rw-r--r-- | icefuzz/tests/colbuf_logic_lm4k.sh | 29 | ||||
-rwxr-xr-x | icefuzz/tests/colbuf_ram_lm4k.sh | 56 | ||||
-rw-r--r-- | icefuzz/tests/io_latched_lm4k.sh | 31 | ||||
-rw-r--r-- | icefuzz/tests/ioctrl_lm4k.py | 21 | ||||
-rwxr-xr-x | icefuzz/tests/ioctrl_lm4k.sh | 33 | ||||
-rwxr-xr-x | icefuzz/tests/pllauto/pllauto.py | 3 | ||||
-rw-r--r-- | icemulti/icemulti.cc | 16 | ||||
-rw-r--r-- | icepack/icepack.cc | 55 | ||||
-rw-r--r-- | icepll/icepll.cc | 29 | ||||
-rw-r--r-- | iceprog/iceprog.c | 157 | ||||
-rw-r--r-- | icetime/icetime.cc | 42 |
24 files changed, 1096 insertions, 68 deletions
diff --git a/docs/format.html b/docs/format.html index 698a321..8d36151 100644 --- a/docs/format.html +++ b/docs/format.html @@ -96,7 +96,7 @@ in the FPGA. The following sequence is used to program an SRAM cell: <p> The bank width and height parameters reflect the width and height of the SRAM bank. A large SRAM can -be written in smaller junks. In this case height parameter may be smaller and the offset parameter +be written in smaller chunks. In this case height parameter may be smaller and the offset parameter reflects the vertical start position. </p> diff --git a/docs/index.html b/docs/index.html index 6b3ff5e..919122e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -16,6 +16,7 @@ <h1>Project IceStorm</h1> <p> +<b>2018-01-30:</b> Released support for iCE40 UltraPlus devices.<br/> <b>2017-03-13:</b> Released support for LP384 chips (in all package variants).<br/> <b>2016-02-07:</b> Support for all package variants of LP1K, LP4K, LP8K and HX1K, HX4K, and HX8K.<br/> <b>2016-01-17:</b> First release of IceTime timing analysis. Video: <a href="https://youtu.be/IG5CpFJRnOk">https://youtu.be/IG5CpFJRnOk</a><br/> @@ -39,7 +40,9 @@ fully open source Verilog-to-Bitstream flow for iCE40 FPGAs. <p> The focus of the project is on the iCE40 LP/HX 1K/4K/8K chips. (Most of the -work was done on HX1K-TQ144 and HX8K-CT256 parts.) +work was done on HX1K-TQ144 and HX8K-CT256 parts.) The iCE40 UltraPlus parts +are also supported, including DSPs, oscillators, RGB and SPRAM. iCE40 LM, Ultra +and UltraLite parts are not yet supported. </p> <h2>Why the Lattice iCE40?</h2> @@ -74,6 +77,8 @@ Here is a list of currently supported parts and the corresponding options for ar <table class="ctab"> <tr><th>Part</th><th>Package</th><th>Pin Spacing</th><th>I/Os</th><th>arachne-pnr opts</th><th>icetime opts</th></tr> <tr><td>iCE40-LP1K-SWG16TR</td><td>16-ball WLCSP (1.40 x 1.48 mm)</td><td>0.35 mm</td><td>10</td><td>-d 1k -P swg16tr</td><td>-d lp1k</td></tr> +<tr><td>iCE40-UP3K-UWG30</td><td>30-ball WLCSP (2.15 x 2.55 mm)</td><td>0.40 mm</td><td>21</td><td>-d 5k -P uwg30</td><td>-d up5k</td></tr> +<tr><td>iCE40-UP5K-UWG30</td><td>30-ball WLCSP (2.15 x 2.55 mm)</td><td>0.40 mm</td><td>21</td><td>-d 5k -P uwg30</td><td>-d up5k</td></tr> <tr><td>iCE40-LP384-CM36</td><td>36-ball ucBGA (2.5 x 2.5 mm)</td><td>0.40 mm</td><td>25</td><td>-d 384 -P cm36</td><td>-d lp384</td></tr> <tr><td>iCE40-LP1K-CM36</td><td>36-ball ucBGA (2.5 x 2.5 mm)</td><td>0.40 mm</td><td>25</td><td>-d 1k -P cm36</td><td>-d lp1k</td></tr> <tr><td>iCE40-LP384-CM49</td><td>49-ball ucBGA (3 x 3 mm)</td><td>0.40 mm</td><td>37</td><td>-d 384 -P cm49</td><td>-d lp384</td></tr> @@ -88,6 +93,7 @@ Here is a list of currently supported parts and the corresponding options for ar <tr><td>iCE40-LP8K-CM225</td><td>225-ball ucBGA (7 x 7 mm)</td><td>0.40 mm</td><td>178</td><td>-d 8k -P cm225</td><td>-d lp8k</td></tr> <tr><td>iCE40-HX8K-CM225</td><td>225-ball ucBGA (7 x 7 mm)</td><td>0.40 mm</td><td>178</td><td>-d 8k -P cm225</td><td>-d hx8k</td></tr> <tr><td>iCE40-LP384-QN32</td><td>32-pin QFN (5 x 5 mm)</td><td>0.50 mm</td><td>21</td><td>-d 384 -P qn32</td><td>-d lp384</td></tr> +<tr><td>iCE40-UP5K-SG48</td><td>48-pin QFN (7 x 7 mm)</td><td>0.50 mm</td><td>39</td><td>-d 5k -P sg48</td><td>-d up5k</td></tr> <tr><td>iCE40-LP1K-QN84</td><td>84-pin QFNS (7 x 7 mm)</td><td>0.50 mm</td><td>67</td><td>-d 1k -P qn84</td><td>-d lp1k</td></tr> <tr><td>iCE40-LP1K-CB81</td><td>81-ball csBGA (5 x 5 mm)</td><td>0.50 mm</td><td>62</td><td>-d 1k -P cb81</td><td>-d lp1k</td></tr> <tr><td>iCE40-LP1K-CB121</td><td>121-ball csBGA (6 x 6 mm)</td><td>0.50 mm</td><td>92</td><td>-d 1k -P cb121</td><td>-d lp1k</td></tr> @@ -97,15 +103,12 @@ Here is a list of currently supported parts and the corresponding options for ar <tr><td>iCE40-HX1K-VQ100</td><td>100-pin VQFP (14 x 14 mm)</td><td>0.50 mm</td><td>72</td><td>-d 1k -P vq100</td><td>-d hx1k</td></tr> <tr><td>iCE40-HX1K-TQ144</td><td>144-pin TQFP (20 x 20 mm)</td><td>0.50 mm</td><td>96</td><td>-d 1k -P tq144</td><td>-d hx1k</td></tr> <tr><td>iCE40-HX4K-TQ144</td><td>144-pin TQFP (20 x 20 mm)</td><td>0.50 mm</td><td>107</td><td>-d 8k -P tq144:4k</td><td>-d hx8k</td></tr> +<tr><td>iCE40-HX4K-BG121</td><td>121-ball caBGA (9 x 9 mm)</td><td>0.80 mm</td><td>93</td><td>-d 8k -P bg121:4k</td><td>-d hx8k</td></tr> +<tr><td>iCE40-HX8K-BG121</td><td>121-ball caBGA (9 x 9 mm)</td><td>0.80 mm</td><td>93</td><td>-d 8k -P bg121</td><td>-d hx8k</td></tr> <tr><td>iCE40-HX8K-CT256</td><td>256-ball caBGA (14 x 14 mm)</td><td>0.80 mm</td><td>206</td><td>-d 8k -P ct256</td><td>-d hx8k</td></tr> </table> <p> - Experimental support is also included for one iCE40 UltraPlus device, the iCE40-UP5K-SG48, including support for some of - the new UltraPlus features such as DSPs, SPRAM and internal oscillators. -</p> - -<p> Current work focuses on further improving our timing analysis flow. </p> @@ -534,6 +537,7 @@ Links to related projects. Contact me at clifford@clifford.at if you have an int <li><a href="https://media.ccc.de/v/32c3-7139-a_free_and_open_source_verilog-to-bitstream_flow_for_ice40_fpgas">A Free and Open Source Verilog-to-Bitstream Flow for iCE40 FPGAs [32c3]</a> <li><a href="https://www.youtube.com/watch?v=s7fNTF8nd8A">Synthesizing Verilog for Lattice ICE40 FPGAs (Paul Martin)</a> <li><a href="https://github.com/Obijuan/open-fpga-verilog-tutorial/wiki">A Spanish FPGA Tutorial using IceStorm</a> +<li><a href="http://hedmen.org/icestorm-doc/icestorm.html">IceStorm Learner’s Documentation</a> </ul> <h3>Other FPGA reverse engineering projects</h3> diff --git a/docs/logic_tile.html b/docs/logic_tile.html index 982b25d..ab9adc7 100644 --- a/docs/logic_tile.html +++ b/docs/logic_tile.html @@ -29,7 +29,7 @@ The <i>span-4</i> and <i>span-12</i> wires are the main interconnect resource in </p> <p> -The bits marked <span style="font-family:monospace">routing</span> in the bitstream do enable switches (transfer gates) that can +The bits marked <span style="font-family:monospace">routing</span> in the bitstream enable switches (transfer gates) that can be used to connect wire segments bidirectionally to each other in order to create larger segments. The bits marked <span style="font-family:monospace">buffer</span> in the bitstream enable tristate buffers that drive the signal in one direction from one wire to another. Both types of bits exist for routing between @@ -56,7 +56,7 @@ for this wire names.) The wires connecting the left and right horizontal span-4 </p> <p> -The wires <span style="font-family:monospace">sp4_h_l_36</span> to <span style="font-family:monospace">sp4_h_l_47</span> terminate in the cell, so do the wires <span style="font-family:monospace">sp4_h_r_0</span> to <span style="font-family:monospace">sp4_h_r_11</span>. +The wires <span style="font-family:monospace">sp4_h_l_36</span> to <span style="font-family:monospace">sp4_h_l_47</span> terminate in the cell as do the wires <span style="font-family:monospace">sp4_h_r_0</span> to <span style="font-family:monospace">sp4_h_r_11</span>. </p> <p> @@ -150,7 +150,7 @@ Each logic tile has 32 local tracks. They are organized in 4 groups of 8 wires e <p> The span wires, global signals, and neighbour outputs can be routed to the local tracks. But not -every of those signals can be routed to every of the local tracks. Instead there is a different +all of those signals can be routed to all of the local tracks. Instead there is a different mix of 16 signals for each local track. </p> diff --git a/icebox/.gitignore b/icebox/.gitignore index 035ca9c..0cd67f6 100644 --- a/icebox/.gitignore +++ b/icebox/.gitignore @@ -1,5 +1,6 @@ chipdb-1k.txt chipdb-5k.txt +chipdb-lm4k.txt chipdb-8k.txt chipdb-384.txt __pycache__ diff --git a/icebox/Makefile b/icebox/Makefile index a26d80c..5f4d47a 100644 --- a/icebox/Makefile +++ b/icebox/Makefile @@ -1,6 +1,6 @@ include ../config.mk -all: chipdb-384.txt chipdb-1k.txt chipdb-8k.txt chipdb-5k.txt +all: chipdb-384.txt chipdb-1k.txt chipdb-8k.txt chipdb-5k.txt chipdb-lm4k.txt chipdb-384.txt: icebox.py iceboxdb.py icebox_chipdb.py python3 icebox_chipdb.py -3 > chipdb-384.new @@ -14,6 +14,10 @@ chipdb-5k.txt: icebox.py iceboxdb.py icebox_chipdb.py python3 icebox_chipdb.py -5 > chipdb-5k.new mv chipdb-5k.new chipdb-5k.txt +chipdb-lm4k.txt: icebox.py iceboxdb.py icebox_chipdb.py + python3 icebox_chipdb.py -4 > chipdb-lm4k.new + mv chipdb-lm4k.new chipdb-lm4k.txt + chipdb-8k.txt: icebox.py iceboxdb.py icebox_chipdb.py python3 icebox_chipdb.py -8 > chipdb-8k.new mv chipdb-8k.new chipdb-8k.txt @@ -24,7 +28,7 @@ check: all python3 tc_logic_xpr.py clean: - rm -f chipdb-1k.txt chipdb-8k.txt chipdb-384.txt chipdb-5k.txt + rm -f chipdb-1k.txt chipdb-8k.txt chipdb-384.txt chipdb-5k.txt chipdb-lm4k.txt rm -f icebox.pyc iceboxdb.pyc install: all @@ -34,6 +38,7 @@ install: all cp chipdb-1k.txt $(DESTDIR)$(PREFIX)/share/icebox/ cp chipdb-8k.txt $(DESTDIR)$(PREFIX)/share/icebox/ cp chipdb-5k.txt $(DESTDIR)$(PREFIX)/share/icebox/ + cp chipdb-lm4k.txt $(DESTDIR)$(PREFIX)/share/icebox/ cp icebox.py $(DESTDIR)$(PREFIX)/bin/icebox.py cp iceboxdb.py $(DESTDIR)$(PREFIX)/bin/iceboxdb.py cp icebox_chipdb.py $(DESTDIR)$(PREFIX)/bin/icebox_chipdb$(PY_EXE) @@ -63,6 +68,7 @@ uninstall: rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-384.txt rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-1k.txt rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-8k.txt + rm -f $(DESTDIR)$(PREFIX)/share/icebox/chipdb-lm4k.txt -rmdir $(DESTDIR)$(PREFIX)/share/icebox .PHONY: all check clean install uninstall diff --git a/icebox/icebox.py b/icebox/icebox.py index 198b5f2..27bd243 100644 --- a/icebox/icebox.py +++ b/icebox/icebox.py @@ -79,6 +79,30 @@ class iceconfig: self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)] self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)] + def setup_empty_lm4k(self): + self.clear() + self.device = "lm4k" + self.max_x = 25 + self.max_y = 21 + + for x in range(1, self.max_x): + for y in range(1, self.max_y): + if x in (6, 19): + if y % 2 == 1: + self.ramb_tiles[(x, y)] = ["0" * 42 for i in range(16)] + else: + self.ramt_tiles[(x, y)] = ["0" * 42 for i in range(16)] + else: + self.logic_tiles[(x, y)] = ["0" * 54 for i in range(16)] + + for x in range(1, self.max_x): + self.io_tiles[(x, 0)] = ["0" * 18 for i in range(16)] + self.io_tiles[(x, self.max_y)] = ["0" * 18 for i in range(16)] + + for y in range(1, self.max_y): + self.io_tiles[(0, y)] = ["0" * 18 for i in range(16)] + self.io_tiles[(self.max_x, y)] = ["0" * 18 for i in range(16)] + def setup_empty_5k(self): self.clear() self.device = "5k" @@ -150,11 +174,15 @@ class iceconfig: if (x, y) in self.ipcon_tiles: return self.ipcon_tiles[(x, y)] return None - def pinloc_db(self): - if self.device == "384": return pinloc_db["384-qn32"] - if self.device == "1k": return pinloc_db["1k-tq144"] - if self.device == "5k": return pinloc_db["5k-sg48"] - if self.device == "8k": return pinloc_db["8k-ct256"] + def pinloc_db(self, package = None): + if package is None: + if self.device == "384": return pinloc_db["384-qn32"] + if self.device == "1k": return pinloc_db["1k-tq144"] + if self.device == "lm4k": return pinloc_db["lm4k-cm49"] + if self.device == "5k": return pinloc_db["5k-sg48"] + if self.device == "8k": return pinloc_db["8k-ct256"] + else: + return pinloc_db[self.device + "-" + package] assert False def gbufin_db(self): @@ -175,6 +203,8 @@ class iceconfig: def pll_list(self): if self.device == "1k": return ["1k"] + if self.device == "lm4k": + return ["lm4k"] if self.device == "5k": return ["5k"] if self.device == "8k": @@ -203,6 +233,19 @@ class iceconfig: entries.append((x, src_y, x, y)) return entries + # TODO(awygle) - actually capture 0 and 21 here + if self.device == "lm4k": + entries = list() + for x in range(self.max_x+1): + for y in range(self.max_y+1): + src_y = None + if 0 <= y <= 4: src_y = 4 + if 5 <= y <= 10: src_y = 5 + if 11 <= y <= 16: src_y = 16 + if 17 <= y <= 21: src_y = 17 + entries.append((x, src_y, x, y)) + return entries + if self.device == "8k": entries = list() for x in range(self.max_x+1): @@ -302,7 +345,7 @@ class iceconfig: def tile_db(self, x, y): # Only these devices have IO on the left and right sides. - if self.device in ["384", "1k", "8k"]: + if self.device in ["384", "1k", "lm4k", "8k"]: if x == 0: return iotile_l_db if x == self.max_x: return iotile_r_db # The 5k needs an IO db including the extra bits @@ -326,7 +369,7 @@ class iceconfig: if (x, y) in self.dsp_tiles[2]: return dsp2_5k_db if (x, y) in self.dsp_tiles[3]: return dsp3_5k_db - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": if (x, y) in self.logic_tiles: return logictile_8k_db if (x, y) in self.ramb_tiles: return rambtile_8k_db if (x, y) in self.ramt_tiles: return ramttile_8k_db @@ -449,7 +492,7 @@ class iceconfig: return (nx, ny, "ram/RDATA_%d" % func) elif self.device == "5k": return (nx, ny, "ram/RDATA_%d" % (15-func)) - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": return (nx, ny, "ram/RDATA_%d" % (15-func)) else: assert False @@ -458,7 +501,7 @@ class iceconfig: return (nx, ny, "ram/RDATA_%d" % (8+func)) elif self.device == "5k": return (nx, ny, "ram/RDATA_%d" % (7-func)) - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": return (nx, ny, "ram/RDATA_%d" % (7-func)) else: assert False @@ -500,7 +543,7 @@ class iceconfig: funcnets |= self.follow_funcnet(x, y, int(match.group(1)) % 8) elif self.device == "5k": funcnets |= self.follow_funcnet(x, y, 7 - int(match.group(1)) % 8) - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": funcnets |= self.follow_funcnet(x, y, 7 - int(match.group(1)) % 8) else: assert False @@ -714,7 +757,7 @@ class iceconfig: add_seed_segments(idx, tile, logictile_db) elif self.device == "5k": add_seed_segments(idx, tile, logictile_5k_db) - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": add_seed_segments(idx, tile, logictile_8k_db) elif self.device == "384": add_seed_segments(idx, tile, logictile_384_db) @@ -726,7 +769,7 @@ class iceconfig: add_seed_segments(idx, tile, rambtile_db) elif self.device == "5k": add_seed_segments(idx, tile, rambtile_8k_db) - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": add_seed_segments(idx, tile, rambtile_8k_db) else: assert False @@ -736,7 +779,7 @@ class iceconfig: add_seed_segments(idx, tile, ramttile_db) elif self.device == "5k": add_seed_segments(idx, tile, ramttile_8k_db) - elif self.device == "8k": + elif self.device == "8k" or self.device == "lm4k": add_seed_segments(idx, tile, ramttile_8k_db) else: assert False @@ -881,7 +924,7 @@ class iceconfig: self.extra_bits.add((int(line[1]), int(line[2]), int(line[3]))) continue if line[0] == ".device": - assert line[1] in ["1k", "5k", "8k", "384"] + assert line[1] in ["1k", "lm4k", "5k", "8k", "384"] self.device = line[1] continue if line[0] == ".warmboot": @@ -1303,7 +1346,8 @@ def run_checks_neigh(): print("Running consistency checks on neighbour finder..") ic = iceconfig() # ic.setup_empty_1k() - ic.setup_empty_5k() + ic.setup_empty_lm4k() + # ic.setup_empty_5k() # ic.setup_empty_8k() # ic.setup_empty_384() @@ -1353,7 +1397,8 @@ def parse_db(text, device="1k"): continue line = line_1k elif line_8k != line: - if device != "8k" and device != "5k": # global network is the same for 8k and 5k + # global network is the same for 8k, 5k, and lm4k + if device != "8k" and device != "5k" and device != "lm4k": continue line = line_8k elif line_384 != line: @@ -1378,6 +1423,16 @@ extra_bits_db = { (0, 330, 143): ("padin_glb_netwk", "6"), # (0 0) (330 143) (330 143) routing T_0_0.padin_6 <X> T_0_0.glb_netwk_6 (0, 331, 143): ("padin_glb_netwk", "7"), }, + "lm4k": { + (0, 654, 174): ("padin_glb_netwk", "0"), + (0, 655, 174): ("padin_glb_netwk", "1"), + (1, 654, 175): ("padin_glb_netwk", "2"), + (1, 655, 175): ("padin_glb_netwk", "3"), + (1, 654, 174): ("padin_glb_netwk", "4"), # HSOSC + (1, 655, 174): ("padin_glb_netwk", "5"), # LSOSC + (0, 654, 175): ("padin_glb_netwk", "6"), + (0, 655, 175): ("padin_glb_netwk", "7"), + }, "5k": { (0, 690, 334): ("padin_glb_netwk", "0"), # check (0, 691, 334): ("padin_glb_netwk", "1"), # good @@ -1431,6 +1486,16 @@ gbufin_db = { (13, 31, 1), #checked (19, 31, 2), #checked ], + "lm4k": [ + ( 6, 0, 6), + (12, 0, 5), + (13, 0, 0), + (19, 0, 7), + ( 6, 21, 3), + (12, 21, 4), + (13, 21, 1), + (19, 21, 2), + ], "8k": [ (33, 16, 7), ( 0, 16, 6), @@ -1468,6 +1533,10 @@ iolatch_db = { ( 5, 0), ( 8, 17), ], + "lm4k": [ + (14, 0), + (14, 21) + ], "5k": [ (14, 0), (14, 31), @@ -1500,6 +1569,12 @@ warmbootinfo_db = { "S0": ( 23, 0, "fabout" ), "S1": ( 24, 0, "fabout" ), }, + "lm4k": { + # These are the right locations but may be the wrong order. + "BOOT": ( 23, 0, "fabout" ), + "S0": ( 24, 0, "fabout" ), + "S1": ( 25, 1, "fabout" ), + }, "8k": { "BOOT": ( 31, 0, "fabout" ), "S0": ( 33, 1, "fabout" ), @@ -1619,6 +1694,99 @@ pllinfo_db = { "SDI": ( 4, 0, "fabout"), "SCLK": ( 3, 0, "fabout"), }, + "lm4k": { + "LOC" : (12, 0), + + # 3'b000 = "DISABLED" + # 3'b010 = "SB_PLL40_PAD" + # 3'b100 = "SB_PLL40_2_PAD" + # 3'b110 = "SB_PLL40_2F_PAD" + # 3'b011 = "SB_PLL40_CORE" + # 3'b111 = "SB_PLL40_2F_CORE" + "PLLTYPE_0": (12, 0, "PLLCONFIG_5"), + "PLLTYPE_1": (14, 0, "PLLCONFIG_1"), + "PLLTYPE_2": (14, 0, "PLLCONFIG_3"), + + # 3'b000 = "DELAY" + # 3'b001 = "SIMPLE" + # 3'b010 = "PHASE_AND_DELAY" + # 3'b110 = "EXTERNAL" + "FEEDBACK_PATH_0": (14, 0, "PLLCONFIG_5"), + "FEEDBACK_PATH_1": (11, 0, "PLLCONFIG_9"), + "FEEDBACK_PATH_2": (12, 0, "PLLCONFIG_1"), + + # 1'b0 = "FIXED" + # 1'b1 = "DYNAMIC" (also set FDA_FEEDBACK=4'b1111) + "DELAY_ADJMODE_FB": (13, 0, "PLLCONFIG_4"), + + # 1'b0 = "FIXED" + # 1'b1 = "DYNAMIC" (also set FDA_RELATIVE=4'b1111) + "DELAY_ADJMODE_REL": (13, 0, "PLLCONFIG_9"), + + # 2'b00 = "GENCLK" + # 2'b01 = "GENCLK_HALF" + # 2'b10 = "SHIFTREG_90deg" + # 2'b11 = "SHIFTREG_0deg" + "PLLOUT_SELECT_A_0": (12, 0, "PLLCONFIG_6"), + "PLLOUT_SELECT_A_1": (12, 0, "PLLCONFIG_7"), + # 2'b00 = "GENCLK" + # 2'b01 = "GENCLK_HALF" + # 2'b10 = "SHIFTREG_90deg" + # 2'b11 = "SHIFTREG_0deg" + "PLLOUT_SELECT_B_0": (12, 0, "PLLCONFIG_2"), + "PLLOUT_SELECT_B_1": (12, 0, "PLLCONFIG_3"), + + # Numeric Parameters + "SHIFTREG_DIV_MODE": (12, 0, "PLLCONFIG_4"), + "FDA_FEEDBACK_0": (12, 0, "PLLCONFIG_9"), + "FDA_FEEDBACK_1": (13, 0, "PLLCONFIG_1"), + "FDA_FEEDBACK_2": (13, 0, "PLLCONFIG_2"), + "FDA_FEEDBACK_3": (13, 0, "PLLCONFIG_3"), + "FDA_RELATIVE_0": (13, 0, "PLLCONFIG_5"), + "FDA_RELATIVE_1": (13, 0, "PLLCONFIG_6"), + "FDA_RELATIVE_2": (13, 0, "PLLCONFIG_7"), + "FDA_RELATIVE_3": (13, 0, "PLLCONFIG_8"), + "DIVR_0": (10, 0, "PLLCONFIG_1"), + "DIVR_1": (10, 0, "PLLCONFIG_2"), + "DIVR_2": (10, 0, "PLLCONFIG_3"), + "DIVR_3": (10, 0, "PLLCONFIG_4"), + "DIVF_0": (10, 0, "PLLCONFIG_5"), + "DIVF_1": (10, 0, "PLLCONFIG_6"), + "DIVF_2": (10, 0, "PLLCONFIG_7"), + "DIVF_3": (10, 0, "PLLCONFIG_8"), + "DIVF_4": (10, 0, "PLLCONFIG_9"), + "DIVF_5": (11, 0, "PLLCONFIG_1"), + "DIVF_6": (11, 0, "PLLCONFIG_2"), + "DIVQ_0": (11, 0, "PLLCONFIG_3"), + "DIVQ_1": (11, 0, "PLLCONFIG_4"), + "DIVQ_2": (11, 0, "PLLCONFIG_5"), + "FILTER_RANGE_0": (11, 0, "PLLCONFIG_6"), + "FILTER_RANGE_1": (11, 0, "PLLCONFIG_7"), + "FILTER_RANGE_2": (11, 0, "PLLCONFIG_8"), + "TEST_MODE": (12, 0, "PLLCONFIG_8"), + + # PLL Ports + # TODO(awygle) confirm these + "PLLOUT_A": ( 12, 0, 1), + "PLLOUT_B": ( 13, 0, 0), + "REFERENCECLK": ( 10, 0, "fabout"), + "EXTFEEDBACK": ( 11, 0, "fabout"), + "DYNAMICDELAY_0": ( 1, 0, "fabout"), + "DYNAMICDELAY_1": ( 2, 0, "fabout"), + "DYNAMICDELAY_2": ( 3, 0, "fabout"), + "DYNAMICDELAY_3": ( 4, 0, "fabout"), + "DYNAMICDELAY_4": ( 5, 0, "fabout"), + "DYNAMICDELAY_5": ( 7, 0, "fabout"), + "DYNAMICDELAY_6": ( 8, 0, "fabout"), + "DYNAMICDELAY_7": ( 9, 0, "fabout"), + "LOCK": ( 1, 1, "neigh_op_bnl_1"), #check? + "BYPASS": ( 15, 0, "fabout"), + "RESETB": ( 16, 0, "fabout"), + "LATCHINPUTVALUE": ( 14, 0, "fabout"), + "SDO": ( 24, 1, "neigh_op_bnr_3"), #check? + "SDI": ( 18, 0, "fabout"), + "SCLK": ( 17, 0, "fabout"), + }, "5k": { "LOC" : (12, 31), @@ -1910,6 +2078,18 @@ padin_pio_db = { ( 6, 0, 1), # glb_netwk_6 ( 6, 17, 1), # glb_netwk_7 ], + "lm4k": [ + (19, 0, 0), #0 fixed + ( 6, 0, 1), #1 fixed + (13, 21, 0), #2 fixed + (13, 0, 0), #3 fixed + + (19, 21, 0), #These two are questionable, but keep the order correct + ( 6, 21, 0), #They may need to be fixed if other package options are added. + + (12, 0, 1), #6 fixed + (12, 21, 1), #7 fixed + ], "5k": [ (19, 0, 1), #0 fixed ( 6, 0, 1), #1 fixed @@ -2308,6 +2488,45 @@ ieren_db = { ( 7, 6, 0, 7, 6, 1), ( 7, 6, 1, 7, 6, 0), ], + "lm4k": [ + ( 6, 0, 0, 6, 0, 1), + ( 6, 0, 1, 6, 0, 0), + ( 7, 0, 0, 7, 0, 1), + ( 7, 0, 1, 7, 0, 0), + ( 8, 0, 0, 8, 0, 1), + ( 8, 0, 1, 8, 0, 0), + (10, 0, 0, 10, 0, 1), + (12, 0, 0, 12, 0, 1), + (12, 0, 1, 12, 0, 0), + (13, 0, 0, 13, 0, 1), + (13, 0, 1, 13, 0, 0), + (19, 0, 0, 19, 0, 1), + (19, 0, 1, 19, 0, 0), + (21, 0, 0, 21, 0, 1), + (21, 0, 1, 21, 0, 0), + (22, 0, 0, 22, 0, 1), + (23, 0, 0, 23, 0, 1), + (23, 0, 1, 23, 0, 0), + (24, 0, 0, 24, 0, 1), + (24, 0, 1, 24, 0, 0), + ( 4, 21, 0, 4, 21, 1), + ( 4, 21, 1, 4, 21, 0), + ( 5, 21, 1, 5, 21, 0), + ( 6, 21, 0, 6, 21, 1), + ( 7, 21, 1, 7, 21, 0), + ( 9, 21, 0, 9, 21, 1), + (12, 21, 1, 12, 21, 0), + (13, 21, 0, 13, 21, 1), + (15, 21, 0, 15, 21, 1), + (17, 21, 1, 17, 21, 0), + (18, 21, 0, 18, 21, 1), + (19, 21, 0, 19, 21, 1), + (19, 21, 1, 19, 21, 0), + (21, 21, 1, 21, 21, 0), + (22, 21, 1, 22, 21, 0), + (23, 21, 0, 23, 21, 1), + (23, 21, 1, 23, 21, 0), + ], "5k": [ ( 8, 0, 0, 8, 0, 1), ( 9, 0, 1, 9, 0, 0), @@ -3459,6 +3678,101 @@ pinloc_db = { ( "L8", 29, 0, 0), ("L10", 31, 0, 0), ], + "8k-bg121:4k": [ + ( "A1", 2, 33, 0), + ( "A2", 3, 33, 1), + ( "A3", 3, 33, 0), + ( "A4", 9, 33, 0), + ( "A5", 11, 33, 0), + ( "A6", 11, 33, 1), + ( "A7", 19, 33, 1), + ( "A8", 20, 33, 1), + ( "A9", 26, 33, 1), + ("A10", 30, 33, 1), + ("A11", 31, 33, 1), + ( "B1", 0, 30, 1), + ( "B2", 0, 30, 0), + ( "B3", 4, 33, 0), + ( "B4", 5, 33, 0), + ( "B5", 10, 33, 1), + ( "B6", 16, 33, 1), + ( "B7", 17, 33, 0), + ( "B8", 27, 33, 0), + ( "B9", 28, 33, 1), + ("B11", 33, 28, 0), + ( "C1", 0, 25, 0), + ( "C2", 0, 25, 1), + ( "C3", 0, 27, 0), + ( "C4", 0, 27, 1), + ( "C7", 20, 33, 0), + ( "C8", 26, 33, 0), + ( "C9", 29, 33, 1), + ("C11", 33, 27, 1), + ( "D1", 0, 22, 0), + ( "D2", 0, 21, 1), + ( "D3", 0, 21, 0), + ( "D5", 8, 33, 1), + ( "D7", 25, 33, 0), + ( "D9", 33, 21, 0), + ("D10", 33, 24, 1), + ("D11", 33, 23, 1), + ( "E1", 0, 22, 1), + ( "E2", 0, 20, 1), + ( "E3", 0, 20, 0), + ( "E8", 33, 20, 1), + ( "E9", 33, 19, 1), + ("E10", 33, 17, 0), + ("E11", 33, 21, 1), + ( "F1", 0, 18, 1), + ( "F2", 0, 18, 0), + ( "F3", 0, 17, 0), + ( "F4", 0, 17, 1), + ( "F9", 33, 15, 0), + ("F10", 33, 14, 1), + ("F11", 33, 16, 1), + ( "G1", 0, 16, 1), + ( "G2", 0, 16, 0), + ( "G3", 0, 12, 1), + ( "G8", 33, 5, 1), + ( "G9", 33, 10, 1), + ("G10", 33, 6, 1), + ("G11", 33, 11, 0), + ( "H1", 0, 11, 1), + ( "H2", 0, 11, 0), + ( "H3", 0, 12, 0), + ( "H7", 20, 0, 1), + ( "H9", 29, 0, 1), + ("H10", 33, 4, 1), + ("H11", 33, 6, 0), + ( "J1", 0, 6, 1), + ( "J2", 0, 4, 0), + ( "J3", 4, 0, 1), + ( "J4", 8, 0, 0), + ( "J5", 15, 0, 0), + ( "J7", 20, 0, 0), + ( "J8", 22, 0, 1), + ( "J9", 30, 0, 1), + ("J10", 33, 5, 0), + ("J11", 33, 3, 1), + ( "K1", 0, 6, 0), + ( "K2", 0, 4, 1), + ( "K3", 7, 0, 1), + ( "K4", 12, 0, 1), + ( "K5", 15, 0, 1), + ( "K6", 17, 0, 0), + ( "K7", 21, 0, 1), + ( "K9", 30, 0, 0), + ("K10", 31, 0, 1), + ("K11", 33, 4, 0), + ( "L1", 4, 0, 0), + ( "L2", 6, 0, 1), + ( "L3", 11, 0, 1), + ( "L4", 12, 0, 0), + ( "L5", 16, 0, 1), + ( "L7", 24, 0, 0), + ( "L8", 29, 0, 0), + ("L10", 31, 0, 0), + ], "8k-cm225:4k": [ ( "A1", 1, 33, 1), ( "A2", 3, 33, 1), @@ -3788,6 +4102,101 @@ pinloc_db = { ( "L8", 29, 0, 0), ("L10", 31, 0, 0), ], + "8k-bg121": [ + ( "A1", 2, 33, 0), + ( "A2", 3, 33, 1), + ( "A3", 3, 33, 0), + ( "A4", 9, 33, 0), + ( "A5", 11, 33, 0), + ( "A6", 11, 33, 1), + ( "A7", 19, 33, 1), + ( "A8", 20, 33, 1), + ( "A9", 26, 33, 1), + ("A10", 30, 33, 1), + ("A11", 31, 33, 1), + ( "B1", 0, 30, 1), + ( "B2", 0, 30, 0), + ( "B3", 4, 33, 0), + ( "B4", 5, 33, 0), + ( "B5", 10, 33, 1), + ( "B6", 16, 33, 1), + ( "B7", 17, 33, 0), + ( "B8", 27, 33, 0), + ( "B9", 28, 33, 1), + ("B11", 33, 28, 0), + ( "C1", 0, 25, 0), + ( "C2", 0, 25, 1), + ( "C3", 0, 27, 0), + ( "C4", 0, 27, 1), + ( "C7", 20, 33, 0), + ( "C8", 26, 33, 0), + ( "C9", 29, 33, 1), + ("C11", 33, 27, 1), + ( "D1", 0, 22, 0), + ( "D2", 0, 21, 1), + ( "D3", 0, 21, 0), + ( "D5", 8, 33, 1), + ( "D7", 25, 33, 0), + ( "D9", 33, 21, 0), + ("D10", 33, 24, 1), + ("D11", 33, 23, 1), + ( "E1", 0, 22, 1), + ( "E2", 0, 20, 1), + ( "E3", 0, 20, 0), + ( "E8", 33, 20, 1), + ( "E9", 33, 19, 1), + ("E10", 33, 17, 0), + ("E11", 33, 21, 1), + ( "F1", 0, 18, 1), + ( "F2", 0, 18, 0), + ( "F3", 0, 17, 0), + ( "F4", 0, 17, 1), + ( "F9", 33, 15, 0), + ("F10", 33, 14, 1), + ("F11", 33, 16, 1), + ( "G1", 0, 16, 1), + ( "G2", 0, 16, 0), + ( "G3", 0, 12, 1), + ( "G8", 33, 5, 1), + ( "G9", 33, 10, 1), + ("G10", 33, 6, 1), + ("G11", 33, 11, 0), + ( "H1", 0, 11, 1), + ( "H2", 0, 11, 0), + ( "H3", 0, 12, 0), + ( "H7", 20, 0, 1), + ( "H9", 29, 0, 1), + ("H10", 33, 4, 1), + ("H11", 33, 6, 0), + ( "J1", 0, 6, 1), + ( "J2", 0, 4, 0), + ( "J3", 4, 0, 1), + ( "J4", 8, 0, 0), + ( "J5", 15, 0, 0), + ( "J7", 20, 0, 0), + ( "J8", 22, 0, 1), + ( "J9", 30, 0, 1), + ("J10", 33, 5, 0), + ("J11", 33, 3, 1), + ( "K1", 0, 6, 0), + ( "K2", 0, 4, 1), + ( "K3", 7, 0, 1), + ( "K4", 12, 0, 1), + ( "K5", 15, 0, 1), + ( "K6", 17, 0, 0), + ( "K7", 21, 0, 1), + ( "K9", 30, 0, 0), + ("K10", 31, 0, 1), + ("K11", 33, 4, 0), + ( "L1", 4, 0, 0), + ( "L2", 6, 0, 1), + ( "L3", 11, 0, 1), + ( "L4", 12, 0, 0), + ( "L5", 16, 0, 1), + ( "L7", 24, 0, 0), + ( "L8", 29, 0, 0), + ("L10", 31, 0, 0), + ], "8k-cm225": [ ( "A1", 1, 33, 1), ( "A2", 3, 33, 1), @@ -4425,6 +4834,45 @@ pinloc_db = { ( "F2", 19, 0, 1), ( "F4", 12, 0, 1), ( "F5", 6, 0, 1), + ], + "lm4k-cm49": [ + ( "A1", 5, 21, 1), + ( "A2", 6, 21, 0), + ( "A3", 12, 21, 1), + ( "A4", 13, 21, 0), + ( "A5", 17, 21, 1), + ( "A6", 19, 21, 1), + ( "A7", 22, 21, 1), + ( "B1", 4, 21, 1), + ( "B2", 7, 21, 1), + ( "B4", 15, 21, 0), + ( "B6", 18, 21, 0), + ( "B7", 23, 21, 1), + ( "C1", 4, 21, 0), + ( "C3", 9, 21, 0), + ( "C4", 19, 21, 0), + ( "C6", 21, 21, 1), + ( "C7", 23, 21, 0), + ( "D1", 7, 0, 1), + ( "D2", 6, 0, 1), + ( "D3", 10, 0, 0), + ( "D6", 19, 0, 1), + ( "D7", 21, 0, 0), + ( "E1", 6, 0, 0), + ( "E2", 12, 0, 1), + ( "E3", 7, 0, 0), + ( "E4", 12, 0, 0), + ( "E5", 19, 0, 0), + ( "E6", 24, 0, 1), + ( "E7", 22, 0, 0), + ( "F2", 8, 0, 1), + ( "F3", 8, 0, 0), + ( "F4", 13, 0, 1), + ( "F5", 23, 0, 0), + ( "F6", 24, 0, 0), + ( "F7", 21, 0, 1), + ( "G3", 13, 0, 0), + ( "G6", 23, 0, 1), ] } @@ -4769,6 +5217,10 @@ extra_cells_db = { "RGB2_CURRENT_5": (0, 30, "CBIT_7"), "CURRENT_MODE": (0, 28, "CBIT_4"), + "RGB0": (4, 31, 0), + "RGB1": (5, 31, 0), + "RGB2": (6, 31, 0), + }, ("I2C", (0, 31, 0)): { "I2CIRQ": (0, 30, "slf_op_7"), @@ -4984,7 +5436,16 @@ extra_cells_db = { "PWMOUT1": (0, 28, "slf_op_5"), "PWMOUT2": (0, 28, "slf_op_6"), }, - + ("IO_I3C", (25, 27, 0)): { + "PU_ENB": (25, 27, "lutff_6/in_0"), + "WEAK_PU_ENB": (25, 27, "lutff_4/in_0"), + "PACKAGE_PIN": (19, 31, 0) + }, + ("IO_I3C", (25, 27, 1)): { + "PU_ENB": (25, 27, "lutff_7/in_0"), + "WEAK_PU_ENB": (25, 27, "lutff_5/in_0"), + "PACKAGE_PIN": (19, 31, 1) + } } } diff --git a/icebox/icebox_chipdb.py b/icebox/icebox_chipdb.py index fc25403..6497ae2 100755 --- a/icebox/icebox_chipdb.py +++ b/icebox/icebox_chipdb.py @@ -19,6 +19,7 @@ import icebox import getopt, sys, re mode_384 = False +mode_lm4k = False mode_5k = False mode_8k = False @@ -34,11 +35,14 @@ Usage: icebox_chipdb [options] [bitmap.asc] -8 create chipdb for 8k device + + -4 + create chipdb for lm4k device """) sys.exit(0) try: - opts, args = getopt.getopt(sys.argv[1:], "358") + opts, args = getopt.getopt(sys.argv[1:], "3584") except: usage() @@ -49,6 +53,8 @@ for o, a in opts: mode_5k = True elif o == "-3": mode_384 = True + elif o == "-4": + mode_lm4k = True else: usage() @@ -59,6 +65,8 @@ elif mode_5k: ic.setup_empty_5k() elif mode_384: ic.setup_empty_384() +elif mode_lm4k: + ic.setup_empty_lm4k() else: ic.setup_empty_1k() @@ -319,7 +327,7 @@ for dsploc in ic.dsp_tiles[0]: print() if ic.device in icebox.extra_cells_db: - for cell in icebox.extra_cells_db[ic.device]: + for cell in sorted(icebox.extra_cells_db[ic.device]): name, loc = cell x, y, z = loc print(".extra_cell %d %d %d %s" % (x, y, z, name)) @@ -329,7 +337,7 @@ if ic.device in icebox.extra_cells_db: print() if ic.device in icebox.spram_db: - for cell in icebox.spram_db[ic.device]: + for cell in sorted(icebox.spram_db[ic.device]): loc = cell x, y, z = loc print(".extra_cell %d %d %d SPRAM" % (x, y, z)) diff --git a/icebox/icebox_vlog.py b/icebox/icebox_vlog.py index 873e4b2..5736011 100755 --- a/icebox/icebox_vlog.py +++ b/icebox/icebox_vlog.py @@ -25,6 +25,7 @@ check_ieren = False check_driver = False lookup_symbols = False do_collect = False +package = None pcf_data = dict() portnames = set() unmatched_ports = set() @@ -56,6 +57,10 @@ Usage: icebox_vlog [options] [bitmap.asc] like -p, enable some hacks for pcf files created by the iCEcube2 placer. + -d <package> + use the given package to obtain chip pin numbers, + rather than the default for a device + -c collect multi-bit ports @@ -68,7 +73,7 @@ Usage: icebox_vlog [options] [bitmap.asc] sys.exit(0) try: - opts, args = getopt.getopt(sys.argv[1:], "sSlLap:P:n:cRD") + opts, args = getopt.getopt(sys.argv[1:], "sSlLap:P:n:d:cRD") except: usage() @@ -111,6 +116,8 @@ for o, a in opts: else: pinloc = (line[2],) pcf_data[pinloc] = p + elif o == "-d": + package = a elif o == "-c": do_collect = True elif o == "-R": @@ -285,7 +292,7 @@ for segs in sorted(ic.group_segments(extra_connections=extra_connections, extra_ idx = (s[0], s[1], int(match.group(1))) p = "io_%d_%d_%d" % idx if lookup_pins or pcf_data: - for entry in ic.pinloc_db(): + for entry in ic.pinloc_db(package): if idx[0] == entry[1] and idx[1] == entry[2] and idx[2] == entry[3]: if (entry[0],) in pcf_data: p = pcf_data[(entry[0],)] diff --git a/icebram/icebram.cc b/icebram/icebram.cc index 245a0ab..a796f92 100644 --- a/icebram/icebram.cc +++ b/icebram/icebram.cc @@ -28,6 +28,10 @@ #include <fstream> #include <iostream> +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif + using std::map; using std::pair; using std::vector; @@ -109,6 +113,18 @@ void help(const char *cmd) int main(int argc, char **argv) { +#ifdef __EMSCRIPTEN__ + EM_ASM( + if (ENVIRONMENT_IS_NODE) + { + FS.mkdir('/hostcwd'); + FS.mount(NODEFS, { root: '.' }, '/hostcwd'); + FS.mkdir('/hostfs'); + FS.mount(NODEFS, { root: '/' }, '/hostfs'); + } + ); +#endif + bool verbose = false; bool generate = false; diff --git a/icefuzz/Makefile b/icefuzz/Makefile index a2a40b4..ea9f3e0 100644 --- a/icefuzz/Makefile +++ b/icefuzz/Makefile @@ -18,6 +18,11 @@ ifeq ($(DEVICECLASS), 5k) RAM_SUFFIX := _8k endif +ifeq ($(DEVICECLASS), 4k) + DEVICE := lm4k-cm49 + RAM_SUFFIX := _8k +endif + ifeq ($(DEVICECLASS), 8k) DEVICE := hx8k-ct256 RAM_SUFFIX = _8k diff --git a/icefuzz/fuzzconfig.py b/icefuzz/fuzzconfig.py index a50cce5..f03c815 100644 --- a/icefuzz/fuzzconfig.py +++ b/icefuzz/fuzzconfig.py @@ -60,6 +60,25 @@ elif device_class == "1k": """.split() gpins = "20 21 49 50 93 94 128 129".split() + +elif device_class == "4k": + num_ramb40 = 20 + num_iobanks = 2 + num_dsp = 0 + + # TODO(awygle) add F5 G6 F6 E6 which are constrained to (config) SPI. + pins = """ + A1 A2 A3 A4 A5 A6 A7 + B1 B2 B4 B6 B7 + C1 C3 C4 C6 C7 + D1 D2 D3 D6 D7 + E1 E2 E3 E4 E5 E7 + F2 F3 F4 F7 + G3 + """.split() + + gpins = "A3 A4 D2 E2 E5 G3".split() + elif device_class == "5k": num_ramb40 = 30 num_iobanks = 2 diff --git a/icefuzz/icecube.sh b/icefuzz/icecube.sh index 5a1a7f2..832c15e 100644 --- a/icefuzz/icecube.sh +++ b/icefuzz/icecube.sh @@ -56,6 +56,11 @@ if [ "$1" == "-up5k" ]; then shift fi +if [ "$1" == "-lm4k" ]; then + ICEDEV=lm4k-cm49 + shift +fi + set -ex set -- ${1%.v} icecubedir="${ICECUBEDIR:-/opt/lscc/iCEcube2.2015.08}" @@ -187,6 +192,42 @@ case "${ICEDEV:-hx1k-tq144}" in iCEPACKAGE="UWG30" iCE40DEV="iCE40UP5K" ;; + lm4k-cm49) + iCEPACKAGE="CM49" + iCE40DEV="iCE40LM4K" + ;; + lm4k-cm36) + iCEPACKAGE="CM36" + iCE40DEV="iCE40LM4K" + ;; + lm4k-swg25tr) + iCEPACKAGE="SWG25TR" + iCE40DEV="iCE40LM4K" + ;; + lm2k-cm49) + iCEPACKAGE="CM49" + iCE40DEV="iCE40LM2K" + ;; + lm2k-cm36) + iCEPACKAGE="CM36" + iCE40DEV="iCE40LM2K" + ;; + lm2k-swg25tr) + iCEPACKAGE="SWG25TR" + iCE40DEV="iCE40LM2K" + ;; + lm1k-cm49) + iCEPACKAGE="CM49" + iCE40DEV="iCE40LM1K" + ;; + lm1k-cm36) + iCEPACKAGE="CM36" + iCE40DEV="iCE40LM1K" + ;; + lm1k-swg25tr) + iCEPACKAGE="SWG25TR" + iCE40DEV="iCE40LM1K" + ;; *) echo "ERROR: Invalid \$ICEDEV device config '$ICEDEV'." exit 1 @@ -238,6 +279,21 @@ case "$iCE40DEV" in libfile="ice40UP5K.lib" devfile="ICE40T05.dev" ;; + iCE40LM1K) + icetech="SBTiCE40LM" + libfile="ice40LM4K.lib" + devfile="ICE40R04.dev" + ;; + iCE40LM2K) + icetech="SBTiCE40LM" + libfile="ice40LM4K.lib" + devfile="ICE40R04.dev" + ;; + iCE40LM4K) + icetech="SBTiCE40LM" + libfile="ice40LM4K.lib" + devfile="ICE40R04.dev" + ;; esac ( diff --git a/icefuzz/tests/colbuf_io_lm4k.sh b/icefuzz/tests/colbuf_io_lm4k.sh new file mode 100644 index 0000000..80d2f64 --- /dev/null +++ b/icefuzz/tests/colbuf_io_lm4k.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +set -ex + +mkdir -p colbuf_io_lm4k.work +cd colbuf_io_lm4k.work + +glb_pins="A3 A4 D2 E2 E5 G3" + +pins=" + A1 A2 A3 A4 A5 A6 A7 + B1 B2 B4 B6 B7 + C1 C3 C4 C6 C7 + D1 D2 D3 D6 D7 + E1 E2 E3 E4 E5 E7 + F2 F3 F4 F7 + G3 +" +pins="$( echo $pins )" + +for pin in $pins; do + pf="colbuf_io_lm4k_$pin" + gpin=$( echo $glb_pins | tr ' ' '\n' | grep -v $pin | sort -R | head -n1; ) + cat > ${pf}.v <<- EOT + module top (input clk, data, output pin); + SB_IO #( + .PIN_TYPE(6'b 0101_00) + ) pin_obuf ( + .PACKAGE_PIN(pin), + .OUTPUT_CLK(clk), + .D_OUT_0(data) + ); + endmodule + EOT + echo "set_io pin $pin" > ${pf}.pcf + echo "set_io clk $gpin" >> ${pf}.pcf + ICEDEV=lm4k-cm49 bash ../../icecube.sh ${pf}.v > ${pf}.log 2>&1 + ../../../icebox/icebox_explain.py ${pf}.asc > ${pf}.exp + rm -rf ${pf}.tmp +done + diff --git a/icefuzz/tests/colbuf_logic_lm4k.sh b/icefuzz/tests/colbuf_logic_lm4k.sh new file mode 100644 index 0000000..d1dc681 --- /dev/null +++ b/icefuzz/tests/colbuf_logic_lm4k.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +set -ex + +mkdir -p colbuf_logic_lm4k.work +cd colbuf_logic_lm4k.work + +glb_pins="A3 A4 D2 E2 E5 G3" + +for y in {1..32}; do +for y in {1..20}; do + pf="colbuf_logic_lm4k_${x}_${y}" + gpin=$( echo $glb_pins | tr ' ' '\n' | sort -R | head -n1; ) + cat > ${pf}.v <<- EOT + module top (input c, d, output q); + SB_DFF dff ( + .C(c), + .D(d), + .Q(q) + ); + endmodule + EOT + echo "set_location dff $x $y 0" > ${pf}.pcf + echo "set_io c $gpin" >> ${pf}.pcf + ICEDEV=lm4k-cm49 bash ../../icecube.sh ${pf}.v > ${pf}.log 2>&1 + ../../../icebox/icebox_explain.py ${pf}.asc > ${pf}.exp + rm -rf ${pf}.tmp +done; done + diff --git a/icefuzz/tests/colbuf_ram_lm4k.sh b/icefuzz/tests/colbuf_ram_lm4k.sh new file mode 100755 index 0000000..86fb08a --- /dev/null +++ b/icefuzz/tests/colbuf_ram_lm4k.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +set -ex + +mkdir -p colbuf_ram_lm4k.work +cd colbuf_ram_lm4k.work + +glb_pins="A3 A4 D2 E2 E5 G3" + +for x in 6 19; do +for y in {1..20}; do + pf="colbuf_ram_lm4k_${x}_${y}" + gpin=$( echo $glb_pins | tr ' ' '\n' | sort -R | head -n1; ) + if [ $((y % 2)) == 1 ]; then + clkport="WCLK" + other_clkport="RCLK" + else + clkport="RCLK" + other_clkport="WCLK" + fi + cat > ${pf}.v <<- EOT + module top (input c, oc, input [1:0] d, output [1:0] q); + wire gc; + SB_GB_IO #( + .PIN_TYPE(6'b 0000_00), + .PULLUP(1'b0), + .NEG_TRIGGER(1'b0), + .IO_STANDARD("SB_LVCMOS") + ) gbuf ( + .PACKAGE_PIN(c), + .GLOBAL_BUFFER_OUTPUT(gc) + ); + SB_RAM40_4K #( + .READ_MODE(3), + .WRITE_MODE(3) + ) ram40 ( + .WADDR(11'b0), + .RADDR(11'b0), + .$clkport(gc), + .$other_clkport(oc), + .RDATA(q), + .WDATA(d), + .WE(1'b1), + .WCLKE(1'b1), + .RE(1'b1), + .RCLKE(1'b1) + ); + endmodule + EOT + echo "set_location ram40 $x $((y - (1 - y%2))) 0" > ${pf}.pcf + echo "set_io oc 1" >> ${pf}.pcf + echo "set_io c $gpin" >> ${pf}.pcf + ICEDEV=lm4k-cm49 bash ../../icecube.sh ${pf}.v > ${pf}.log 2>&1 + ../../../icebox/icebox_explain.py ${pf}.asc > ${pf}.exp + rm -rf ${pf}.tmp +done; done diff --git a/icefuzz/tests/io_latched_lm4k.sh b/icefuzz/tests/io_latched_lm4k.sh new file mode 100644 index 0000000..5e6b63c --- /dev/null +++ b/icefuzz/tests/io_latched_lm4k.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +set -ex + +mkdir -p io_latched_lm4k.work +cd io_latched_lm4k.work + +pins=" + A1 A2 A3 A4 A5 A6 A7 + B1 B2 B4 B6 B7 + C1 C3 C4 C6 C7 + D1 D2 D3 D6 D7 + E1 E2 E3 E4 E5 E7 + F2 F3 F4 F7 + G3 +" +pins="$( echo $pins )" + +for pin in $pins; do + pf="io_latched_$pin" + cp ../io_latched.v ${pf}.v + read pin_latch pin_data < <( echo $pins | tr ' ' '\n' | grep -v $pin | sort -R; ) + { + echo "set_io pin $pin" + echo "set_io latch_in $pin_latch" + echo "set_io data_out $pin_data" + } > ${pf}.pcf + ICEDEV=lm4k-cm49 bash ../../icecube.sh ${pf}.v + ../../../icebox/icebox_vlog.py -SP ${pf}.psb ${pf}.asc > ${pf}.ve +done + diff --git a/icefuzz/tests/ioctrl_lm4k.py b/icefuzz/tests/ioctrl_lm4k.py new file mode 100644 index 0000000..67c0c6d --- /dev/null +++ b/icefuzz/tests/ioctrl_lm4k.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +import fileinput + +for line in fileinput.input(): + line = line.split() + if len(line) == 0: + continue + if line[0] == ".io_tile": + current_tile = (int(line[1]), int(line[2])) + if line[0] == "IoCtrl" and line[1] == "REN_0": + ren = (current_tile[0], current_tile[1], 0) + if line[0] == "IoCtrl" and line[1] == "REN_1": + ren = (current_tile[0], current_tile[1], 1) + if line[0] == "IOB_0": + iob = (current_tile[0], current_tile[1], 0) + if line[0] == "IOB_1": + iob = (current_tile[0], current_tile[1], 1) + +print("(%2d, %2d, %2d, %2d, %2d, %2d)," % (iob[0], iob[1], iob[2], ren[0], ren[1], ren[2])) + diff --git a/icefuzz/tests/ioctrl_lm4k.sh b/icefuzz/tests/ioctrl_lm4k.sh new file mode 100755 index 0000000..9722038 --- /dev/null +++ b/icefuzz/tests/ioctrl_lm4k.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -ex + +mkdir -p ioctrl.work +cd ioctrl.work + +pins=" + A1 A2 A3 A4 A5 A6 A7 + B1 B2 B4 B6 B7 + C1 C3 C4 C6 C7 + D1 D2 D3 D6 D7 + E1 E2 E3 E4 E5 E6 E7 + F2 F3 F4 F5 F6 F7 + G3 G6 +" + +pins="$( echo $pins )" + +for pin in $pins; do + pf="ioctrl_$pin" + echo "module top (output pin); assign pin = 1; endmodule" > ${pf}.v + echo "set_io pin $pin" > ${pf}.pcf + bash ../../icecube.sh -lm4k ${pf}.v > ${pf}.log 2>&1 + ../../../icebox/icebox_explain.py ${pf}.asc > ${pf}.exp +done + +set +x +echo "--snip--" +for pin in $pins; do + python3 ../ioctrl_5k.py ioctrl_${pin}.exp +done | tee ioctrl_db.txt +echo "--snap--" diff --git a/icefuzz/tests/pllauto/pllauto.py b/icefuzz/tests/pllauto/pllauto.py index 647be29..517417d 100755 --- a/icefuzz/tests/pllauto/pllauto.py +++ b/icefuzz/tests/pllauto/pllauto.py @@ -209,7 +209,8 @@ device = "up5k" #TODO: environment variable? #and look for the stuck bit) #TODO: clever code could get rid of this divq_bit0 = { - "up5k" : (11, 31, 3) + "up5k" : (11, 31, 3), + "lm4k" : (11, 0, 3) } #Return a list of PLL config bits in the format (x, y, bit) diff --git a/icemulti/icemulti.cc b/icemulti/icemulti.cc index 65ae6b6..4bc0919 100644 --- a/icemulti/icemulti.cc +++ b/icemulti/icemulti.cc @@ -24,6 +24,10 @@ #include <stdlib.h> #include <string.h> +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif + #define log(...) fprintf(stderr, __VA_ARGS__); #define error(...) do { fprintf(stderr, "%s: ", program_short_name); fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); } while (0) @@ -178,6 +182,18 @@ void usage() int main(int argc, char **argv) { +#ifdef __EMSCRIPTEN__ + EM_ASM( + if (ENVIRONMENT_IS_NODE) + { + FS.mkdir('/hostcwd'); + FS.mount(NODEFS, { root: '.' }, '/hostcwd'); + FS.mkdir('/hostfs'); + FS.mount(NODEFS, { root: '/' }, '/hostfs'); + } + ); +#endif + int c; char *endptr = NULL; bool coldboot = false; diff --git a/icepack/icepack.cc b/icepack/icepack.cc index ac3e8c6..325c853 100644 --- a/icepack/icepack.cc +++ b/icepack/icepack.cc @@ -34,6 +34,10 @@ #include <stdio.h> #include <stdarg.h> +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif + #ifdef _WIN32 #define __PRETTY_FUNCTION__ __FUNCTION__ #endif @@ -414,6 +418,10 @@ void FpgaConfig::read_bits(std::istream &ifs) this->device = "8k"; else if (this->cram_width == 692 && this->cram_height == 336) this->device = "5k"; + else if (this->cram_width == 692 && this->cram_height == 176) + this->device = "u4k"; + else if (this->cram_width == 656 && this->cram_height == 176) + this->device = "lm4k"; else error("Failed to detect chip type.\n"); @@ -681,6 +689,18 @@ void FpgaConfig::read_ascii(std::istream &ifs, bool nosleep) this->bram_width = 160; this->bram_height = 2 * 128; } else + if (this->device == "u4k") { + this->cram_width = 692; + this->cram_height = 176; + this->bram_width = 80; + this->bram_height = 2 * 128; + } else + if (this->device == "lm4k") { + this->cram_width = 656; + this->cram_height = 176; + this->bram_width = 80; + this->bram_height = 2 * 128; + } else error("Unsupported chip type '%s'.\n", this->device.c_str()); this->cram.resize(4); @@ -1035,6 +1055,8 @@ int FpgaConfig::chip_width() const if (this->device == "384") return 6; if (this->device == "1k") return 12; if (this->device == "5k") return 24; + if (this->device == "u4k") return 24; + if (this->device == "lm4k") return 24; if (this->device == "8k") return 32; panic("Unknown chip type '%s'.\n", this->device.c_str()); } @@ -1044,6 +1066,8 @@ int FpgaConfig::chip_height() const if (this->device == "384") return 8; if (this->device == "1k") return 16; if (this->device == "5k") return 30; + if (this->device == "u4k") return 20; + if (this->device == "lm4k") return 20; if (this->device == "8k") return 32; panic("Unknown chip type '%s'.\n", this->device.c_str()); } @@ -1052,6 +1076,8 @@ vector<int> FpgaConfig::chip_cols() const { if (this->device == "384") return vector<int>({18, 54, 54, 54, 54}); if (this->device == "1k") return vector<int>({18, 54, 54, 42, 54, 54, 54}); + if (this->device == "u4k") return vector<int>({54, 54, 54, 54, 54, 54, 42, 54, 54, 54, 54, 54, 54}); + if (this->device == "lm4k") return vector<int>({18, 54, 54, 54, 54, 54, 42, 54, 54, 54, 54, 54, 54}); // Its IPConnect or Mutiplier block, five logic, ram, six logic. if (this->device == "5k") return vector<int>({54, 54, 54, 54, 54, 54, 42, 54, 54, 54, 54, 54, 54}); if (this->device == "8k") return vector<int>({18, 54, 54, 54, 54, 54, 54, 54, 42, 54, 54, 54, 54, 54, 54, 54, 54}); @@ -1063,7 +1089,7 @@ string FpgaConfig::tile_type(int x, int y) const if ((x == 0 || x == this->chip_width()+1) && (y == 0 || y == this->chip_height()+1)) return "corner"; // The sides on the 5k devices are IPConnect or DSP tiles if (this->device == "5k" && (x == 0 || x == this->chip_width()+1)) { - if( (y == 5) || (y == 10) || (y == 15) || (y == 23)) //check ordering here, tile 23-26 might be reversed + if( (y == 5) || (y == 10) || (y == 15) || (y == 23)) return "dsp0"; if( (y == 6) || (y == 11) || (y == 16) || (y == 24)) return "dsp1"; @@ -1073,6 +1099,19 @@ string FpgaConfig::tile_type(int x, int y) const return "dsp3"; return "ipcon"; } + + if (this->device == "u4k" && (x == 0 || x == this->chip_width()+1)) { + if( (y == 5) || (y == 13)) + return "dsp0"; + if( (y == 6) || (y == 14)) + return "dsp1"; + if( (y == 7) || (y == 15)) + return "dsp2"; + if( (y == 8) || (y == 16)) + return "dsp3"; + return "ipcon"; + } + if ((x == 0 || x == this->chip_width()+1) || (y == 0 || y == this->chip_height()+1)) return "io"; if (this->device == "384") return "logic"; @@ -1082,7 +1121,7 @@ string FpgaConfig::tile_type(int x, int y) const return "logic"; } - if (this->device == "5k") { + if (this->device == "5k" || this->device == "u4k" || this->device == "lm4k") { if (x == 6 || x == 19) return y % 2 == 1 ? "ramb" : "ramt"; return "logic"; } @@ -1314,6 +1353,18 @@ void usage() int main(int argc, char **argv) { +#ifdef __EMSCRIPTEN__ + EM_ASM( + if (ENVIRONMENT_IS_NODE) + { + FS.mkdir('/hostcwd'); + FS.mount(NODEFS, { root: '.' }, '/hostcwd'); + FS.mkdir('/hostfs'); + FS.mount(NODEFS, { root: '/' }, '/hostfs'); + } + ); +#endif + vector<string> parameters; bool unpack_mode = false; bool nosleep_mode = false; diff --git a/icepll/icepll.cc b/icepll/icepll.cc index 6b6cedb..82bf3e3 100644 --- a/icepll/icepll.cc +++ b/icepll/icepll.cc @@ -20,6 +20,10 @@ #include <string.h> #include <math.h> +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif + const char *binstr(int v, int n) { static char buffer[16]; @@ -52,6 +56,9 @@ void help(const char *cmd) printf(" -m\n"); printf(" Save PLL configuration as Verilog module (use with -f)\n"); printf("\n"); + printf(" -n <module name>\n"); + printf(" Specify different Verilog module name than the default 'pll'\n"); + printf("\n"); printf(" -q\n"); printf(" Do not print PLL configuration to stdout\n"); printf("\n"); @@ -60,15 +67,28 @@ void help(const char *cmd) int main(int argc, char **argv) { +#ifdef __EMSCRIPTEN__ + EM_ASM( + if (ENVIRONMENT_IS_NODE) + { + FS.mkdir('/hostcwd'); + FS.mount(NODEFS, { root: '.' }, '/hostcwd'); + FS.mkdir('/hostfs'); + FS.mount(NODEFS, { root: '/' }, '/hostfs'); + } + ); +#endif + double f_pllin = 12; double f_pllout = 60; bool simple_feedback = true; char* filename = NULL; + char* module_name = NULL; bool save_as_module = false; bool quiet = false; int opt; - while ((opt = getopt(argc, argv, "i:o:Smf:q")) != -1) + while ((opt = getopt(argc, argv, "i:o:Smf:n:q")) != -1) { switch (opt) { @@ -87,6 +107,9 @@ int main(int argc, char **argv) case 'f': filename = optarg; break; + case 'n': + module_name = optarg; + break; case 'q': quiet = true; break; @@ -238,11 +261,11 @@ int main(int argc, char **argv) f_pllin, f_pllout, best_fout); // generate Verilog module - fprintf(f, "module pll(\n" + fprintf(f, "module %s(\n" "\tinput clock_in,\n" "\toutput clock_out,\n" "\toutput locked\n" - "\t);\n\n" + "\t);\n\n", (module_name ? module_name : "pll") ); // save iCE40 PLL tile configuration diff --git a/iceprog/iceprog.c b/iceprog/iceprog.c index c19de9d..29d4c22 100644 --- a/iceprog/iceprog.c +++ b/iceprog/iceprog.c @@ -42,6 +42,120 @@ static bool verbose = false; static bool ftdic_latency_set = false; static unsigned char ftdi_latency; +/* MPSSE engine command definitions */ +enum mpsse_cmd +{ + /* Mode commands */ + MC_SETB_LOW = 0x80, /* Set Data bits LowByte */ + MC_READB_LOW = 0x81, /* Read Data bits LowByte */ + MC_SETB_HIGH = 0x82, /* Set Data bits HighByte */ + MC_READB_HIGH = 0x83, /* Read data bits HighByte */ + MC_LOOPBACK_EN = 0x84, /* Enable loopback */ + MC_LOOPBACK_DIS = 0x85, /* Disable loopback */ + MC_SET_CLK_DIV = 0x86, /* Set clock divisor */ + MC_FLUSH = 0x87, /* Flush buffer fifos to the PC. */ + MC_WAIT_H = 0x88, /* Wait on GPIOL1 to go high. */ + MC_WAIT_L = 0x89, /* Wait on GPIOL1 to go low. */ + MC_TCK_X5 = 0x8A, /* Disable /5 div, enables 60MHz master clock */ + MC_TCK_D5 = 0x8B, /* Enable /5 div, backward compat to FT2232D */ + MC_EN_3PH_CLK = 0x8C, /* Enable 3 phase clk, DDR I2C */ + MC_DIS_3PH_CLK = 0x8D, /* Disable 3 phase clk */ + MC_CLK_N = 0x8E, /* Clock every bit, used for JTAG */ + MC_CLK_N8 = 0x8F, /* Clock every byte, used for JTAG */ + MC_CLK_TO_H = 0x94, /* Clock until GPIOL1 goes high */ + MC_CLK_TO_L = 0x95, /* Clock until GPIOL1 goes low */ + MC_EN_ADPT_CLK = 0x96, /* Enable adaptive clocking */ + MC_DIS_ADPT_CLK = 0x97, /* Disable adaptive clocking */ + MC_CLK8_TO_H = 0x9C, /* Clock until GPIOL1 goes high, count bytes */ + MC_CLK8_TO_L = 0x9D, /* Clock until GPIOL1 goes low, count bytes */ + MC_TRI = 0x9E, /* Set IO to only drive on 0 and tristate on 1 */ + /* CPU mode commands */ + MC_CPU_RS = 0x90, /* CPUMode read short address */ + MC_CPU_RE = 0x91, /* CPUMode read extended address */ + MC_CPU_WS = 0x92, /* CPUMode write short address */ + MC_CPU_WE = 0x93, /* CPUMode write extended address */ +}; + +/* Transfer Command bits */ + +/* All byte based commands consist of: + * - Command byte + * - Length lsb + * - Length msb + * + * If data out is enabled the data follows after the above command bytes, + * otherwise no additional data is needed. + * - Data * n + * + * All bit based commands consist of: + * - Command byte + * - Length + * + * If data out is enabled a byte containing bitst to transfer follows. + * Otherwise no additional data is needed. Only up to 8 bits can be transferred + * per transaction when in bit mode. + */ + +/* b 0000 0000 + * |||| |||`- Data out negative enable. Update DO on negative clock edge. + * |||| ||`-- Bit count enable. When reset count represents bytes. + * |||| |`--- Data in negative enable. Latch DI on negative clock edge. + * |||| `---- LSB enable. When set clock data out LSB first. + * |||| + * |||`------ Data out enable + * ||`------- Data in enable + * |`-------- TMS mode enable + * `--------- Special command mode enable. See mpsse_cmd enum. + */ + +#define MC_DATA_TMS (0x40) /* When set use TMS mode */ +#define MC_DATA_IN (0x20) /* When set read data (Data IN) */ +#define MC_DATA_OUT (0x10) /* When set write data (Data OUT) */ +#define MC_DATA_LSB (0x08) /* When set input/output data LSB first. */ +#define MC_DATA_ICN (0x04) /* When set receive data on negative clock edge */ +#define MC_DATA_BITS (0x02) /* When set count bits not bytes */ +#define MC_DATA_OCN (0x01) /* When set update data on negative clock edge */ + +/* Flash command definitions */ +/* This command list is based on the Winbond W25Q128JV Datasheet */ +enum flash_cmd { + FC_WE = 0x06, /* Write Enable */ + FC_SRWE = 0x50, /* Volatile SR Write Enable */ + FC_WD = 0x04, /* Write Disable */ + FC_RPD = 0xAB, /* Release Power-Down, returns Device ID */ + FC_MFGID = 0x90, /* Read Manufacturer/Device ID */ + FC_JEDECID = 0x9F, /* Read JEDEC ID */ + FC_UID = 0x4B, /* Read Unique ID */ + FC_RD = 0x03, /* Read Data */ + FC_FR = 0x0B, /* Fast Read */ + FC_PP = 0x02, /* Page Program */ + FC_SE = 0x20, /* Sector Erase 4kb */ + FC_BE32 = 0x52, /* Block Erase 32kb */ + FC_BE64 = 0xD8, /* Block Erase 64kb */ + FC_CE = 0xC7, /* Chip Erase */ + FC_RSR1 = 0x05, /* Read Status Register 1 */ + FC_WSR1 = 0x01, /* Write Status Register 1 */ + FC_RSR2 = 0x35, /* Read Status Register 2 */ + FC_WSR2 = 0x31, /* Write Status Register 2 */ + FC_RSR3 = 0x15, /* Read Status Register 3 */ + FC_WSR3 = 0x11, /* Write Status Register 3 */ + FC_RSFDP = 0x5A, /* Read SFDP Register */ + FC_ESR = 0x44, /* Erase Security Register */ + FC_PSR = 0x42, /* Program Security Register */ + FC_RSR = 0x48, /* Read Security Register */ + FC_GBL = 0x7E, /* Global Block Lock */ + FC_GBU = 0x98, /* Global Block Unlock */ + FC_RBL = 0x3D, /* Read Block Lock */ + FC_IBL = 0x36, /* Individual Block Lock */ + FC_IBU = 0x39, /* Individual Block Unlock */ + FC_EPS = 0x75, /* Erase / Program Suspend */ + FC_EPR = 0x7A, /* Erase / Program Resume */ + FC_PD = 0xB9, /* Power-down */ + FC_QPI = 0x38, /* Enter QPI mode */ + FC_ERESET = 0x66, /* Enable Reset */ + FC_RESET = 0x99, /* Reset Device */ +}; + static void check_rx() { while (1) { @@ -96,7 +210,8 @@ static void send_spi(uint8_t *data, int n) if (n < 1) return; - send_byte(0x11); + /* Output only, update data on negative clock edge. */ + send_byte(MC_DATA_OUT | MC_DATA_OCN); send_byte(n - 1); send_byte((n - 1) >> 8); @@ -112,7 +227,8 @@ static void xfer_spi(uint8_t *data, int n) if (n < 1) return; - send_byte(0x31); + /* Input and output, update data on negative edge read on positive. */ + send_byte(MC_DATA_IN | MC_DATA_OUT | MC_DATA_OCN); send_byte(n - 1); send_byte((n - 1) >> 8); @@ -140,15 +256,15 @@ static void set_gpio(int slavesel_b, int creset_b) gpio |= 0x80; } - send_byte(0x80); - send_byte(gpio); - send_byte(0x93); + send_byte(MC_SETB_LOW); + send_byte(gpio); /* Value */ + send_byte(0x93); /* Direction */ } static int get_cdone() { uint8_t data; - send_byte(0x81); + send_byte(MC_READB_LOW); data = recv_byte(); // ADBUS6 (GPIOL2) return (data & 0x40) != 0; @@ -158,7 +274,7 @@ static void flash_read_id() { // fprintf(stderr, "read flash ID..\n"); - uint8_t data[21] = { 0x9F }; + uint8_t data[21] = { FC_JEDECID }; set_gpio(0, 0); xfer_spi(data, 21); set_gpio(1, 0); @@ -171,7 +287,7 @@ static void flash_read_id() static void flash_power_up() { - uint8_t data[1] = { 0xAB }; + uint8_t data[1] = { FC_RPD }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -179,7 +295,7 @@ static void flash_power_up() static void flash_power_down() { - uint8_t data[1] = { 0xB9 }; + uint8_t data[1] = { FC_PD }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -190,7 +306,7 @@ static void flash_write_enable() if (verbose) fprintf(stderr, "write enable..\n"); - uint8_t data[1] = { 0x06 }; + uint8_t data[1] = { FC_WE }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -200,7 +316,7 @@ static void flash_bulk_erase() { fprintf(stderr, "bulk erase..\n"); - uint8_t data[1] = { 0xc7 }; + uint8_t data[1] = { FC_CE }; set_gpio(0, 0); xfer_spi(data, 1); set_gpio(1, 0); @@ -210,7 +326,7 @@ static void flash_64kB_sector_erase(int addr) { fprintf(stderr, "erase 64kB sector at 0x%06X..\n", addr); - uint8_t command[4] = { 0xd8, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; + uint8_t command[4] = { FC_BE64, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; set_gpio(0, 0); send_spi(command, 4); @@ -222,7 +338,7 @@ static void flash_prog(int addr, uint8_t *data, int n) if (verbose) fprintf(stderr, "prog 0x%06X +0x%03X..\n", addr, n); - uint8_t command[4] = { 0x02, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; + uint8_t command[4] = { FC_PP, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; set_gpio(0, 0); send_spi(command, 4); @@ -239,7 +355,7 @@ static void flash_read(int addr, uint8_t *data, int n) if (verbose) fprintf(stderr, "read 0x%06X +0x%03X..\n", addr, n); - uint8_t command[4] = { 0x03, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; + uint8_t command[4] = { FC_RD, (uint8_t)(addr >> 16), (uint8_t)(addr >> 8), (uint8_t)addr }; set_gpio(0, 0); send_spi(command, 4); @@ -259,7 +375,7 @@ static void flash_wait() while (1) { - uint8_t data[2] = { 0x05 }; + uint8_t data[2] = { FC_RSR1 }; set_gpio(0, 0); xfer_spi(data, 2); @@ -678,16 +794,17 @@ int main(int argc, char **argv) ftdic_latency_set = true; + /* Enter MPSSE (Multi-Protocol Synchronous Serial Engine) mode. Set all pins to output. */ if (ftdi_set_bitmode(&ftdic, 0xff, BITMODE_MPSSE) < 0) { fprintf(stderr, "Failed to set BITMODE_MPSSE on iCE FTDI USB device.\n"); error(2); } // enable clock divide by 5 - send_byte(0x8b); + send_byte(MC_TCK_D5); // set 6 MHz clock - send_byte(0x86); + send_byte(MC_SET_CLK_DIV); send_byte(0x00); send_byte(0x00); @@ -749,13 +866,13 @@ int main(int argc, char **argv) send_spi(buffer, rc); } - // add 48 dummy bits - send_byte(0x8f); + // add 48 dummy bits (aka 6 bytes) + send_byte(MC_CLK_N8); send_byte(0x05); send_byte(0x00); // add 1 more dummy bit - send_byte(0x8e); + send_byte(MC_CLK_N); send_byte(0x00); fprintf(stderr, "cdone: %s\n", get_cdone() ? "high" : "low"); diff --git a/icetime/icetime.cc b/icetime/icetime.cc index cdec43e..f9e0994 100644 --- a/icetime/icetime.cc +++ b/icetime/icetime.cc @@ -33,6 +33,10 @@ #include <map> #include <set> +#ifdef __EMSCRIPTEN__ +#include <emscripten.h> +#endif + // add this number of ns as estimate for clock distribution mismatch #define GLOBAL_CLK_DIST_JITTER 0.1 @@ -1283,16 +1287,24 @@ std::string ecnetname_to_vlog(std::string ec_name) std::string end = ec_name.substr(last_+1); size_t nidx = 0; - int num = std::stoi(end, &nidx, 10); - if(nidx == end.length()) { - return base + "[" + std::to_string(num) + "]"; - } else { + int num = 0; + try { + num = std::stoi(end, &nidx, 10); + if(nidx == end.length()) { + return base + "[" + std::to_string(num) + "]"; + } else { + return ec_name; + } + } catch(std::invalid_argument e) { // Not numeric and stoi throws exception return ec_name; } + } std::string make_dsp_ip(int x, int y, std::string net, std::string &primnet) { + // Don't generate excessive warnings about unknown cells + static std::set<std::string> unsupported_cells; std::tuple<int, int, std::string> ecnet(x, y, net); std::tuple<std::string, int, int, int> key("", -1, -1, -1); bool found = false; @@ -1423,9 +1435,11 @@ std::string make_dsp_ip(int x, int y, std::string net, std::string &primnet) return cell; } else { - netlist_cell_types[cell] = "SB_" + ectype; - fprintf(stderr, "Warning: timing analysis not supported for cell type %s\n", ectype.c_str()); - return cell; + if (unsupported_cells.find(ectype) == unsupported_cells.end()) { + fprintf(stderr, "Warning: timing analysis not supported for cell type %s\n", ectype.c_str()); + unsupported_cells.insert(ectype); + } + return ""; } } @@ -1567,8 +1581,8 @@ void make_seg_cell(int net, const net_segment_t &seg) if(device_type == "up5k" && ((seg.x == 0) || (seg.x == int(config_tile_type.size()) - 1))) { std::string primnet; auto cell = make_dsp_ip(seg.x, seg.y, seg.name, primnet); - netlist_cell_ports[cell][primnet] = net_name(net); if(cell != "") { + netlist_cell_ports[cell][primnet] = net_name(net); make_inmux(seg.x, seg.y, net); } return; @@ -2213,6 +2227,18 @@ void help(const char *cmd) int main(int argc, char **argv) { +#ifdef __EMSCRIPTEN__ + EM_ASM( + if (ENVIRONMENT_IS_NODE) + { + FS.mkdir('/hostcwd'); + FS.mount(NODEFS, { root: '.' }, '/hostcwd'); + FS.mkdir('/hostfs'); + FS.mount(NODEFS, { root: '/' }, '/hostfs'); + } + ); +#endif + bool listnets = false; bool print_timing = false; bool interior_timing = false; |