diff options
Diffstat (limited to 'icebox/icebox_hlc2asc.py')
-rwxr-xr-x | icebox/icebox_hlc2asc.py | 1052 |
1 files changed, 0 insertions, 1052 deletions
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() |