Add romgen, a tool to generate ROMs for litho
[minecraft-eda] / romgen.py
1 import argparse
2 import sys
3
4 base = [
5 (0, 0,-1, 'stone_slab[type=top]'),
6 (0, 1,-1, 'stone_slab[type=top]'),
7 (0, 2,-1, 'stone_slab[type=top]'),
8 (0, 0, 0, 'air'),
9 (0, 1, 0, 'air'),
10 (0, 2, 0, 'air'),
11 (1, 1, 0, 'stone'),
12 (2, 1, 1, 'stone'),
13 (2, 2, 1, 'stone'),
14 (3, 2, 1, 'stone_slab[type=top]'),
15 (1, 2, 2, 'stone'),
16 ]
17 redstone = [
18 (0, 0, 0, 'redstone_wire[north=side,south=side]'),
19 (0, 1, 0, 'redstone_wire[east=up,north=side,south=side]'),
20 (0, 2, 0, 'redstone_wire[north=side,south=side]'),
21 (1, 1, 1, 'redstone_wire[east=up,west=side]'),
22 (2, 1, 2, 'redstone_wire[north=none,east=none,south=side,west=side]'),
23 (2, 2, 2, 'redstone_wire[north=side,east=side,south=none,west=up]'),
24 (3, 2, 2, 'redstone_wire[north=none,east=side,south=none,west=side]'),
25 (1, 2, 3, 'redstone_wire[north=none,east=side,south=none,west=side]'),
26 ]
27
28 if __name__ == '__main__':
29 parser = argparse.ArgumentParser(
30 description="Generate a ROM cell of specified dimensions and contents",
31 )
32 parser.add_argument(
33 '-w', '--width', required=True, type=int,
34 help="the number of bits in a word",
35 )
36 parser.add_argument(
37 '-d', '--depth', required=True, type=int,
38 help="the number of bits in an address",
39 )
40 parser.add_argument(
41 '-D', '--data', required=True,
42 help="the value to initialize the memory to, formatted as a .hex file",
43 )
44 if len(sys.argv) == 1:
45 parser.print_help(sys.stderr)
46 sys.exit(1)
47 args = parser.parse_args()
48 words = 2 ** args.depth
49 offset = 3 * args.depth + 1
50 data = [0] * words
51 limit = 2 ** args.width - 1
52 with open(args.data, 'r') as f:
53 for i, line in enumerate(f):
54 if i >= words:
55 print(f"Warning: Truncating '{args.data}' to {words} words", file=sys.stderr)
56 break
57 try:
58 val = int(line, 16)
59 except:
60 print(f"Error: invalid hex on line {i} ({line})", file=sys.stderr)
61 sys.exit(1)
62 data[i] = val
63 if val > limit:
64 print(
65 f"Error: hex out of bounds on line {i} ({val:x} > {limit:x})",
66 file=sys.stderr,
67 )
68 sys.exit(1)
69 for word in range(words):
70 y0 = word * 3
71 for bit in range(args.depth):
72 x0 = bit * 3
73 for x, y, z, block in base:
74 print(x0 + x, y0 + y, z, block)
75 for bit in range(args.width):
76 x0 = 2 * bit + offset
77 print(x0 + 0, y0 + 2, 1, 'stone')
78 print(x0 + 1, y0 + 2, 1, 'stone')
79 for word in range(words):
80 y0 = word * 3
81 for bit in range(args.depth):
82 x0 = bit * 3
83 for x, y, z, block in redstone:
84 print(x0 + x, y0 + y, z, block)
85 for bit in range(args.width):
86 x0 = 2 * bit + offset
87 if bit % 8 == 0:
88 print(x0 - 1, y0 + 2, 2, 'repeater[facing=west]')
89 print(x0 + 0, y0 + 2, 2, 'redstone_wire[east=side,west=side]')
90 print(x0 + 1, y0 + 2, 2, 'redstone_wire[east=side,west=side]')
91 for bit in range(args.depth):
92 x0 = 3 * bit
93 print(x0, -1, 0, 'redstone_wire[north=up,south=side]')
94 print(x0, -2, 1, 'redstone_wire[north=side,south=side]')
95 print(x0, -3, 1, 'redstone_wire[north=side,south=side]')
96 for word in range(words):
97 y0 = 3 * word
98 for bit in range(args.depth):
99 x0 = 3 * bit
100 if word & (1 << bit):
101 print(x0 + 2, y0 + 1, 2, 'redstone_torch')
102 else:
103 print(x0 + 2, y0 + 1, 1, 'glass')
104 if bit % 2 == 1:
105 print(x0 + 3, y0 + 2, 2, 'repeater[facing=west]')
106 if word % 3 == 0:
107 print(x0, y0, 0, 'repeater[facing=north]')
108 for bit in range(args.width):
109 x0 = 2 * bit + offset
110 if data[word] & (1 << bit):
111 print(x0 + 0, y0 + 1, 1, 'redstone_wall_torch')
112 for bit in range(args.width):
113 x0 = 2 * bit + offset
114 print(x0, -3, 1, 'redstone_wire[north=side,south=side]')
115 print(x0, -2, 1, 'redstone_wire[north=side,south=side]')
116 for y0 in range(-1, 3 * words + 1):
117 print(x0, y0, -1, 'stone_slab[type=top]')
118 if y0 % 15 == 2:
119 print(x0, y0, 0, 'repeater[facing=south]')
120 else:
121 print(x0, y0, 0, 'redstone_wire[north=side,south=side]')