From 8ed21b1662e67e9b9813406a0409f1cf993544bd Mon Sep 17 00:00:00 2001 From: Cassie Jones Date: Fri, 3 May 2019 13:22:57 -0700 Subject: [PATCH] Change genlib to generate or/nor clauses --- genlib.py | 163 ++++++++++++++++++++++++++++-------------------------- makefile | 2 +- 2 files changed, 85 insertions(+), 80 deletions(-) diff --git a/genlib.py b/genlib.py index 6531516..78ef067 100644 --- a/genlib.py +++ b/genlib.py @@ -1,43 +1,72 @@ """ -Generate a cell library for redstone circuits +Generate a cell library for redstone circuits. """ import sys +import argparse +from dataclasses import dataclass +from typing import List, Dict -CELLS = [ - (6, {'Y': 'A'}), - (6, {'Y': '!A'}), - (12, {'Y': 'A & B'}), - (12, {'Y': '!(A & B)'}), - (12, {'Y': 'A | B'}), - (12, {'Y': '!(A | B)'}), - (18, {'Y': 'A & B & C'}), - (18, {'Y': '!(A & B & C)'}), - (18, {'Y': 'A | B | C'}), - (18, {'Y': '!(A | B | C)'}), - (18, {'Y': '(A & B) | C'}), - (18, {'Y': '(A & B) | !C'}), - (18, {'Y': '!(A & B) | C'}), - (18, {'Y': '!(A & B) | !C'}), - (18, {'Y': '(A | B) & C'}), - (18, {'Y': '!((A | B) & C)'}), - (24, {'Y': 'A & B & C & D'}), - (24, {'Y': '!(A & B & C & D)'}), - (24, {'Y': 'A | B | C | D'}), - (24, {'Y': '!(A | B | C | D)'}), - (24, {'Y': '(A | B) & (C | D)'}), - (24, {'Y': '!((A | B) & (C | D))'}), - (24, {'Y': '(A & B) | (C & D)'}), - (24, {'Y': '(A & B) | !(C & D)'}), - (24, {'Y': '!(A & B) | !(C & D)'}), - (24, {'Y': '!((A & B) | !(C & D))'}), - (24, {'Y': '!(!(A & B) | (C & D))'}), - (24, {'Y': '!(!(A & B) | !(C & D))'}), - (24, {'Y': '(A | B) & C & D'}), - (24, {'Y': '!((A | B) & C & D)'}), - (24, {'Y': '(A | B) & (C | D)'}), - (24, {'Y': '!((A | B) & (C | D))'}), - """ +@dataclass +class Cell: + name: str + area: int + inputs: List[str] + outputs: Dict[str, str] + + def lib(self, tab_size=2, indent=0) -> str: + tab = ' ' * tab_size + pad = tab * indent + pad2 = pad + tab + return '\n'.join([ + f"{pad}cell({self.name}) {{", + f"{pad2}area: {self.area};", + *(f"{pad2}pin({name}) {{ direction: input; }}" + for name in self.inputs), + *(f"{pad2}pin({name}) {{ direction: output; function: \"{func}\"; }}" + for name, func in self.outputs.items()), + f"{pad}}}", + ]) + +@dataclass +class TextCell: + text: str + + def lib(self, tab_size=2, indent=0) -> str: + if indent == 0: + return self.text + padding = ' ' * (tab_size * indent) + return padding + self.text.replace('\n', '\n' + padding) + +def print_lib(lib_name, cells): + print(f"library({lib_name}) {{") + for cell in cells: + print(cell.lib(tab_size=2, indent=1)) + print("}") + +def gen_cells(max_pins: int, or_nor: bool): + yield Cell("BUF", 1, ["A"], {"Y": "A"}) + yield Cell("NOT", 4, ["A"], {"Y": "!A"}) + # @TODO: Generate inputs more nicely + all_inputs = "ABCDEFGHIJKLMNOPQRSTUV" + for pins in range(2, max_pins+1): + inputs = all_inputs[:pins] + area = pins * 5 - 2 + for neg in range(pins+1): + func = ' | '.join( + ["!" + inputs[i] for i in range(neg)] + + [inputs[i] for i in range(neg, pins)], + ) + pin_name = f"{pins - neg}N{neg}" + yield Cell(f"OR_{pin_name}", area + 1, inputs, {"Y": func}) + yield Cell(f"NOR_{pin_name}", area + 2, inputs, {"Y": f"!({func})"}) + if or_nor: + yield Cell( + f"OR_NOR_{pin_name}", area + 3, inputs, + {"Y": func, "Z": f"!({func})"}, + ) + +DFF_P = TextCell(""" cell(DFF_P) { area: 8; ff(IQ, IQN) { clocked_on: C; next_state: D; } @@ -45,8 +74,9 @@ cell(DFF_P) { pin(D) { direction: input; } pin(Q) { direction: output; function: "IQ"; } } - """, - """ +""".strip()) + +DFF_N = TextCell(""" cell(DFF_N) { area: 8; ff(IQ, IQN) { clocked_on: "!C"; next_state: D; } @@ -54,47 +84,22 @@ cell(DFF_N) { pin(D) { direction: input; } pin(Q) { direction: output; function: "IQ"; } } - """, -] - -def find_inputs(eqs): - inputs = set() - for eq in eqs.values(): - inputs.update( - eq.replace('(', ' ').replace(')', ' ') - .replace('&', ' ').replace('|', ' ') - .replace('+', ' ').replace('*', ' ') - .replace('!', ' ').split() - ) - return inputs +""".strip()) -def make_name(eqs): - return ','.join( - f"{x}={f.replace(' ', '').replace('|', '+')}" - for x, f in eqs.items() +if __name__ == '__main__': + parser = argparse.ArgumentParser( + description="Generate a liberty file for Minecraft standard cells.", ) - -def print_lib(lib, defns): - print(f"library({lib}) {{") - defined = {} - for i, defn in enumerate(defns): - if isinstance(defn, str): - print(' ' + defn.strip().replace('\n', '\n ')) - else: - area, eqs = defn - name = make_name(eqs) - if name in defined: - print(f"Warning: {name} defined at both {defined[name]} and {i}, skipping...", file=sys.stderr) - continue - defined[name] = i - inputs = find_inputs(eqs) - print(f""" cell("{name}") {{""") - print(f""" area: {area};""") - for pin in sorted(inputs): - print(f" pin({pin}) {{ direction: input; }}") - for x, f in eqs.items(): - print(f""" pin({x}) {{ direction: output; function: "{f}"; }}""") - print(" }") - print("}") - -print_lib("redstone", CELLS) + parser.add_argument( + '-n', '--max-pins', metavar='N', type=int, choices=range(2, 17), default=5, + help="the maximum number of input pins on a single cell", + ) + parser.add_argument( + '-o', '--or-nor', action='store_true', + help="generate two output combined or/nor gates", + ) + args = parser.parse_args() + cells = list(gen_cells(args.max_pins, args.or_nor)) + cells.append(DFF_P) + cells.append(DFF_N) + print_lib("redstone", cells) diff --git a/makefile b/makefile index cc3b15a..8872f4a 100644 --- a/makefile +++ b/makefile @@ -2,4 +2,4 @@ synth: example/counter.ys minecraft.lib example/counter.sv yosys $< minecraft.lib: genlib.py - python3 $< > $@ + python3 $< -n 5 -o > $@ -- 2.47.0