]> Witch of Git - minecraft-eda/blob - genlib.py
Change genlib to generate or/nor clauses
[minecraft-eda] / genlib.py
1 """
2 Generate a cell library for redstone circuits.
3 """
4
5 import sys
6 import argparse
7 from dataclasses import dataclass
8 from typing import List, Dict
9
10 @dataclass
11 class Cell:
12 name: str
13 area: int
14 inputs: List[str]
15 outputs: Dict[str, str]
16
17 def lib(self, tab_size=2, indent=0) -> str:
18 tab = ' ' * tab_size
19 pad = tab * indent
20 pad2 = pad + tab
21 return '\n'.join([
22 f"{pad}cell({self.name}) {{",
23 f"{pad2}area: {self.area};",
24 *(f"{pad2}pin({name}) {{ direction: input; }}"
25 for name in self.inputs),
26 *(f"{pad2}pin({name}) {{ direction: output; function: \"{func}\"; }}"
27 for name, func in self.outputs.items()),
28 f"{pad}}}",
29 ])
30
31 @dataclass
32 class TextCell:
33 text: str
34
35 def lib(self, tab_size=2, indent=0) -> str:
36 if indent == 0:
37 return self.text
38 padding = ' ' * (tab_size * indent)
39 return padding + self.text.replace('\n', '\n' + padding)
40
41 def print_lib(lib_name, cells):
42 print(f"library({lib_name}) {{")
43 for cell in cells:
44 print(cell.lib(tab_size=2, indent=1))
45 print("}")
46
47 def gen_cells(max_pins: int, or_nor: bool):
48 yield Cell("BUF", 1, ["A"], {"Y": "A"})
49 yield Cell("NOT", 4, ["A"], {"Y": "!A"})
50 # @TODO: Generate inputs more nicely
51 all_inputs = "ABCDEFGHIJKLMNOPQRSTUV"
52 for pins in range(2, max_pins+1):
53 inputs = all_inputs[:pins]
54 area = pins * 5 - 2
55 for neg in range(pins+1):
56 func = ' | '.join(
57 ["!" + inputs[i] for i in range(neg)] +
58 [inputs[i] for i in range(neg, pins)],
59 )
60 pin_name = f"{pins - neg}N{neg}"
61 yield Cell(f"OR_{pin_name}", area + 1, inputs, {"Y": func})
62 yield Cell(f"NOR_{pin_name}", area + 2, inputs, {"Y": f"!({func})"})
63 if or_nor:
64 yield Cell(
65 f"OR_NOR_{pin_name}", area + 3, inputs,
66 {"Y": func, "Z": f"!({func})"},
67 )
68
69 DFF_P = TextCell("""
70 cell(DFF_P) {
71 area: 8;
72 ff(IQ, IQN) { clocked_on: C; next_state: D; }
73 pin(C) { direction: input; clock: true; }
74 pin(D) { direction: input; }
75 pin(Q) { direction: output; function: "IQ"; }
76 }
77 """.strip())
78
79 DFF_N = TextCell("""
80 cell(DFF_N) {
81 area: 8;
82 ff(IQ, IQN) { clocked_on: "!C"; next_state: D; }
83 pin(C) { direction: input; clock: true; }
84 pin(D) { direction: input; }
85 pin(Q) { direction: output; function: "IQ"; }
86 }
87 """.strip())
88
89 if __name__ == '__main__':
90 parser = argparse.ArgumentParser(
91 description="Generate a liberty file for Minecraft standard cells.",
92 )
93 parser.add_argument(
94 '-n', '--max-pins', metavar='N', type=int, choices=range(2, 17), default=5,
95 help="the maximum number of input pins on a single cell",
96 )
97 parser.add_argument(
98 '-o', '--or-nor', action='store_true',
99 help="generate two output combined or/nor gates",
100 )
101 args = parser.parse_args()
102 cells = list(gen_cells(args.max_pins, args.or_nor))
103 cells.append(DFF_P)
104 cells.append(DFF_N)
105 print_lib("redstone", cells)