aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClifford Wolf <clifford@clifford.at>2017-08-31 14:55:36 +0200
committerClifford Wolf <clifford@clifford.at>2017-08-31 15:00:41 +0200
commit8354bc6086f11002cc58497f91f43200a09c13a9 (patch)
tree8a8ff79693f41b9678581ecd03900cc98513fa8b
parent7b07cd489d771d543c4db808f7b1eb22ced976bb (diff)
downloadicestorm-8354bc6086f11002cc58497f91f43200a09c13a9.tar.gz
icestorm-8354bc6086f11002cc58497f91f43200a09c13a9.tar.bz2
icestorm-8354bc6086f11002cc58497f91f43200a09c13a9.zip
Removed files that are under GNU licenses
-rw-r--r--icebox/Makefile9
-rwxr-xr-xicebox/icebox_asc2hlc.py1132
-rwxr-xr-xicebox/icebox_hlc2asc.py1052
-rw-r--r--icebox/tc_logic_xpr.py42
-rw-r--r--icebox/tc_rxlat_netnames.py69
-rw-r--r--icebox/tc_xlat_netnames.py79
-rw-r--r--iceprog/Makefile3
-rw-r--r--iceprog/iceprog.1155
8 files changed, 0 insertions, 2541 deletions
diff --git a/icebox/Makefile b/icebox/Makefile
index 778e2ce..430fb17 100644
--- a/icebox/Makefile
+++ b/icebox/Makefile
@@ -18,11 +18,6 @@ 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
-check: all
- python3 tc_xlat_netnames.py
- python3 tc_rxlat_netnames.py
- python3 tc_logic_xpr.py
-
clean:
rm -f chipdb-1k.txt chipdb-8k.txt chipdb-384.txt chipdb-5k.txt
rm -f icebox.pyc iceboxdb.pyc
@@ -38,8 +33,6 @@ install: all
cp icebox_chipdb.py $(DESTDIR)$(PREFIX)/bin/icebox_chipdb$(PY_EXE)
cp icebox_diff.py $(DESTDIR)$(PREFIX)/bin/icebox_diff$(PY_EXE)
cp icebox_explain.py $(DESTDIR)$(PREFIX)/bin/icebox_explain$(PY_EXE)
- cp icebox_asc2hlc.py $(DESTDIR)$(PREFIX)/bin/icebox_asc2hlc$(PY_EXE)
- cp icebox_hlc2asc.py $(DESTDIR)$(PREFIX)/bin/icebox_hlc2asc$(PY_EXE)
cp icebox_colbuf.py $(DESTDIR)$(PREFIX)/bin/icebox_colbuf$(PY_EXE)
cp icebox_html.py $(DESTDIR)$(PREFIX)/bin/icebox_html$(PY_EXE)
cp icebox_maps.py $(DESTDIR)$(PREFIX)/bin/icebox_maps$(PY_EXE)
@@ -52,8 +45,6 @@ uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/icebox_chipdb$(PY_EXE)
rm -f $(DESTDIR)$(PREFIX)/bin/icebox_diff$(PY_EXE)
rm -f $(DESTDIR)$(PREFIX)/bin/icebox_explain$(PY_EXE)
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_asc2hlc$(PY_EXE)
- rm -f $(DESTDIR)$(PREFIX)/bin/icebox_hlc2asc$(PY_EXE)
rm -f $(DESTDIR)$(PREFIX)/bin/icebox_colbuf$(PY_EXE)
rm -f $(DESTDIR)$(PREFIX)/bin/icebox_html$(PY_EXE)
rm -f $(DESTDIR)$(PREFIX)/bin/icebox_maps$(PY_EXE)
diff --git a/icebox/icebox_asc2hlc.py b/icebox/icebox_asc2hlc.py
deleted file mode 100755
index 0b96441..0000000
--- a/icebox/icebox_asc2hlc.py
+++ /dev/null
@@ -1,1132 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (C) 2017 Roland Lutz
-#
-# This program is free software: you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-import getopt, os, re, sys
-import icebox
-
-GLB_NETWK_EXTERNAL_BLOCKS = [(13, 8, 1), (0, 8, 1), (7, 17, 0), (7, 0, 0),
- (0, 9, 0), (13, 9, 0), (6, 0, 1), (6, 17, 1)]
-GLB_NETWK_INTERNAL_TILES = [(7, 0), (7, 17), (13, 9), (0, 9),
- (6, 17), (6, 0), (0, 8), (13, 8)]
-
-
-## Get the global name of a net.
-#
-# \param x, y coordinates of the tile to which the net belongs
-# \param fw, fh width and height of the tile fabric (excluding I/O tiles)
-# \param net net name
-#
-# \return the global name of the net if it is a span wire, otherwise
-# the unmodified net name
-#
-# There are 46624 span wires on the 1k (not counting dummies):
-#
-# span4_x[1..12]_g[1..20]_[0..11]
-# span4_y[1..16]_g[1..16]_[0..11]
-# span12_x[1..12]_g[1..28]_[0..1]
-# span12_y[1..16]_g[1..24]_[0..1]
-#
-# span4_left_g[3..16]_[0..3]
-# span4_right_g[5..18]_[0..3]
-# span4_bottom_g[3..12]_[0..3]
-# span4_top_g[5..14]_[0..3]
-#
-# span4_topleft[2,4,6,8]_[0..3]
-# span4_bottomright[2,4,6,8]_[0..3]
-#
-# dummy_y[1..16]_g[0..3]_[0..11]
-#
-# "Dummy" nets are horizontal accesses to non-existing vertical span
-# wires on the right edge which are listed by icebox but don't
-# actually connect to anything outside the tile itself.
-
-def translate_netname(x, y, fw, fh, net):
- def group_and_index(s, group_size):
- n = int(s)
- g = n // group_size
- i = n % group_size
- if g % 2 == 1:
- i = i + 1 - (i % 2) * 2
- return g, i
-
- # logic and RAM tiles
-
- match = re.match(r'sp4_h_r_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- return 'span4_y%d_g%d_%d' % (y, x - g + 4, i)
- match = re.match(r'sp4_h_l_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- return 'span4_y%d_g%d_%d' % (y, x - g + 3, i)
-
- match = re.match(r'sp4_v_b_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- return 'span4_x%d_g%d_%d' % (x, y + g, i)
- match = re.match(r'sp4_v_t_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- return 'span4_x%d_g%d_%d' % (x, y + g + 1, i)
- match = re.match(r'sp4_r_v_b_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- if x == fw:
- # this net doesn't connect anywhere
- return 'dummy_y%d_g%d_%d' % (y, g, i)
- else:
- return 'span4_x%d_g%d_%d' % (x + 1, y + g, i)
-
- match = re.match(r'sp12_h_r_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 2)
- return 'span12_y%d_g%d_%d' % (y, x - g + 12, i)
- match = re.match(r'sp12_h_l_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 2)
- return 'span12_y%d_g%d_%d' % (y, x - g + 11, i)
-
- match = re.match(r'sp12_v_b_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 2)
- return 'span12_x%d_g%d_%d' % (x, y + g, i)
- match = re.match(r'sp12_v_t_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 2)
- return 'span12_x%d_g%d_%d' % (x, y + g + 1, i)
-
- # I/O tiles
-
- match = re.match(r'span4_horz_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- if x == 0:
- return 'span4_y%d_g%d_%d' % (y, x - g + 4, i)
- else:
- return 'span4_y%d_g%d_%d' % (y, x - g + 3, i)
-
- match = re.match(r'span4_vert_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 12)
- if y == 0:
- return 'span4_x%d_g%d_%d' % (x, y + g + 1, i)
- else:
- return 'span4_x%d_g%d_%d' % (x, y + g, i)
-
- match = re.match(r'span12_horz_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 2)
- if x == 0:
- return 'span12_y%d_g%d_%d' % (y, x - g + 12, i)
- else:
- return 'span12_y%d_g%d_%d' % (y, x - g + 11, i)
-
- match = re.match(r'span12_vert_(\d+)$', net)
- if match is not None:
- g, i = group_and_index(match.group(1), 2)
- if y == 0:
- return 'span12_x%d_g%d_%d' % (x, y + g + 1, i)
- else:
- return 'span12_x%d_g%d_%d' % (x, y + g, i)
-
- # I/O tiles - peripheral wires
-
- match = re.match(r'span4_horz_r_(\d+)$', net)
- if match is not None:
- n = int(match.group(1)); g = n // 4; i = n % 4
- if y == 0:
- if fw - x + g - 4 < 0:
- return 'span4_bottomright%d_%d' % ((fw - x + 1 + g) * 2, i)
- elif x - g + 1 < 0:
- return 'span4_left_g%d_%d' % (-x + 1 + g, i)
- else:
- return 'span4_bottom_g%d_%d' % (x + 4 - g, i)
- else:
- if x - g - 1 < 0:
- return 'span4_topleft%d_%d' % ((x + 4 - g) * 2, i)
- elif x - g + 1 >= fw:
- return 'span4_right_g%d_%d' % (fh + fw - x + 1 + g, i)
- else:
- return 'span4_top_g%d_%d' % (x + 4 - g, i)
-
- match = re.match(r'span4_horz_l_(\d+)$', net)
- if match is not None:
- n = int(match.group(1)); g = n // 4; i = n % 4
- if y == 0:
- if x - g < 0:
- return 'span4_left_g%d_%d' % (-x + 2 + g, i)
- else:
- return 'span4_bottom_g%d_%d' % (x + 3 - g, i)
- else:
- if x - g - 2 < 0:
- return 'span4_topleft%d_%d' % ((x + 3 - g) * 2, i)
- else:
- return 'span4_top_g%d_%d' % (x + 3 - g, i)
-
- match = re.match(r'span4_vert_b_(\d+)$', net)
- if match is not None:
- n = int(match.group(1)); g = n // 4; i = n % 4
- if x == 0:
- if y + g - 3 < 0:
- return 'span4_bottom_g%d_%d' % (-y + 5 - g, i)
- if fh - y - g < 0:
- return 'span4_topleft%d_%d' % ((fh + 5 - y - g) * 2, i)
- else:
- return 'span4_left_g%d_%d' % (y + g, i)
- else:
- if y + g - 5 < 0:
- return 'span4_bottomright%d_%d' % ((y + g) * 2, i)
- elif y + g >= fh + 3:
- return 'span4_top_g%d_%d' % (fw + fh + 5 - y - g, i)
- else:
- return 'span4_right_g%d_%d' % (y + g, i)
-
- match = re.match(r'span4_vert_t_(\d+)$', net)
- if match is not None:
- n = int(match.group(1)); g = n // 4; i = n % 4
- if x == 0:
- if fh - y - g - 1 < 0:
- return 'span4_topleft%d_%d' % ((fh + 4 - y - g) * 2, i)
- else:
- return 'span4_left_g%d_%d' % (y + g + 1, i)
- else:
- if y + g >= fh + 2:
- return 'span4_top_g%d_%d' % (fw + fh + 4 - y - g, i)
- else:
- return 'span4_right_g%d_%d' % (y + g + 1, i)
-
- return net
-
-## Return the human-readable name of the \c fabout net of IO tile
-## <tt>(x, y)</tt>.
-
-def lookup_fabout(x, y):
- if (x, y) in GLB_NETWK_INTERNAL_TILES:
- return 'glb_netwk_%d' % GLB_NETWK_INTERNAL_TILES.index((x, y))
-
- return 'fabout'
-
-
-## Remove an argument from a LUT string and an associated list of
-## argument names.
-#
-# This is a helper function for \ref lut_to_logic_expression.
-#
-# \param lut string of 2^N `0' or `1' characters representing the
-# logic of an Nx1 look-up table
-# \param args list of N strings containing the human-readable names
-# of the arguments
-# \param i index of the argument to remove
-# \param keep boolean value indicating which value of the removed
-# argument is to be assumed in the resulting LUT
-#
-# \return a new pair <tt>(lut, args)</tt> with the argument removed
-
-def discard_argument(lut, args, i, keep):
- assert len(lut) == 1 << len(args)
- assert i >= 0 and i < len(args)
- return ''.join(bit for j, bit in enumerate(lut)
- if (j & (1 << i) != 0) == keep), \
- args[:i] + args[i + 1:]
-
-## Negate a tuple representation of a logic expression.
-#
-# This is a helper function for \ref lut_to_logic_expression.
-
-def negate_expr(expr):
- if len(expr) == 2:
- op, a = expr
- assert op == 'not'
- return a
- if len(expr) != 3:
- return 'not', expr
- a, op, b = expr
- if op == 'and':
- return negate_expr(a), 'or', negate_expr(b)
- if op == 'or':
- return negate_expr(a), 'and', negate_expr(b)
- assert op == 'xor'
- if len(a) == 2 and a[0] == 'not':
- return a[1], op, b
- if len(b) == 2 and b[0] == 'not':
- return a, op, b[1]
- return negate_expr(a), op, b
-
-## Convert a tuple representation of a logic expression into a string.
-#
-# This is a helper function for \ref lut_to_logic_expression.
-#
-# \param expr the expression to convert
-# \param parenthize whether a compound expression should be
-# surrounded by parentheses
-
-def stringify(expr, parenthize):
- if type(expr) == str:
- return expr
- assert type(expr) == tuple
-
- if len(expr) == 2:
- op, a = expr
- assert op == 'not'
- assert type(a) == str
- return "!" + a
-
- if len(expr) == 5:
- a, op0, b, op1, c = expr
- assert op0 == '?' and op1 == ':'
- s = '%s ? %s : %s' % (stringify(a, False), stringify(b, False),
- stringify(c, False))
- if parenthize:
- return '(%s)' % s
- return s
-
- assert len(expr) == 3
-
- a, op, b = expr
- l = [a, b]
- i = 0
- while i < len(l):
- if type(l[i]) == tuple and len(l[i]) == 3 and l[i][1] == op:
- l = l[:i] + [l[i][0], l[i][2]] + l[i + 1:]
- else:
- i += 1
-
- if op == 'and':
- op = '&'
- elif op == 'xor':
- op = '^'
- elif op == 'or':
- op = '|'
-
- s = (' %s ' % op).join(stringify(x, True) for x in l)
- if parenthize:
- return '(%s)' % s
- return s
-
-## Remove arguments which don't affect the result from a LUT string
-## and an associated list of argument names.
-#
-# This is a helper function for \ref lut_to_logic_expression.
-#
-# \param lut string of 2^N `0' or `1' characters representing the
-# logic of an Nx1 look-up table
-# \param args list of N strings containing the human-readable names
-# of the arguments
-#
-# \return a new pair <tt>(lut, args)</tt> with all unused arguments
-# removed
-
-def discard_unused_arguments(lut, args):
- assert len(lut) == 1 << len(args)
- i = 0
- while i < len(args):
- diff = False
- for j in range(len(lut)):
- if j & (1 << i) == 0 and lut[j] != lut[j | (1 << i)]:
- diff = True
- if not diff:
- lut, args = discard_argument(lut, args, i, False)
- else:
- i += 1
- return lut, args
-
-## Convert a LUT string to a logic expression.
-#
-# \param lut string of 2^N `0' or `1' characters representing the
-# logic of an Nx1 look-up table
-# \param args list of N strings containing the human-readable names
-# of the arguments
-#
-# \return a string containing a human-readable logic expression
-# equivalent to the look-up table
-#
-# Example: lut_to_logic_expression('00010000', ['a', 'b', 'c']) -> 'a & b & !c'
-
-def lut_to_logic_expression(lut, args):
- lut, args = discard_unused_arguments(lut, args)
-
- # filter out independent top-level arguments
- toplevel_args = []
- i = 0
- while i < len(args) and len(args) >= 2:
- ai_0 = set(bit for j, bit in enumerate(lut) if j & (1 << i) == 0)
- ai_1 = set(bit for j, bit in enumerate(lut) if j & (1 << i) != 0)
- assert len(ai_0) == 2 or len(ai_1) == 2
-
- if len(ai_0) == 1:
- # expression is constant if this argument is 0
- # e = (...) & arg or e = (...) | !arg
- if tuple(ai_0)[0] == '0':
- toplevel_args.append(('and', args[i]))
- else:
- toplevel_args.append(('or', ('not', args[i])))
- lut, args = discard_argument(lut, args, i, True)
- i = 0
- continue
-
- if len(ai_1) == 1:
- # expression is constant if this argument is 1
- # e = (...) & !arg or e = (...) | arg
- if tuple(ai_1)[0] == '0':
- toplevel_args.append(('and', ('not', args[i])))
- else:
- toplevel_args.append(('or', args[i]))
- lut, args = discard_argument(lut, args, i, False)
- i = 0
- continue
-
- i += 1
-
- i = 0
- while i < len(args) and len(args) >= 2:
- is_xor = True
- for j in range(len(lut)):
- if j & (1 << i) == 0 and lut[j] == lut[j | (1 << i)]:
- is_xor = False
- break
-
- if is_xor:
- toplevel_args.append(('xor', args[i]))
- lut, args = discard_argument(lut, args, i, False)
- continue
-
- i += 1
-
- # detect simple top-level ternary conditions
- i = 0
- while i < len(args) and len(args) >= 3:
- j = i + 1
- while j < len(args):
- ai_0_aj_0 = set(bit for k, bit in enumerate(lut)
- if k & (1 << i) == 0 and k & (1 << j) == 0)
- ai_0_aj_1 = set(bit for k, bit in enumerate(lut)
- if k & (1 << i) == 0 and k & (1 << j) != 0)
- ai_1_aj_0 = set(bit for k, bit in enumerate(lut)
- if k & (1 << i) != 0 and k & (1 << j) == 0)
- ai_1_aj_1 = set(bit for k, bit in enumerate(lut)
- if k & (1 << i) != 0 and k & (1 << j) != 0)
- assert len(ai_0_aj_0) == 2 or len(ai_0_aj_1) == 2 or \
- len(ai_1_aj_0) == 2 or len(ai_1_aj_1) == 2
-
- if (len(ai_0_aj_0) == 2 or len(ai_0_aj_1) == 2) and \
- (len(ai_1_aj_0) == 2 or len(ai_1_aj_1) == 2) and \
- (len(ai_0_aj_0) == 2 or len(ai_1_aj_0) == 2) and \
- (len(ai_0_aj_1) == 2 or len(ai_1_aj_1) == 2):
- j += 1
- continue
-
- ai_doesnt_matter_for_aj_0 = True
- ai_doesnt_matter_for_aj_1 = True
- aj_doesnt_matter_for_ai_0 = True
- aj_doesnt_matter_for_ai_1 = True
-
- for k in range(len(lut)):
- if k & (1 << i) != 0 or k & (1 << j) != 0:
- continue
- if lut[k] != lut[k | (1 << i)]:
- ai_doesnt_matter_for_aj_0 = False
- if lut[k | (1 << j)] != lut[k | (1 << i) | (1 << j)]:
- ai_doesnt_matter_for_aj_1 = False
- if lut[k] != lut[k | (1 << j)]:
- aj_doesnt_matter_for_ai_0 = False
- if lut[k | (1 << i)] != lut[k | (1 << i) | (1 << j)]:
- aj_doesnt_matter_for_ai_1 = False
-
- if len(ai_0_aj_0) == 1 and len(ai_0_aj_1) == 1 and \
- aj_doesnt_matter_for_ai_1:
- assert tuple(ai_0_aj_0)[0] != tuple(ai_0_aj_1)[0]
- if tuple(ai_0_aj_0)[0] == '0':
- toplevel_args.append((args[i], '?', ':', args[j]))
- else:
- toplevel_args.append((args[i], '?', ':', ('not', args[j])))
- lut, args = discard_argument(lut, args, i, True)
-
- # break loops
- i = len(args)
- j = len(args)
- break
-
- if len(ai_1_aj_0) == 1 and len(ai_1_aj_1) == 1 and \
- aj_doesnt_matter_for_ai_0:
- assert tuple(ai_1_aj_0)[0] != tuple(ai_1_aj_1)[0]
- if tuple(ai_1_aj_0)[0] == '0':
- toplevel_args.append((args[i], '?', args[j], ':'))
- else:
- toplevel_args.append((args[i], '?', ('not', args[j]), ':'))
- lut, args = discard_argument(lut, args, i, False)
-
- # break loops
- i = len(args)
- j = len(args)
- break
-
- if len(ai_0_aj_0) == 1 and len(ai_1_aj_0) == 1 and \
- ai_doesnt_matter_for_aj_1:
- assert tuple(ai_0_aj_0)[0] != tuple(ai_1_aj_0)[0]
- if tuple(ai_0_aj_0)[0] == '0':
- toplevel_args.append((args[j], '?', ':', args[i]))
- else:
- toplevel_args.append((args[j], '?', ':', ('not', args[i])))
- lut, args = discard_argument(lut, args, j, True)
-
- # break loops
- i = len(args)
- j = len(args)
- break
-
- if len(ai_0_aj_1) == 1 and len(ai_1_aj_1) == 1 and \
- ai_doesnt_matter_for_aj_0:
- assert tuple(ai_0_aj_1)[0] != tuple(ai_1_aj_1)[0]
- if tuple(ai_0_aj_1)[0] == '0':
- toplevel_args.append((args[j], '?', args[i], ':'))
- else:
- toplevel_args.append((args[j], '?', ('not', args[i]), ':'))
- lut, args = discard_argument(lut, args, j, False)
-
- # break loops
- i = len(args)
- j = len(args)
- break
-
- j += 1
- i += 1
-
- lut, args = discard_unused_arguments(lut, args)
-
- # group pairwise isolated arguments
- i = 0
- while i < len(args):
- j = i + 1
- while j < len(args):
- ai_doesnt_matter_for_aj_0 = True
- ai_doesnt_matter_for_aj_1 = True
- aj_doesnt_matter_for_ai_0 = True
- aj_doesnt_matter_for_ai_1 = True
- both_dont_matter_if_equal = True
- both_dont_matter_if_unequal = True
-
- for k in range(len(lut)):
- if k & (1 << i) != 0 or k & (1 << j) != 0:
- continue
- if lut[k] != lut[k | (1 << i)]:
- ai_doesnt_matter_for_aj_0 = False
- if lut[k | (1 << j)] != lut[k | (1 << i) | (1 << j)]:
- ai_doesnt_matter_for_aj_1 = False
- if lut[k] != lut[k | (1 << j)]:
- aj_doesnt_matter_for_ai_0 = False
- if lut[k | (1 << i)] != lut[k | (1 << i) | (1 << j)]:
- aj_doesnt_matter_for_ai_1 = False
- if lut[k] != lut[k | (1 << i) | (1 << j)]:
- both_dont_matter_if_equal = False
- if lut[k | (1 << i)] != lut[k | (1 << j)]:
- both_dont_matter_if_unequal = False
-
- # There are five possibilities of coupled arguments: one
- # of the four combinations differs from the other three,
- # or they are xor'ed
-
- if ai_doesnt_matter_for_aj_1 and \
- aj_doesnt_matter_for_ai_1 and \
- both_dont_matter_if_unequal:
- # special case is ai=0 aj=0
- args = args[:i] + ((args[i], 'or', args[j]), ) + args[i + 1:]
- lut, args = discard_argument(lut, args, j, False)
- j = i + 1
- elif ai_doesnt_matter_for_aj_1 and \
- aj_doesnt_matter_for_ai_0 and \
- both_dont_matter_if_equal:
- # special case is ai=1 aj=0
- args = args[:i] + ((args[i], 'and', negate_expr(args[j])), ) + \
- args[i + 1:]
- lut, args = discard_argument(lut, args, j, False)
- j = i + 1
- elif ai_doesnt_matter_for_aj_0 and \
- aj_doesnt_matter_for_ai_1 and \
- both_dont_matter_if_equal:
- # special case is ai=0 aj=1
- args = args[:i] + ((args[i], 'or', negate_expr(args[j])), ) + \
- args[i + 1:]
- lut, args = discard_argument(lut, args, j, True)
- j = i + 1
- elif ai_doesnt_matter_for_aj_0 and \
- aj_doesnt_matter_for_ai_0 and \
- both_dont_matter_if_unequal:
- # special case is ai=1 aj=1
- args = args[:i] + ((args[i], 'and', args[j]), ) + args[i + 1:]
- lut, args = discard_argument(lut, args, j, True)
- j = i + 1
-
- elif both_dont_matter_if_equal and \
- both_dont_matter_if_unequal:
- args = args[:i] + ((args[i], 'xor', args[j]), ) + args[i + 1:]
- lut, args = discard_argument(lut, args, j, False)
- j = i + 1
- else:
- j += 1
- i += 1
-
- # collect the result
-
- if not args:
- # constant expression
- assert len(lut) == 1
- return lut
-
- negate_result = lut.count('1') > lut.count('0')
- if negate_result:
- lut = ''.join('1' if bit == '0' else '0' for bit in lut)
-
- result = None
- for i, bit in enumerate(lut):
- if bit == '0':
- continue
- expr = None
- for j, arg in enumerate(args):
- if i & (1 << j) == 0:
- arg = negate_expr(arg)
- if expr is None:
- expr = arg
- else:
- expr = (expr, 'and', arg)
- if result is None:
- result = expr
- else:
- result = (result, 'or', expr)
-
- if negate_result:
- result = negate_expr(result)
-
- for toplevel_arg in reversed(toplevel_args):
- if len(toplevel_arg) != 4:
- result = tuple(reversed(toplevel_arg)) + (result, )
- elif toplevel_arg[2] == ':':
- result = toplevel_arg[0:2] + (result, ) + toplevel_arg[2:4]
- else:
- assert toplevel_arg[3] == ':'
- result = toplevel_arg + (result, )
-
- return stringify(result, False)
-
-
-class Fabric:
- def __init__(self, ic):
- self.ic = ic
- self.tiles = {}
- #self.colbuf = set()
-
- io_blocks = {}
- ieren_blocks = {}
-
- for x0, y0, b0, x1, y1, b1 in self.ic.ieren_db():
- i = IOBlock()
- assert (x0, y0, b0) not in io_blocks
- io_blocks[x0, y0, b0] = i
- assert (x1, y1, b1) not in ieren_blocks
- ieren_blocks[x1, y1, b1] = i
-
- for xy in ic.io_tiles:
- assert xy not in self.tiles
- self.tiles[xy] = IOTile(self, xy,
- (io_blocks.pop((xy[0], xy[1], 0), None),
- io_blocks.pop((xy[0], xy[1], 1), None)),
- (ieren_blocks.pop((xy[0], xy[1], 0), None),
- ieren_blocks.pop((xy[0], xy[1], 1), None)))
- assert not io_blocks
- assert not ieren_blocks
-
- for xy in ic.logic_tiles:
- assert xy not in self.tiles
- self.tiles[xy] = LogicTile(self, xy)
-
- for xy in ic.ramb_tiles:
- assert xy not in self.tiles
- self.tiles[xy] = RAMBTile(self, xy)
-
- for xy in ic.ramt_tiles:
- assert xy not in self.tiles
- self.tiles[xy] = RAMTTile(self, xy)
-
- for x, y in self.tiles:
- assert x >= 0 and x <= self.ic.max_x
- assert y >= 0 and y <= self.ic.max_y
- for x in range(self.ic.max_x + 1):
- for y in range(self.ic.max_y + 1):
- should_exist = (x > 0 and x < self.ic.max_x) or \
- (y > 0 and y < self.ic.max_y)
- assert ((x, y) in self.tiles) == should_exist
-
- for xy in ic.ram_data:
- assert type(self.tiles.get(xy, None)) == RAMBTile
-
- #colbuf_db = ic.colbuf_db()
- #for x, y, i in self.colbuf:
- # exists = False
- # for src_x, src_y, dst_x, dst_y in colbuf_db:
- # if src_x != x or src_y != y:
- # continue
- # assert (dst_x, dst_y) in self.tiles
- # assert not self.tiles[dst_x, dst_y].colbuf[i]
- # self.tiles[dst_x, dst_y].colbuf[i] = True
- # exists = True
- # assert exists
- #
- #for xy in self.tiles:
- # for br in self.tiles[xy].buffer_and_routing:
- # if br[0].startswith('glb_netwk_'):
- # assert self.tiles[xy].colbuf[int(br[0][10:])]
-
- for bit in self.ic.extra_bits:
- directive, arg = self.ic.lookup_extra_bit(bit)
- assert directive == 'padin_glb_netwk'
- x, y, n = GLB_NETWK_EXTERNAL_BLOCKS[int(arg)]
- assert type(self.tiles.get((x, y), None)) == IOTile
- block = self.tiles[x, y].io_blocks[n]
- assert block is not None
- block.padin_glb_netwk = True
-
- def printout(self, options):
- print('device "%s" %d %d' % (self.ic.device, self.ic.max_x - 1,
- self.ic.max_y - 1))
-
- print('')
- # internal_configuration_oscillator_frequency = low | medium | high
- #print('coldboot = off')
- print('warmboot = on') # IceStorm assumes this to be always on
-
- for xy in sorted(self.tiles.keys(), key = lambda xy: (xy[1], xy[0])):
- self.tiles[xy].printout(options)
-
-class Tile:
- def __init__(self, fabric, xy, data, is_logic_block):
- self.fabric = fabric
- self.ic = fabric.ic
- self.xy = xy
- self.data = data
-
- self.buffer_and_routing = set()
- self.used_buffer_and_routing = set()
- self.text = set()
- self.bitinfo = list()
- self.unknown_bits = False
-
- x, y = xy
- db = self.ic.tile_db(x, y)
- mapped_bits = set()
-
- # 'data' is a list of strings containing a series of zeroes and
- # ones. 'bits' is a set of strings containing an entry
- # "B<row>[<col>]" or "!B<row>[<col>]" for each bit.
-
- bits = set()
- for k, line in enumerate(data):
- for i in range(len(line)):
- if line[i] == '1':
- bits.add('B%d[%d]' % (k, i))
- else:
- bits.add('!B%d[%d]' % (k, i))
-
- for entry in db:
- # LC bits don't have a useful entry in the database; skip them
- # for now
- if re.match(r'LC_', entry[1]):
- continue
-
- # some nets have different names depending on the tile; filter
- # out non-applicable net names
- if entry[1] in ('routing', 'buffer') and (
- not self.ic.tile_has_net(x, y, entry[2]) or
- not self.ic.tile_has_net(x, y, entry[3])):
- continue
-
- # are all required bits set/unset?
- match = True
- for bit in entry[0]:
- if not bit in bits:
- match = False
- if match:
- for bit in entry[0]:
- mapped_bits.add(bit)
-
- if entry[1:] == ['IoCtrl', 'IE_0']:
- if match != (self.ic.device == '1k'):
- self.ieren_blocks[0].enable_input = True
- continue
- if entry[1:] == ['IoCtrl', 'REN_0']:
- if match:
- self.ieren_blocks[0].disable_pull_up = True
- continue
- if entry[1:] == ['IoCtrl', 'IE_1']:
- if match != (self.ic.device == '1k'):
- self.ieren_blocks[1].enable_input = True
- continue
- if entry[1:] == ['IoCtrl', 'REN_1']:
- if match:
- self.ieren_blocks[1].disable_pull_up = True
- continue
-
- if entry[1].startswith('IOB_') and entry[2].startswith('PINTYPE_'):
- if match:
- self.io_blocks[int(entry[1][4:])].pintype \
- |= 1 << int(entry[2][8:])
- continue
-
- if entry[1:] == ['RamConfig', 'PowerUp']:
- if match != (self.ic.device == '1k'):
- self.text.add('power_up')
- continue
-
- if entry[1] == 'routing':
- if match:
- src = translate_netname(self.xy[0], self.xy[1],
- self.ic.max_x - 1,
- self.ic.max_y - 1, entry[2])
- dst = translate_netname(self.xy[0], self.xy[1],
- self.ic.max_x - 1,
- self.ic.max_y - 1, entry[3])
- if dst == 'fabout':
- dst = lookup_fabout(*self.xy)
- self.buffer_and_routing.add((src, '<->', dst))
- continue
- if entry[1] == 'buffer':
- if match:
- src = translate_netname(self.xy[0], self.xy[1],
- self.ic.max_x - 1,
- self.ic.max_y - 1, entry[2])
- dst = translate_netname(self.xy[0], self.xy[1],
- self.ic.max_x - 1,
- self.ic.max_y - 1, entry[3])
- if dst == 'fabout':
- dst = lookup_fabout(*self.xy)
- self.buffer_and_routing.add((src, '->', dst))
- continue
-
- if entry[1] == 'ColBufCtrl':
- assert entry[2].startswith('glb_netwk_')
- #if match:
- # fabric.colbuf.add(self.xy + (int(entry[2][10:]), ))
- continue
-
- if match:
- self.text.add(' '.join(entry[1:]))
-
- for prefix in ('local_', 'glb2local_'):
- for fst in [fst for fst in self.buffer_and_routing
- if fst[-1].startswith(prefix)]:
- used = False
- for snd in [snd for snd in self.buffer_and_routing
- if snd[0] == fst[-1]]:
- self.buffer_and_routing.remove(snd)
- self.buffer_and_routing.add(fst[:-1] + snd)
- used = True
- if used:
- self.buffer_and_routing.remove(fst)
-
- for k, line in enumerate(data):
- self.bitinfo.append('')
- extra_text = ''
- for i in range(len(line)):
- if 36 <= i <= 45 and is_logic_block:
- self.bitinfo[-1] += '*' if line[i] == '1' else '-'
- elif line[i] == '1' and 'B%d[%d]' % (k, i) not in mapped_bits:
- self.unknown_bits = True
- extra_text += ' B%d[%d]' % (k, i)
- self.bitinfo[-1] += '?'
- else:
- self.bitinfo[-1] += '+' if line[i] == '1' else '-'
- self.bitinfo[-1] += extra_text
-
- def get_hlc(self):
- return sorted(set.union(self.text,
- set(' '.join(t)
- for t in set.difference(
- self.buffer_and_routing,
- self.used_buffer_and_routing))))
-
- def printout(self, stmt, options):
- text = self.get_hlc()
- if text or self.unknown_bits or options.print_all:
- if self.unknown_bits or options.print_map:
- print()
- if self.unknown_bits:
- print("; Warning: No DB entries for some bits:")
- for k, line in enumerate(self.bitinfo):
- print("; %4s %s" % ('B%d' % k, line))
- print()
- print("%s %d %d {" % (stmt, self.xy[0], self.xy[1]))
- for line in text:
- print(" " + line)
- print("}")
-
-class LogicCell:
- def __init__(self, tile, lcidx):
- self.lut = ''.join(icebox.get_lutff_lut_bits(tile.data, lcidx))
- self.expr = lut_to_logic_expression(
- self.lut, ('in_0', 'in_1', 'in_2', 'in_3'))
-
- self.options = []
- lutff_option_bits = ''.join(icebox.get_lutff_seq_bits(tile.data, lcidx))
- if lutff_option_bits[0] == '1': self.options.append('enable_carry')
- if lutff_option_bits[1] == '1': self.options.append('enable_dff')
- if lutff_option_bits[2] == '1': self.options.append('set_noreset')
- if lutff_option_bits[3] == '1': self.options.append('async_setreset')
-
- self.buffer_and_routing0 = set()
- self.buffer_and_routing1 = set()
- for br in tuple(tile.buffer_and_routing):
- if br[0] == 'lutff_%d/out' % lcidx:
- self.buffer_and_routing1.add((br[0][8:], ) + br[1:])
- tile.used_buffer_and_routing.add(br)
- elif br[-1].startswith('lutff_%d/' % lcidx):
- self.buffer_and_routing0.add(br[:-1] + (br[-1][8:], ))
- tile.used_buffer_and_routing.add(br)
-
- def get_hlc(self):
- if self.lut == '0000000000000000' and not self.options:
- t = []
- elif len(self.expr) > 64:
- t = ['lut ' + self.lut]
- else:
- t = ['out = ' + self.expr]
- return [' '.join(t) for t in sorted(self.buffer_and_routing0,
- key = lambda x: x[-1])] + \
- t + self.options + \
- [' '.join(t) for t in sorted(self.buffer_and_routing1,
- key = lambda x: x[-1])]
-
-class LogicTile(Tile):
- def __init__(self, fabric, xy):
- super().__init__(fabric, xy, fabric.ic.logic_tiles[xy], True)
- self.cells = tuple(LogicCell(self, lcidx) for lcidx in range(8))
-
- def get_hlc(self):
- text = super().get_hlc()
-
- for i, cell in reversed(tuple(enumerate(self.cells))):
- t = cell.get_hlc()
- if t:
- text = ['lutff_%d {' % i] + \
- [' %s' % s for s in t] + \
- ['}'] + \
- text
-
- return text
-
- def printout(self, options):
- super().printout('logic_tile', options)
-
-class IOBlock:
- def __init__(self):
- # stored in the I/O tile where this block is located
- self.pintype = 0
-
- # stored in the I/O tile where this is an IE/REN block
- self.enable_input = False
- self.disable_pull_up = False
-
- # stored as an extra bit
- self.padin_glb_netwk = False
-
-class IOTile(Tile):
- def __init__(self, fabric, xy, io_blocks, ieren_blocks):
- self.io_blocks = io_blocks
- self.ieren_blocks = ieren_blocks
- super().__init__(fabric, xy, fabric.ic.io_tiles[xy], False)
- #self.cells = tuple(IOCell() for i in range(2))
-
- for i, block in enumerate(io_blocks):
- if block is None:
- continue
- block.buffer_and_routing0 = set()
- block.buffer_and_routing1 = set()
- for br in tuple(self.buffer_and_routing):
- if br[0].startswith('io_%d/D_IN_' % i):
- block.buffer_and_routing1.add((br[0][5:], ) + br[1:])
- self.used_buffer_and_routing.add(br)
- elif br[-1].startswith('io_%d/' % i):
- block.buffer_and_routing0.add(br[:-1] + (br[-1][5:], ))
- self.used_buffer_and_routing.add(br)
-
- def get_hlc(self):
- # if io_blocks[N] is None, this means there's no I/O pin there
-
- text = super().get_hlc()
- for n in (1, 0):
- block = self.io_blocks[n]
- if block is None:
- continue
-
- t = []
- input_pt = block.pintype & 3
- output_pt = block.pintype >> 2 & 15
- unknown_pt = block.pintype >> 6
- if input_pt != 0:
- t.append('input_pin_type = %s' % (
- 'registered_pin',
- 'simple_input_pin',
- 'latched_registered_pin',
- 'latched_pin')[input_pt])
- if output_pt != 0:
- t.append('output_pin_type = %s' % (
- 'no_output',
- '1',
- '2',
- '3',
- 'DDR',
- 'REGISTERED',
- 'simple_output_pin',
- 'REGISTERED_INVERTED',
- 'DDR_ENABLE',
- 'REGISTERED_ENABLE',
- 'OUTPUT_TRISTATE',
- 'REGISTERED_ENABLE_INVERTED',
- 'DDR_ENABLE_REGISTERED',
- 'REGISTERED_ENABLE_REGISTERED',
- 'ENABLE_REGISTERED',
- 'REGISTERED_ENABLE_REGISTERED_INVERTED')[output_pt])
- if unknown_pt != 0:
- t.append('unknown_pin_type = %d' % unknown_pt)
- if block.enable_input:
- t.append('enable_input')
- if block.disable_pull_up:
- t.append('disable_pull_up')
-
- t += [' '.join(t) for t in sorted(block.buffer_and_routing0,
- key = lambda x: x[-1])]
- t += [' '.join(t) for t in sorted(block.buffer_and_routing1,
- key = lambda x: x[0])]
- if block.padin_glb_netwk:
- t += ['GLOBAL_BUFFER_OUTPUT -> glb_netwk_%d'
- % GLB_NETWK_EXTERNAL_BLOCKS.index(self.xy + (n, ))]
-
- if t:
- text = ['io_%d {' % n] + \
- [' %s' % s for s in t] + \
- ['}'] + \
- text
-
- return text
-
- def printout(self, options):
- super().printout('io_tile', options)
-
-class IOCell:
- pass
-
-class RAMBTile(Tile):
- def __init__(self, fabric, xy):
- super().__init__(fabric, xy, fabric.ic.ramb_tiles[xy], False)
- if xy in fabric.ic.ram_data:
- self.data = fabric.ic.ram_data[xy]
- else:
- self.data = None
-
- def get_hlc(self):
- text = super().get_hlc()
- if self.data is not None:
- text.append('')
- text.append('data {')
- for line in self.data:
- text.append(' ' + line)
- text.append('}')
- return text
-
- def printout(self, options):
- super().printout('ramb_tile', options)
-
-class RAMTTile(Tile):
- def __init__(self, fabric, xy):
- super().__init__(fabric, xy, fabric.ic.ramt_tiles[xy], False)
-
- def printout(self, options):
- super().printout('ramt_tile', options)
-
-
-class Options:
- def __init__(self):
- self.print_map = False
- self.print_all = False
-
-def main():
- program_short_name = os.path.basename(sys.argv[0])
- options = Options()
-
- try:
- opts, args = getopt.getopt(sys.argv[1:], 'mA', ['help', 'version'])
- except getopt.GetoptError as e:
- sys.stderr.write("%s: %s\n" % (program_short_name, e.msg))
- sys.stderr.write("Try `%s --help' for more information.\n"
- % sys.argv[0])
- sys.exit(1)
-
- for opt, arg in opts:
- if opt == '--help':
- sys.stderr.write("""\
-Create a high-level representation from an ASCII bitstream.
-Usage: %s [OPTION]... FILE
-
- -m print tile config bitmaps
- -A don't skip uninteresting tiles
-
- --help display this help and exit
- --version output version information and exit
-
-If you have a bug report, please file an issue on github:
- https://github.com/rlutz/icestorm/issues
-""" % sys.argv[0])
- sys.exit(0)
-
- if opt == '--version':
- sys.stderr.write("""\
-icebox_asc2hlc - create a high-level representation from an ASCII bitstream
-Copyright (C) 2017 Roland Lutz
-
-This program is free software: you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation, either version 3 of
-the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-""")
- sys.exit(0)
-
- if opt == '-m':
- options.print_map = True
- elif opt == '-A':
- options.print_all = True
-
- if not args:
- sys.stderr.write("%s: missing argument\n" % (program_short_name))
- sys.stderr.write("Try `%s --help' for more information.\n"
- % sys.argv[0])
- sys.exit(1)
-
- if len(args) != 1:
- sys.stderr.write("%s: too many arguments\n" % (program_short_name))
- sys.stderr.write("Try `%s --help' for more information.\n"
- % sys.argv[0])
- sys.exit(1)
-
- ic = icebox.iceconfig()
- if args[0] == '-':
- ic.read_file('/dev/stdin')
- else:
- ic.read_file(args[0])
-
- fabric = Fabric(ic)
- fabric.printout(options)
-
-if __name__ == '__main__':
- main()
diff --git a/icebox/icebox_hlc2asc.py b/icebox/icebox_hlc2asc.py
deleted file mode 100755
index 54d6722..0000000
--- a/icebox/icebox_hlc2asc.py
+++ /dev/null
@@ -1,1052 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (C) 2017 Roland Lutz
-#
-# This program is free software: you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-import getopt, os, re, sys
-import icebox
-
-GLB_NETWK_EXTERNAL_BLOCKS = [(13, 8, 1), (0, 8, 1), (7, 17, 0), (7, 0, 0),
- (0, 9, 0), (13, 9, 0), (6, 0, 1), (6, 17, 1)]
-GLB_NETWK_INTERNAL_TILES = [(7, 0), (7, 17), (13, 9), (0, 9),
- (6, 17), (6, 0), (0, 8), (13, 8)]
-
-
-## Get the tile-local name of a net.
-#
-# \param x, y coordinates of the tile to which the net belongs
-# \param fw, fh width and height of the tile fabric (excluding I/O tiles)
-# \param net global net name
-#
-# \return the tile-local name of the net if it is a span wire,
-# otherwise the unmodified net name
-
-def untranslate_netname(x, y, fw, fh, net):
- def index(g, i, group_size):
- if g % 2 == 1:
- i = i + 1 - (i % 2) * 2
- return g * group_size + i
-
- match = re.match(r'span4_y(\d+)_g(\d+)_(\d+)$', net)
- if match is not None:
- my = int(match.group(1))
- mw = int(match.group(2))
- mi = int(match.group(3))
- assert my == y
- assert mi >= 0 and mi < 12
-
- mg = x - mw + 4
- assert mg >= 0 and mg <= 4
-
- if x == 0:
- return 'span4_horz_%d' % index(mg, mi, 12)
- if x == fw + 1:
- return 'span4_horz_%d' % index(mg - 1, mi, 12)
-
- if mg == 4:
- return 'sp4_h_l_%d' % index(mg - 1, mi, 12)
- else:
- return 'sp4_h_r_%d' % index(mg, mi, 12)
-
- match = re.match(r'span4_x(\d+)_g(\d+)_(\d+)$', net)
- if match is not None:
- mx = int(match.group(1))
- mw = int(match.group(2))
- mi = int(match.group(3))
- assert mi >= 0 and mi < 12
- mg = mw - y
- assert mg >= 0 and mg <= 4
-
- if y == 0:
- return 'span4_vert_%d' % index(mg - 1, mi, 12)
- if y == fh + 1:
- return 'span4_vert_%d' % index(mg, mi, 12)
-
- if mx == x + 1:
- assert mg < 4
- return 'sp4_r_v_b_%d' % index(mg, mi, 12)
-
- assert mx == x
- if mg == 4:
- return 'sp4_v_t_%d' % index(mg - 1, mi, 12)
- else:
- return 'sp4_v_b_%d' % index(mg, mi, 12)
-
- match = re.match(r'dummy_y(\d+)_g(\d+)_(\d+)$', net)
- if match is not None:
- my = int(match.group(1))
- mw = int(match.group(2))
- mi = int(match.group(3))
- assert my == y
-
- mg = mw
- assert mg >= 0 and mg < 4
-
- return 'sp4_r_v_b_%d' % index(mg, mi, 12)
-
- match = re.match(r'span12_y(\d+)_g(\d+)_(\d+)$', net)
- if match is not None:
- my = int(match.group(1))
- mw = int(match.group(2))
- mi = int(match.group(3))
- assert my == y
- assert mi >= 0 and mi < 2
-
- mg = x - mw + 12
- assert mg >= 0 and mg <= 12
-
- if x == 0:
- return 'span12_horz_%d' % index(mg, mi, 2)
- if x == fw + 1:
- return 'span12_horz_%d' % index(mg - 1, mi, 2)
-
- if mg == 12:
- return 'sp12_h_l_%d' % index(mg - 1, mi, 2)
- else:
- return 'sp12_h_r_%d' % index(mg, mi, 2)
-
- match = re.match(r'span12_x(\d+)_g(\d+)_(\d+)$', net)
- if match is not None:
- mx = int(match.group(1))
- mw = int(match.group(2))
- mi = int(match.group(3))
- assert mx == x
- assert mi >= 0 and mi < 2
-
- mg = mw - y
- assert mg >= 0 and mg <= 12
-
- if y == 0:
- return 'span12_vert_%d' % index(mg - 1, mi, 2)
- if y == fh + 1:
- return 'span12_vert_%d' % index(mg, mi, 2)
-
- if mg == 12:
- return 'sp12_v_t_%d' % index(mg - 1, mi, 2)
- else:
- return 'sp12_v_b_%d' % index(mg, mi, 2)
-
- match = re.match(r'span4_bottom_g(\d+)_(\d+)$', net)
- if match is not None:
- mw = int(match.group(1))
- mi = int(match.group(2))
- assert mi >= 0 and mi < 4
-
- if x == 0:
- assert y != 0
- mg = -y + 5 - mw
- assert y + mg - 3 < 0
- return 'span4_vert_b_%d' % (mg * 4 + mi)
- else:
- assert y == 0
- mg = x + 4 - mw
- assert x - mg + 1 >= 0
-
- if mg == 4:
- return 'span4_horz_l_%d' % (mg * 4 + mi - 4)
- else:
- assert fw - x + mg - 4 >= 0
- return 'span4_horz_r_%d' % (mg * 4 + mi)
-
- match = re.match(r'span4_left_g(\d+)_(\d+)$', net)
- if match is not None:
- mw = int(match.group(1))
- mi = int(match.group(2))
- assert mi >= 0 and mi < 4
-
- if y == 0:
- assert x != 0
- mg = mw + x - 1
- assert x - mg + 1 < 0
-
- if mg == 4:
- return 'span4_horz_l_%d' % (mg * 4 + mi - 4)
- else:
- assert fw - x + mg - 4 >= 0
- return 'span4_horz_r_%d' % (mg * 4 + mi)
-
- else:
- assert x == 0
- mg = mw - y
- assert fh - y - mg >= 0
-
- if mg == 4:
- return 'span4_vert_t_%d' % (mg * 4 + mi - 4)
- else:
- assert y + mg - 3 >= 0
- return 'span4_vert_b_%d' % (mg * 4 + mi)
-
- match = re.match(r'span4_right_g(\d+)_(\d+)$', net)
- if match is not None:
- mw = int(match.group(1))
- mi = int(match.group(2))
- assert mi >= 0 and mi < 4
-
- if y == fh + 1:
- mg = mw - fh - fw + x - 1
- assert x - mg - 1 >= 0
- assert x - mg + 1 >= fw
- return 'span4_horz_r_%d' % (mg * 4 + mi)
-
- assert x == fw + 1
- mg = mw - y
-
- if mg == 4:
- assert y + mg - 1 < fh + 2
- return 'span4_vert_t_%d' % (mg * 4 + mi - 4)
- else:
- assert y + mg - 5 >= 0
- assert y + mg < fh + 3
- return 'span4_vert_b_%d' % (mg * 4 + mi)
-
- match = re.match(r'span4_top_g(\d+)_(\d+)$', net)
- if match is not None:
- mw = int(match.group(1))
- mi = int(match.group(2))
- assert mi >= 0 and mi < 4
-
- if x == fw + 1:
- assert y != 0
- mg = fw + fh + 5 - y - mw
- assert y + mg >= fh + 3
-
- if mg == 4:
- return 'span4_vert_t_%d' % (mg * 4 + mi - 4)
- else:
- assert y + mg - 5 >= 0
- return 'span4_vert_b_%d' % (mg * 4 + mi)
-
- assert y != 0
- mg = x + 4 - mw
- assert x - mg - 1 >= 0
-
- if mg == 4:
- return 'span4_horz_l_%d' % (mg * 4 + mi - 4)
- else:
- assert x - mg + 1 < fw
- return 'span4_horz_r_%d' % (mg * 4 + mi)
-
- match = re.match(r'span4_bottomright(\d+)_(\d+)$', net)
- if match is not None:
- mw = int(match.group(1))
- mi = int(match.group(2))
- assert mw % 2 == 0
- assert mi >= 0 and mi < 4
-
- if y == 0:
- assert x != 0
- mg = mw // 2 - fw + x - 1
- assert fw - x + mg - 4 < 0
- return 'span4_horz_r_%d' % (mg * 4 + mi)
- else:
- assert x == fw + 1
- mg = mw // 2 - y
- assert y + mg - 5 < 0
- return 'span4_vert_b_%d' % (mg * 4 + mi)
-
- match = re.match(r'span4_topleft(\d+)_(\d+)$', net)
- if match is not None:
- mw = int(match.group(1))
- mi = int(match.group(2))
- assert mw % 2 == 0
- assert mi >= 0 and mi < 4
-
- if x == 0:
- assert y != 0
- mg = fh + 5 - y - mw // 2
- assert fh - y - mg < 0
-
- if mg == 4:
- return 'span4_vert_t_%d' % (mg * 4 + mi - 4)
- else:
- return 'span4_vert_b_%d' % (mg * 4 + mi)
- else:
- assert y == fh + 1
- mg = x + 4 - mw // 2
- assert x - mg - 1 < 0
-
- if mg == 4:
- return 'span4_horz_l_%d' % (mg * 4 + mi - 4)
- else:
- return 'span4_horz_r_%d' % (mg * 4 + mi)
-
- return net
-
-## Check if the name of a destination net is the human-readable form
-## of the \c fabout net of IO tile <tt>(x, y)</tt>.
-#
-# \return \c 'fabout' if it is the \c fabout net, otherwise the
-# unchanged net name
-
-def revert_to_fabout(x, y, net):
- if net.startswith('glb_netwk_'):
- for i, xy in enumerate(GLB_NETWK_INTERNAL_TILES):
- if net == 'glb_netwk_%d' % i and (x, y) == xy:
- return 'fabout'
- raise ParseError
-
- return net
-
-
-EXPR_AND, EXPR_XOR, EXPR_OR, EXPR_TERN, EXPR_NOT, EXPR_ZERO, EXPR_ONE = range(7)
-
-## Evaluate a list representation of a logic expression for given
-## input values.
-#
-# This is a helper function for \ref logic_expression_to_lut.
-#
-# \param expr list representation of a logic expression (see below)
-# \param args list of boolean values representing the input values
-#
-# \result \c False or \c True, depending on the expression and arguments
-#
-# Expression | Result
-# ---------------------------------------+----------------------------------
-# <tt>i</tt> | value of argument \a i
-# <tt>(EXPR_AND, [expr, ...])</tt> | AND operation of all expressions
-# <tt>(EXPR_XOR, [expr, ...])</tt> | XOR operation of all expressions
-# <tt>(EXPR_OR, [expr, ...])</tt> | OR operation of all expressions
-# <tt>(EXPR_TERN, ex_a, ex_b, ex_c)</tt> | result of \c ex_b if \c ex_a
-# | evaluates to \c True, otherwise
-# | result of \c ex_c
-# <tt>(EXPR_NOT, expr)</tt> | negated result of \a expr
-# <tt>(EXPR_ZERO, )</tt> | \c False
-# <tt>(EXPR_ONE, )</tt> | \c True
-
-def evaluate(expr, args):
- if type(expr) == int:
- return args[expr]
-
- op = expr[0]
-
- if op == EXPR_AND:
- assert len(expr) == 2
- for o in expr[1]:
- if not evaluate(o, args):
- return False
- return True
-
- if op == EXPR_XOR:
- assert len(expr) == 2
- result = False
- for o in expr[1]:
- if evaluate(o, args):
- result = not result
- return result
-
- if op == EXPR_OR:
- assert len(expr) == 2
- for o in expr[1]:
- if evaluate(o, args):
- return True
- return False
-
- if op == EXPR_TERN:
- assert len(expr) == 4
- if evaluate(expr[1], args):
- return evaluate(expr[2], args)
- else:
- return evaluate(expr[3], args)
-
- if op == EXPR_NOT:
- assert len(expr) == 2
- return not evaluate(expr[1], args)
-
- if op == EXPR_ZERO:
- assert len(expr) == 1
- return False
-
- if op == EXPR_ONE:
- assert len(expr) == 1
- return True
-
- assert False # unknown operator
-
-## Convert a logic expression to a LUT string.
-#
-# \param lut string containing a human-readable logic expression
-# \param args list of N strings containing the names of the arguments
-#
-# \return a string of 2^N `0' or `1' characters representing the logic
-# of an Nx1 look-up table equivalent to the logic expression
-#
-# Example: logic_expression_to_lut('a & b & !c', ['a', 'b', 'c']) -> '00010000'
-
-def logic_expression_to_lut(s, args):
- # make sure argument names are unique
- assert len(set(args)) == len(args)
-
- stack = [[None, None, None], [[], None, None]]
- stack[0][2] = l = []; stack[1][0].append((EXPR_OR, l))
- stack[0][1] = l = []; stack[0][2].append((EXPR_XOR, l))
- stack[0][0] = l = []; stack[0][1].append((EXPR_AND, l))
- expect_expr = True
- negate_count = 0
-
- i = 0
- while i < len(s):
- if s[i] == ' ':
- pass
- elif s[i] == '!':
- assert expect_expr
- negate_count += 1
- elif s[i] == '&':
- assert not expect_expr
-
- expect_expr = True
- negate_count = 0
- elif s[i] == '^':
- assert not expect_expr
-
- stack[0][0] = l = []; stack[0][1].append((EXPR_AND, l))
-
- expect_expr = True
- negate_count = 0
- elif s[i] == '|':
- assert not expect_expr
-
- stack[0][1] = l = []; stack[0][2].append((EXPR_XOR, l))
- stack[0][0] = l = []; stack[0][1].append((EXPR_AND, l))
-
- expect_expr = True
- negate_count = 0
- elif s[i] == '?':
- assert not expect_expr
- assert stack[1][0][-1][0] == EXPR_OR
- stack[1][0][-1] = (EXPR_TERN, stack[1][0][-1], (EXPR_OR, []),
- (EXPR_OR, []))
- stack[0][2] = l = stack[1][0][-1][2][1]
- stack[0][1] = l = []; stack[0][2].append((EXPR_XOR, l))
- stack[0][0] = l = []; stack[0][1].append((EXPR_AND, l))
-
- expect_expr = True
- negate_count = 0
- elif s[i] == ':':
- assert not expect_expr
- assert stack[1][0][-1][0] == EXPR_TERN
- stack[0][2] = l = stack[1][0][-1][3][1]
- stack[0][1] = l = []; stack[0][2].append((EXPR_XOR, l))
- stack[0][0] = l = []; stack[0][1].append((EXPR_AND, l))
-
- expect_expr = True
- negate_count = 0
- elif s[i] == '(':
- assert expect_expr
-
- stack.insert(0, [None, None, None])
-
- stack[0][2] = l = []
- if negate_count % 2:
- stack[1][0].append((EXPR_NOT, (EXPR_OR, l)))
- else:
- stack[1][0].append((EXPR_OR, l))
-
- stack[0][1] = l = []; stack[0][2].append((EXPR_XOR, l))
- stack[0][0] = l = []; stack[0][1].append((EXPR_AND, l))
-
- expect_expr = True
- negate_count = 0
-
- elif s[i] == ')':
- assert not expect_expr
- stack.pop(0)
-
- elif s[i] == '0':
- assert expect_expr
- if negate_count % 2:
- stack[0][0].append((EXPR_ONE, ))
- else:
- stack[0][0].append((EXPR_ZERO, ))
-
- expect_expr = False
- negate_count = None
-
- elif s[i] == '1':
- assert expect_expr
- if negate_count % 2:
- stack[0][0].append((EXPR_ZERO, ))
- else:
- stack[0][0].append((EXPR_ONE, ))
-
- expect_expr = False
- negate_count = None
-
- else:
- assert expect_expr
-
- found = None
- for j, arg in enumerate(args):
- if s.startswith(arg, i):
- found = j
- i += len(arg)
- break
- assert found is not None
-
- if negate_count % 2:
- stack[0][0].append((EXPR_NOT, found))
- else:
- stack[0][0].append(found)
-
- expect_expr = False
- negate_count = None
- continue
-
- i += 1
-
- assert len(stack) == 2
- return ''.join('1' if evaluate(stack[1][0][0],
- tuple(i & (1 << j) != 0
- for j in range(len(args)))) else '0'
- for i in range(1 << len(args)))
-
-
-class ParseError(Exception):
- pass
-
-def parse_bool(s):
- if s == 'on':
- return True
- if s == 'off':
- return False
- raise ParseError
-
-class Main:
- def __init__(self):
- self.ic = None
- self.device = None
- #self.coldboot = None
- self.warmboot = None
- self.tiles = {}
-
- def read(self, fields):
- if fields[0] == 'device' and len(fields) == 4 \
- and len(fields[1]) >= 2 and fields[1][0] == '"' \
- and fields[1][-1] == '"' \
- and self.ic is None and self.device is None:
- self.device = fields[1][1:-1]
- if self.device == '1k':
- self.ic = icebox.iceconfig()
- self.ic.setup_empty_1k()
- elif self.device == '8k':
- self.ic = icebox.iceconfig()
- self.ic.setup_empty_8k()
- elif self.device == '384':
- self.ic = icebox.iceconfig()
- self.ic.setup_empty_384()
- else:
- raise ParseError
- #elif fields[0] == 'coldboot' and fields[1] == '=' \
- # and self.coldboot is None:
- # # parsed but ignored (can't be represented in IceStorm .asc format)
- # self.coldboot = parse_bool(fields[2])
- elif fields[0] == 'warmboot' and fields[1] == '=' \
- and self.warmboot is None:
- # parsed but ignored (can't be represented in IceStorm .asc format)
- self.warmboot = parse_bool(fields[2])
- else:
- raise ParseError
-
- def new_block(self, fields):
- if len(fields) != 3:
- raise ParseError
- x = int(fields[1])
- y = int(fields[2])
- if (x, y) in self.tiles:
- return self.tiles[x, y]
- if fields[0] == 'logic_tile':
- if (x, y) not in self.ic.logic_tiles:
- raise ParseError
- tile = LogicTile(self.ic, x, y)
- elif fields[0] == 'ramb_tile':
- if (x, y) not in self.ic.ramb_tiles:
- raise ParseError
- tile = RAMBTile(self.ic, x, y)
- elif fields[0] == 'ramt_tile':
- if (x, y) not in self.ic.ramt_tiles:
- raise ParseError
- tile = RAMTTile(self.ic, x, y)
- elif fields[0] == 'io_tile':
- if (x, y) not in self.ic.io_tiles:
- raise ParseError
- tile = IOTile(self.ic, x, y)
- else:
- raise ParseError
- self.tiles[x, y] = tile
- return tile
-
- def writeout(self):
- if self.ic is None:
- raise ParseError
-
- # fix up IE/REN bits
- unused_ieren = set()
-
- for x in range(1, self.ic.max_x):
- unused_ieren.add((x, 0, 0))
- unused_ieren.add((x, 0, 1))
- unused_ieren.add((x, self.ic.max_y, 0))
- unused_ieren.add((x, self.ic.max_y, 1))
-
- for y in range(1, self.ic.max_y):
- unused_ieren.add((0, y, 0))
- unused_ieren.add((0, y, 1))
- unused_ieren.add((self.ic.max_x, y, 0))
- unused_ieren.add((self.ic.max_x, y, 1))
-
- for x0, y0, b0, x1, y1, b1 in self.ic.ieren_db():
- if (x0, y0) in self.tiles:
- io_tile = self.tiles[x0, y0]
- else:
- io_tile = IOTile(self.ic, x0, y0)
- self.tiles[x0, y0] = io_tile
- if io_tile.blocks[b0] is not None:
- io_block = io_tile.blocks[b0]
- else:
- io_block = IOBlock(io_tile, b0)
- io_tile.blocks[b0] = io_block
-
- if (x1, y1) in self.tiles:
- ieren_tile = self.tiles[x1, y1]
- else:
- ieren_tile = IOTile(self.ic, x1, y1)
- self.tiles[x1, y1] = ieren_tile
-
- if io_block.enable_input != (self.ic.device == '1k'):
- ieren_tile.apply_directive('IoCtrl', 'IE_%d' % b1)
- if io_block.disable_pull_up:
- ieren_tile.apply_directive('IoCtrl', 'REN_%d' % b1)
-
- unused_ieren.remove((x1, y1, b1))
-
- if self.ic.device == '1k':
- for x1, y1, b1 in unused_ieren:
- if (x1, y1) in self.tiles:
- ieren_tile = self.tiles[x1, y1]
- else:
- ieren_tile = IOTile(self.ic, x1, y1)
- self.tiles[x1, y1] = ieren_tile
- ieren_tile.apply_directive('IoCtrl', 'IE_%d' % b1)
-
- # fix up RAMB power-up bits
-
- for x, y in self.ic.ramb_tiles:
- if (x, y) in self.tiles:
- tile = self.tiles[x, y]
- else:
- tile = RAMBTile(self.ic, x, y)
- self.tiles[x, y] = tile
-
- if tile.power_up != (self.ic.device == '1k'):
- tile.apply_directive('RamConfig', 'PowerUp')
-
- # enable column buffers
- colbuf_db = self.ic.colbuf_db()
- for x, y in list(self.tiles):
- for src, dst in self.tiles[x, y].buffers + \
- self.tiles[x, y].routings:
- if not src.startswith('glb_netwk_'):
- continue
- driving_xy = [(src_x, src_y)
- for src_x, src_y, dst_x, dst_y in colbuf_db
- if dst_x == x and dst_y == y]
- assert len(driving_xy) == 1
- driving_xy, = driving_xy
-
- if driving_xy not in self.tiles:
- if driving_xy in self.ic.logic_tiles:
- tile = LogicTile(self.ic, *driving_xy)
- elif driving_xy in self.ic.ramb_tiles:
- tile = RAMBTile(self.ic, *driving_xy)
- elif driving_xy in self.ic.ramt_tiles:
- tile = RAMTTile(self.ic, *driving_xy)
- elif driving_xy in self.ic.io_tiles:
- tile = IOTile(self.ic, *driving_xy)
- else:
- assert False
- self.tiles[driving_xy] = tile
-
- self.tiles[driving_xy].apply_directive('ColBufCtrl', src)
-
- self.ic.write_file('/dev/stdout')
-
-class Tile:
- def __init__(self, ic, x, y):
- self.ic = ic
- self.x = x
- self.y = y
- self.data = ic.tile(x, y)
- self.db = ic.tile_db(x, y)
-
- self.buffers = []
- self.routings = []
- self.bits_set = set()
- self.bits_cleared = set()
-
- def apply_directive(self, *fields):
- fields = list(fields)
- bits, = [entry[0] for entry in self.db if entry[1:] == fields]
- self.set_bits(bits)
-
- def set_bits(self, bits):
- bits_set = set()
- bits_clear = set()
-
- for bit in bits:
- match = re.match(r'(!?)B(\d+)\[(\d+)\]$', bit)
- if not match:
- raise ValueError("invalid bit description: %s" % bit)
- if match.group(1):
- bits_clear.add((int(match.group(2)), int(match.group(3))))
- else:
- bits_set.add((int(match.group(2)), int(match.group(3))))
-
- if set.intersection(bits_set, bits_clear):
- raise ValueError("trying to set/clear the same bit(s) at once")
-
- if set.intersection(bits_set, self.bits_cleared) or \
- set.intersection(bits_clear, self.bits_set):
- raise ParseError("conflicting bits")
-
- self.bits_set.update(bits_set)
- self.bits_cleared.update(bits_clear)
-
- for row, col in bits_set:
- assert row < len(self.data)
- assert col < len(self.data[row])
- self.data[row] = self.data[row][:col] + '1' + \
- self.data[row][col + 1:]
-
- def read(self, fields):
- if len(fields) == 3 and fields[1] == '->':
- src = untranslate_netname(self.x, self.y,
- self.ic.max_x - 1,
- self.ic.max_y - 1, fields[0])
- dst = untranslate_netname(self.x, self.y,
- self.ic.max_x - 1,
- self.ic.max_y - 1, fields[2])
- dst = revert_to_fabout(self.x, self.y, dst)
- if (src, dst) not in self.buffers:
- self.buffers.append((src, dst))
- self.apply_directive('buffer', src, dst)
- elif len(fields) == 3 and fields[1] == '<->':
- src = untranslate_netname(self.x, self.y,
- self.ic.max_x - 1,
- self.ic.max_y - 1, fields[0])
- dst = untranslate_netname(self.x, self.y,
- self.ic.max_x - 1,
- self.ic.max_y - 1, fields[2])
- dst = revert_to_fabout(self.x, self.y, dst)
- if (src, dst) not in self.routings:
- self.routings.append((src, dst))
- self.apply_directive('routing', src, dst)
- elif len(fields) >= 5 and (fields[1] == '->' or fields[1] == '<->'):
- self.read(fields[:3])
- self.read(fields[2:])
- else:
- raise ParseError
-
- def new_block(self, fields):
- raise ParseError
-
-class LogicTile(Tile):
- def __init__(self, ic, x, y):
- super().__init__(ic, x, y)
- self.cells = [None, None, None, None, None, None, None, None]
- self.neg_clk = False
- self.carry_in_set = False # not in global bit list?!
-
- def read(self, fields):
- if fields == ['NegClk'] and not self.neg_clk:
- self.neg_clk = True
- self.apply_directive('NegClk')
- elif fields == ['CarryInSet'] and not self.carry_in_set:
- self.carry_in_set = True
- self.apply_directive('CarryInSet')
- else:
- super().read(fields)
-
- def new_block(self, fields):
- for i in range(8):
- if fields == ['lutff_%d' % i] and self.cells[i] is None:
- self.cells[i] = LogicCell(self, i)
- return self.cells[i]
- raise ParseError
-
-class LogicCell:
- def __init__(self, tile, index):
- self.tile = tile
- self.index = index
- self.lut_bits = None
- self.seq_bits = ['0'] * 4
-
- def read(self, fields):
- if fields[0] == 'lut' and len(fields) == 2 and self.lut_bits is None:
- self.lut_bits = fields[1]
- elif fields[0] == 'out' and len(fields) >= 3 and fields[1] == '=':
- self.lut_bits = logic_expression_to_lut(
- ' '.join(fields[2:]), ('in_0', 'in_1', 'in_2', 'in_3'))
- elif fields == ['enable_carry']:
- self.seq_bits[0] = '1'
- elif fields == ['enable_dff']:
- self.seq_bits[1] = '1'
- elif fields == ['set_noreset']:
- self.seq_bits[2] = '1'
- elif fields == ['async_setreset']:
- self.seq_bits[3] = '1'
- elif len(fields) >= 3 and (fields[1] == '->' or fields[1] == '<->'):
- prefix = 'lutff_%d/' % self.index
- if fields[0] == 'out':
- self.tile.read([prefix + fields[0]] + fields[1:])
- elif fields[-1].startswith('in_'):
- self.tile.read(fields[:-1] + [prefix + fields[-1]])
- else:
- raise ParseError
- return
-
- bits = ''.join([
- self.lut_bits[15], self.lut_bits[12],
- self.lut_bits[11], self.lut_bits[ 8],
- self.lut_bits[ 0], self.lut_bits[ 3],
- self.lut_bits[ 4], self.lut_bits[ 7],
- self.seq_bits[ 0], self.seq_bits[ 1],
- self.lut_bits[14], self.lut_bits[13],
- self.lut_bits[10], self.lut_bits[ 9],
- self.lut_bits[ 1], self.lut_bits[ 2],
- self.lut_bits[ 5], self.lut_bits[ 6],
- self.seq_bits[ 2], self.seq_bits[ 3]
- ])
- self.tile.data[self.index * 2] = \
- self.tile.data[self.index * 2][:36] + bits[:10] + \
- self.tile.data[self.index * 2][46:]
- self.tile.data[self.index * 2 + 1] = \
- self.tile.data[self.index * 2 + 1][:36] + bits[10:] + \
- self.tile.data[self.index * 2 + 1][46:]
-
- def new_block(self, fields):
- raise ParseError
-
-class RAMData:
- def __init__(self, data):
- self.data = data
-
- def read(self, fields):
- if len(fields) == 1:
- self.data.append(fields[0])
- else:
- raise ParseError
-
- def new_block(self, fields):
- raise ParseError
-
-class RAMBTile(Tile):
- def __init__(self, ic, x, y):
- super().__init__(ic, x, y)
- self.power_up = False
-
- def read(self, fields):
- if fields == ['power_up'] and not self.power_up:
- self.power_up = True
- else:
- super().read(fields)
-
- def new_block(self, fields):
- if fields == ['data'] and (self.x, self.y) not in self.ic.ram_data:
- self.ic.ram_data[self.x, self.y] = data = []
- return RAMData(data)
- raise ParseError
-
-class RAMTTile(Tile):
- def __init__(self, ic, x, y):
- super().__init__(ic, x, y)
-
- def read(self, fields):
- if fields == ['NegClk'] or fields[0] == 'RamConfig':
- self.apply_directive(*fields) # TODO
- else:
- super().read(fields)
-
-class IOTile(Tile):
- def __init__(self, ic, x, y):
- super().__init__(ic, x, y)
- self.blocks = [None, None]
-
- def read(self, fields):
- super().read(fields)
-
- def new_block(self, fields):
- if fields == ['io_0'] and self.blocks[0] is None:
- self.blocks[0] = IOBlock(self, 0)
- return self.blocks[0]
- if fields == ['io_1'] and self.blocks[1] is None:
- self.blocks[1] = IOBlock(self, 1)
- return self.blocks[1]
- raise ParseError
-
-class IOBlock:
- def __init__(self, tile, index):
- self.tile = tile
- self.index = index
- self.input_pin_type = None
- self.output_pin_type = None
- self.enable_input = False
- self.disable_pull_up = False
-
- def read(self, fields):
- if fields[0] == 'input_pin_type' and fields[1] == '=' \
- and len(fields) == 3 and self.input_pin_type is None:
- self.input_pin_type = [
- 'registered_pin',
- 'simple_input_pin',
- 'latched_registered_pin',
- 'latched_pin'].index(fields[2])
- for i in range(2):
- if self.input_pin_type & 1 << i:
- self.tile.apply_directive('IOB_%d' % self.index,
- 'PINTYPE_%d' % i)
- elif fields[0] == 'output_pin_type' and fields[1] == '=' \
- and len(fields) == 3 and self.output_pin_type is None:
- self.output_pin_type = [
- 'no_output',
- '1',
- '2',
- '3',
- 'DDR',
- 'REGISTERED',
- 'simple_output_pin',
- 'REGISTERED_INVERTED',
- 'DDR_ENABLE',
- 'REGISTERED_ENABLE',
- 'OUTPUT_TRISTATE',
- 'REGISTERED_ENABLE_INVERTED',
- 'DDR_ENABLE_REGISTERED',
- 'REGISTERED_ENABLE_REGISTERED',
- 'ENABLE_REGISTERED',
- 'REGISTERED_ENABLE_REGISTERED_INVERTED'].index(fields[2])
- for i in range(4):
- if self.output_pin_type & 1 << i:
- self.tile.apply_directive('IOB_%d' % self.index,
- 'PINTYPE_%d' % (i + 2))
- elif fields == ['enable_input'] and not self.enable_input:
- self.enable_input = True
- elif fields == ['disable_pull_up'] and not self.disable_pull_up:
- self.disable_pull_up = True
- elif fields[0] == 'GLOBAL_BUFFER_OUTPUT' and fields[1] == '->' \
- and fields[2].startswith('glb_netwk_'):
- if GLB_NETWK_EXTERNAL_BLOCKS[int(fields[2][10:])] \
- != (self.tile.x, self.tile.y, self.index):
- raise ParseError
- bit = [bit for bit in self.tile.ic.extra_bits_db()
- if self.tile.ic.extra_bits_db()[bit]
- == ("padin_glb_netwk", fields[2][10:])]
- assert len(bit) == 1
- self.tile.ic.extra_bits.add(bit[0])
- elif len(fields) >= 3 and (fields[1] == '->' or fields[1] == '<->'):
- prefix = 'io_%d/' % self.index
- if fields[0] in ('D_IN_0', 'D_IN_1'):
- self.tile.read([prefix + fields[0]] + fields[1:])
- elif fields[-1] in ('CLOCK_ENABLE',
- 'D_OUT_0',
- 'D_OUT_1',
- 'INPUT_CLK',
- 'LATCH_INPUT_VALUE',
- 'OUTPUT_CLK',
- 'OUTPUT_ENABLE'):
- self.tile.read(fields[:-1] + [prefix + fields[-1]])
- else:
- raise ParseError
- else:
- raise ParseError
-
- def new_block(self, fields):
- raise ParseError
-
-def main1(path):
- f = open(path, 'r')
- stack = [Main()]
- for line in f:
- fields = line.split('#')[0].split()
- if not fields:
- pass # empty line
- elif fields == ['}']:
- stack.pop()
- if not stack:
- raise ParseError
- elif fields[-1] == '{':
- stack.append(stack[-1].new_block(fields[:-1]))
- else:
- stack[-1].read(fields)
- if len(stack) != 1:
- raise ParseError
- f.close()
-
- stack[0].writeout()
-
-def main():
- program_short_name = os.path.basename(sys.argv[0])
-
- try:
- opts, args = getopt.getopt(sys.argv[1:], '', ['help', 'version'])
- except getopt.GetoptError as e:
- sys.stderr.write("%s: %s\n" % (program_short_name, e.msg))
- sys.stderr.write("Try `%s --help' for more information.\n"
- % sys.argv[0])
- sys.exit(1)
-
- for opt, arg in opts:
- if opt == '--help':
- sys.stderr.write("""\
-Create an ASCII bitstream from a high-level bitstream representation.
-Usage: %s [OPTION]... FILE
-
- --help display this help and exit
- --version output version information and exit
-
-If you have a bug report, please file an issue on github:
- https://github.com/rlutz/icestorm/issues
-""" % sys.argv[0])
- sys.exit(0)
-
- if opt == '--version':
- sys.stderr.write("""\
-icebox_hlc2asc - create an ASCII bitstream from a high-level representation
-Copyright (C) 2017 Roland Lutz
-
-This program is free software: you can redistribute it and/or
-modify it under the terms of the GNU General Public License as
-published by the Free Software Foundation, either version 3 of
-the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-""")
- sys.exit(0)
-
- if not args:
- sys.stderr.write("%s: missing argument\n" % (program_short_name))
- sys.stderr.write("Try `%s --help' for more information.\n"
- % sys.argv[0])
- sys.exit(1)
-
- if len(args) != 1:
- sys.stderr.write("%s: too many arguments\n" % (program_short_name))
- sys.stderr.write("Try `%s --help' for more information.\n"
- % sys.argv[0])
- sys.exit(1)
-
- if args[0] == '-':
- main1('/dev/stdin')
- else:
- main1(args[0])
-
-if __name__ == '__main__':
- main()
diff --git a/icebox/tc_logic_xpr.py b/icebox/tc_logic_xpr.py
deleted file mode 100644
index e557caf..0000000
--- a/icebox/tc_logic_xpr.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Test case for `icebox_asc2hlc' and `icebox_hlc2asc': Does conversion
-# from LUT strings to logic expressions and back work correctly?
-# Copyright (C) 2017 Roland Lutz
-#
-# This program is free software: you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-import sys
-import icebox
-from icebox_asc2hlc import lut_to_logic_expression
-from icebox_hlc2asc import logic_expression_to_lut
-
-def main():
- sys.stderr.write("testing conversion from LUT strings "
- "to logic expressions and back")
-
- for i in range(65536):
- if i % 4096 == 0:
- sys.stderr.write(".")
- sys.stderr.flush()
-
- lut = bin(i)[2:].zfill(16)
- s = lut_to_logic_expression(lut, ('a', 'b', 'c', 'd'))
- l = logic_expression_to_lut(s, ('a', 'b', 'c', 'd'))
-
- if l != lut:
- sys.stderr.write("\nERROR at LUT = %s\n" % lut)
- sys.stderr.write("stringified = %s\n" % s)
- sys.stderr.write("resulting LUT = %s\n" % l)
- sys.exit(1)
-
- sys.stderr.write("\n")
-
-if __name__ == '__main__':
- main()
diff --git a/icebox/tc_rxlat_netnames.py b/icebox/tc_rxlat_netnames.py
deleted file mode 100644
index 109dfa4..0000000
--- a/icebox/tc_rxlat_netnames.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Test case for `icebox_hlc2asc': Does net name translation work correctly?
-# Copyright (C) 2017 Roland Lutz
-#
-# This program is free software: you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-import sys
-import icebox
-from icebox_asc2hlc import translate_netname
-from icebox_hlc2asc import untranslate_netname
-
-def test_netname_translation(ic):
- sys.stderr.write("testing backward netname translation "
- "for the `%s' device...\n" % ic.device)
- all_tiles = set()
- for x in range(ic.max_x + 1):
- for y in range(ic.max_y + 1):
- if ic.tile(x, y) is not None:
- all_tiles.add((x, y))
-
- netnames = set()
- failed = False
-
- for group in ic.group_segments(all_tiles, connect_gb = False):
- is_span = set(net.startswith('sp') for x, y, net in group)
- assert len(is_span) == 1
- if True not in is_span:
- # only span nets are interesting here
- continue
-
- netname = translate_netname(group[0][0], group[0][1],
- ic.max_x - 1, ic.max_y - 1, group[0][2])
- if netname in netnames:
- failed = True
- print("duplicate netname: %s" % netname)
- netnames.add(netname)
-
- for x, y, net in group:
- s = untranslate_netname(x, y, ic.max_x - 1, ic.max_y - 1, netname)
- if s != net:
- failed = True
- print("%-20s %s -> %s" % ("%d %d %s" % (x, y, net), netname, s))
-
- if failed:
- sys.stderr.write("ERROR\n")
- sys.exit(1)
-
-def main():
- ic = icebox.iceconfig()
- ic.setup_empty_384()
- test_netname_translation(ic)
-
- ic = icebox.iceconfig()
- ic.setup_empty_1k()
- test_netname_translation(ic)
-
- ic = icebox.iceconfig()
- ic.setup_empty_8k()
- test_netname_translation(ic)
-
-if __name__ == '__main__':
- main()
diff --git a/icebox/tc_xlat_netnames.py b/icebox/tc_xlat_netnames.py
deleted file mode 100644
index 53b73de..0000000
--- a/icebox/tc_xlat_netnames.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Test case for `icebox_asc2hlc': Does net name translation work correctly?
-# Copyright (C) 2017 Roland Lutz
-#
-# This program is free software: you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation, either version 3 of
-# the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-import sys
-import icebox
-from icebox_asc2hlc import translate_netname
-
-def test_netname_translation(ic):
- sys.stderr.write("testing forward netname translation "
- "for the `%s' device...\n" % ic.device)
- all_tiles = set()
- for x in range(ic.max_x + 1):
- for y in range(ic.max_y + 1):
- if ic.tile(x, y) is not None:
- all_tiles.add((x, y))
-
- netnames = set()
- failed = False
-
- for group in ic.group_segments(all_tiles, connect_gb = False):
- is_span = set(net.startswith('sp') for x, y, net in group)
- assert len(is_span) == 1
- if True not in is_span:
- # only span nets are interesting here
- continue
-
- s = set()
- for seg in group:
- s.add(translate_netname(seg[0], seg[1],
- ic.max_x - 1, ic.max_y - 1, seg[2]))
- if len(s) != 1:
- failed = True
- print("translated netnames don't match")
- for seg in group:
- print("%d %d %s" % seg, "->",
- translate_netname(seg[0], seg[1],
- ic.max_x - 1, ic.max_y - 1, seg[2]))
- print()
-
- for dulpicate_netname in netnames.intersection(s):
- failed = True
- print("duplicate netname: %s" % dulpicate_netname)
- for seg in group:
- print("%d %d %s" % seg, "->",
- translate_netname(seg[0], seg[1],
- ic.max_x - 1, ic.max_y - 1, seg[2]))
- print()
-
- netnames.update(s)
-
- if failed:
- sys.stderr.write("ERROR\n")
- sys.exit(1)
-
-def main():
- ic = icebox.iceconfig()
- ic.setup_empty_384()
- test_netname_translation(ic)
-
- ic = icebox.iceconfig()
- ic.setup_empty_1k()
- test_netname_translation(ic)
-
- ic = icebox.iceconfig()
- ic.setup_empty_8k()
- test_netname_translation(ic)
-
-if __name__ == '__main__':
- main()
diff --git a/iceprog/Makefile b/iceprog/Makefile
index d71a9b7..8739ba6 100644
--- a/iceprog/Makefile
+++ b/iceprog/Makefile
@@ -24,12 +24,9 @@ iceprog$(EXE): iceprog.o
install: all
mkdir -p $(DESTDIR)$(PREFIX)/bin
cp iceprog$(EXE) $(DESTDIR)$(PREFIX)/bin/iceprog$(EXE)
- mkdir -p $(DESTDIR)$(PREFIX)/share/man/man1
- install -c -m 644 iceprog.1 $(DESTDIR)$(PREFIX)/share/man/man1
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/iceprog$(EXE)
- rm -f $(DESTDIR)$(PREFIX)/share/man/man1/iceprog.1
clean:
rm -f iceprog
diff --git a/iceprog/iceprog.1 b/iceprog/iceprog.1
deleted file mode 100644
index 22d3882..0000000
--- a/iceprog/iceprog.1
+++ /dev/null
@@ -1,155 +0,0 @@
-.\" Manpage for iceprog(1)
-.\" Copyright (C) 2017 Roland Lutz
-.\"
-.\" Permission is granted to copy, distribute and/or modify this document
-.\" under the terms of the GNU Free Documentation License, Version 1.3 or
-.\" any later version published by the Free Software Foundation; with no
-.\" Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
-.\"
-.TH ICEPROG "1" "June 2017" "IceStorm" "User Commands"
-.SH NAME
-iceprog \- simple programming tool for FTDI\-based Lattice iCE programmers
-.SH SYNOPSIS
-.B iceprog
-[\-b|\-n|\-c] \fIINPUT\-FILE\fR
-
-.B iceprog
-\-r|\-R\fI\,BYTES\fR \fIOUTPUT\-FILE\fR
-
-.B iceprog
-\-S \fIINPUT\-FILE\fR
-
-.B iceprog
-\-t
-.SH DESCRIPTION
-The \fBiceprog\fR program is a simple programming tool for FTDI\-based
-Lattice iCE programmers which can read, write and erase the flash and
-write the SRAM of an FPGA. It is typically invoked after the
-bitstream has been converted by \fBicepack\fR to the iCE40 \fB.bin\fR
-format as the last step of the build process to transfer the bitstream
-to the FPGA.
-.SS Operation mode
-When no special option is given, \fBiceprog\fR erases all 64kB sectors
-which would be touched by the written data, writes the data to the
-flash, and then reads it back and verifies it.
-
-\fIPlease note:\fR If the data is not aligned to 64kB, some data
-before (if \fB\-o\fR is used) and after the written data may be erased
-as well.
-
-The way the flash is erased can be changed with the following options:
-.TP
-\fB\-b\fR
-Bulk erase the entire flash before writing. When using this option,
-\fBiceprog\fR can be invoked without an \fIINPUT\-FILE\fR; in this
-case, the flash is just bulk erased, and nothing is written.
-.TP
-\fB\-n\fR
-Don't erase the flash before writing.
-.PP
-Instead of the default erase/write/verify, \fBiceprog\fR can perform
-some other operations:
-.TP
-\fB\-c\fR
-Just read the data which would have been written from the flash and
-verify it (`check').
-.TP
-\fB\-r\fR
-Read the first 256 kB from flash and write them to a file.
-.TP
-\fB\-R\fR \fISIZE\-IN\-BYTES\fR
-Read the specified number of bytes from the flash and write them to a
-file. You can append `\fBk\fR' to the size to specify it in kilobytes
-and `\fBM\fR' to specify it in megabytes.
-.TP
-\fB\-S\fR
-Perform SRAM programming.
-.TP
-\fB\-t\fR
-Just read the flash ID sequence.
-.PP
-All of the above options are mutually exclusive.
-.SS General options
-.TP
-\fB\-d\fR \fIDEVICE\-STRING\fR
-Use the specified USB device instead of the default one (which is
-vendor ID 0x0403 and device ID 0x6010). The supported notations for
-\fIDEVICE\-STRING\fR are:
-
-\fBd:\,\f(BIdevicenode\fR \- path of the bus and device node within
-USB device tree (usually at /proc/bus/usb/); e.g., `d:002/005'
-
-\fBi:\,\f(BIvendor\/\fB:\,\f(BIproduct\fR \- first device with given
-vendor and product ID. IDs can be decimal, octal (preceded by
-`\fB0\fR'), or hex (preceded by `\fB0x\fR'); e.g., `i:0x0403:0x6010'
-
-\fBi:\,\f(BIvendor\/\fB:\,\f(BIproduct\/\fB:\,\f(BIindex\fR \- same as
-above, with index being the number of the device (starting with 0) if
-there is more than one device with this vendor and product ID; e.g.,
-`i:0x0403:0x6010:0'
-
-\fBs:\,\f(BIvendor\/\fB:\,\f(BIproduct\/\fB:\,\f(BIserial\-string\fR
-\- first device with given vendor ID, product ID and serial string.
-.TP
-\fB\-I\fR A|B|C|D
-Connect to the specified interface on the FTDI chip. If this option
-is omitted, interface A is used.
-.TP
-\fB\-o\fR \fIOFFSET\-IN\-BYTES\fR
-Start reading/writing at address \fIOFFSET\-IN\-BYTES\fR instead of the
-beginning of the memory. You can append `\fBk\fR' to the offset to
-specify it in kilobytes and `\fBM\fR' to specify it in megabytes.
-.TP
-\fB\-v\fR
-Write more verbose messages.
-.TP
-\fB\-\-help\fR
-Display a help text and exit.
-.SS Exit status
-.TP
-.B 0
-on success,
-.TP
-.B 1
-if a non\-hardware error occurred (e.g., failure to read from or write
-to a file, or invoked with invalid options),
-.TP
-.B 2
-if communication with the hardware failed (e.g., cannot find the iCE
-FTDI USB device),
-.TP
-.B 3
-if verification of the data failed.
-.SS Notes for iCEstick (iCE40HX\-1k devel board)
-An unmodified iCEstick can only be programmed via the serial flash.
-Direct programming of the SRAM is not supported. For direct SRAM
-programming the flash chip and one zero ohm resistor must be
-desoldered and the FT2232H SI pin must be connected to the iCE SPI_SI
-pin, as shown in this picture:
-<http://www.clifford.at/gallery/2014-elektronik/IMG_20141115_183838>
-.SS Notes for the iCE40\-HX8K Breakout Board
-Make sure that the jumper settings on the board match the selected
-mode (SRAM or FLASH). See the iCE40\-HX8K user manual for details.
-.SH AUTHOR
-Written by Clifford Wolf.
-.SH REPORTING BUGS
-If you have a bug report, please file an issue on github:
-<https://github.com/cliffordwolf/icestorm/issues>
-.SH COPYRIGHT
-Most of Project IceStorm is licensed under the ISC license:
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.SH SEE ALSO
-Full documentation at: <http://hedmen.org/icestorm-doc/>
-.br
-or available locally via: info \(aq(icestorm) iceprog invocation\(aq