Last active
August 12, 2022 04:51
-
-
Save yut23/5b6ded1b894b4b6f13ea26285b624f78 to your computer and use it in GitHub Desktop.
ChipWizard save format notes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ChipWizard save format notes: | |
* stored in save.dat base64-encoded and zlib compressed | |
* multi-byte integers are little-endian | |
4-byte header at start of file: 0xEA 0x03 0x00 0x00 | |
120 bytes of data for layout | |
* 4 bytes for each cell, 5 rows × 6 columns | |
* starts at lower-left corner, proceeds to the right, wrapping to the next row above | |
byte 1: bit field for components | |
0x01: metal | |
0x02: n-type | |
0x04: p-type | |
0x08: capacitor | |
0x10: via | |
0x20: transistor type (set by n-type, cleared by p-type, persists after deletion) | |
0x40 & 0x80: unused | |
byte 2: metal connections, only lowest 4 bits used | |
0x01: right | |
0x02: top | |
0x04: left | |
0x08: bottom | |
byte 3: n-type connections (same values as metal) | |
byte 4: p-type connections (same values as metal) | |
Examples in binary: | |
metal, none: 00000001 00000000 00000000 00000000 | |
metal, right: 00000001 00000001 00000000 00000000 | |
metal, top: 00000001 00000010 00000000 00000000 | |
metal, left: 00000001 00000100 00000000 00000000 | |
metal, bottom: 00000001 00001000 00000000 00000000 | |
n-type, none: 00100010 00000000 00000000 00000000 | |
n-type, right: 00100010 00000000 00000001 00000000 | |
n-type, top: 00100010 00000000 00000010 00000000 | |
n-type, left: 00100010 00000000 00000100 00000000 | |
n-type, bottom: 00100010 00000000 00001000 00000000 | |
p-type, none: 00000100 00000000 00000000 00000000 | |
p-type, right: 00000100 00000000 00000000 00000001 | |
p-type, top: 00000100 00000000 00000000 00000010 | |
p-type, left: 00000100 00000000 00000000 00000100 | |
p-type, bottom: 00000100 00000000 00000000 00001000 | |
capacitor: 00001000 00000000 00000000 00000000 (exclusive with silicon) | |
via: 00010000 00000000 00000000 00000000 (can only be placed on silicon) | |
p-type, L&R: 00000100 00000000 00000000 00000101 (p-type, right | p-type, left) | |
PNP, base on top: 00100110 00000000 00000010 00000101 (p-type, right | p-type, left | n-type, up) | |
n-type, L&R: 00100010 00000000 00000101 00000000 (n-type, right | n-type, left) | |
NPN, base on bottom: 00000110 00000000 00000101 00000010 (n-type, right | n-type, left | p-type, up) | |
The transistor type flag is used to distinguish between transistors that have the same connection layout: | |
PNP, base on top and bottom: 00000110 00000000 00000101 00001010 | |
NPN, base on left and right: 00100110 00000000 00000101 00001010 | |
It gets set when dragging over a cell with n-type silicon selected. | |
This is followed by 0x01 and 16 more bytes if there's a selection, or just 0x00 if not | |
selection format: | |
u4: lower-left corner x | |
u4: lower-left corner y | |
u4: width | |
u4: height |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""Reads ChipWizard solutions from `save.dat` and pretty-prints them.""" | |
import base64 | |
import io | |
import struct | |
import sys | |
import zlib | |
for line in sys.stdin: | |
key, _, string = line.partition(" = ") | |
if not key.startswith("Volgograd.Solution"): | |
continue | |
data = zlib.decompress(base64.b64decode(string.strip())) | |
stream = io.BytesIO(data) | |
print(f"{key}:") | |
# check header | |
assert struct.unpack("<I", stream.read(4))[0] == 1002 | |
rows = [] | |
for r in range(5): | |
row = [] | |
for c in range(6): | |
cell = stream.read(4) | |
row.append(cell) | |
rows.append(row) | |
if stream.read(1)[0]: | |
selection = True | |
x, y, width, height = struct.unpack("<4I", stream.read(16)) | |
else: | |
selection = False | |
# print in reverse order, to match the layout in-game | |
for row in rows[::-1]: | |
for cell in row: | |
print(" ".join([f"{byte:08b}" for byte in cell]), end=" ") | |
print() | |
if selection: | |
print(f"Selection: {x=}, {y=}, {width=}, {height=}") | |
print() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment