aboutsummaryrefslogtreecommitdiffstats
path: root/icebox/icebox_hlc2asc.py
diff options
context:
space:
mode:
Diffstat (limited to 'icebox/icebox_hlc2asc.py')
-rwxr-xr-xicebox/icebox_hlc2asc.py1052
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()