Upload V20 microcode

This commit is contained in:
dbalsom
2025-10-13 15:39:06 -04:00
parent c4ad6c3715
commit d661623167
29 changed files with 6775 additions and 0 deletions
+4
View File
@@ -1,2 +1,6 @@
# x86_microcode
Microcode resources for various x86 CPUs
## /v20
Microcode for the NEC V20 and V30 CPUs.
+178
View File
@@ -0,0 +1,178 @@
# The NEC V20 & V30 Microcode
<img width="800" height="697" alt="The NEC V20 Die" src="images/v20_die_shot_01.jpg" />
NEC used unified microcode for both the NEC V20 and V30, which differ only in their metal layer interconnects.
The only difference between the microcode for either version of CPU is in the microcode routine that handles hardware
interrupts. Like the 8088, the V20 needs a special routine to only issue one INTA request to the 8259 as otherwise its
BIU logic will split two INTA cycles into four.
## Word Format
There are some differences between the actual microcode word format the published legend, which has its origin in
court documents from the NEC vs Intel lawsuit. The microcode is logically split into two parts, 17 bits that encode
source and destination operands, and 12 bits that encode executive instructions.
The source/destination field has two formats, one that encodes two source/destination pairs, and one that encodes an
immediate constant value.
![word_format](./images/v20_word_format.png)
## Files
#### v20_microcode.xlsx
The current working decode spreadsheet of the V20 microcode. Some field values are still undetermined.
#### v20_microcode_01.txt
The extracted bits from the V20's microcode ROM in ASCII format, an array of 258x116 bits.
Note that there are two more columns than you may expect. Column 128 (exactly halfway through the ROM) does not appear
to be decoded. Columns 118 & 119 contain the hardware interrupt routine for the V20 and V30, respectively. The column
not used by the specific CPU is disabled.
These bits are also available as a PNG and PBM image, as follows:
![microcode_bits](./images/microcode_rom.png)
#### /images/microcode_rom.png
#### /images/microcode_rom.pbm
#### /images/microcode_crop_01.jpg
This is a half-resolution crop of the microcode ROM region. This image file was used with MaskRomTool to define the ROM
bit positions.
#### /images/microcode_crop_01.jpg.json
MaskRomTool's saved project file for the image above. If you load the image with this JSON in the same directory in
MaskRomTool the project should be restored and you could attempt your own extraction.
#### /images/microcode_bit_check.jpg
This is a grid-aligned image of the microcode ROM bits showing the logical bit extraction overlayed - a 1 bit being a
bright square and a 0 being a dark square. This image was used for manual verification of the extraction accuracy.
Spot any errors? Please open an issue if you do!
#### /images/activation_pla_01.jpg
This is a half-resolution crop of the microcode activation PLA, or what Intel calls a matching decoder PLA.
#### /images/activation_pla_01.jpg.json
MaskRomTool's saved project file for the image above. If you load the image with this JSON in the same directory in
MaskRomTool the project should be restored and you could attempt your own extraction.
### v20_activation_pla.txt
The extracted gates from the V20's microcode activation PLA in ASCII format, an array of 257x26 bits.
The PLA encodes logic, not just bits - the way to interpret this image is as pairs of two pixels, vertically, that
encode the following logic.
| | | Meaning |
|---|---|------------|
| 0 | 0 | Don't Care |
| 1 | 0 | Match 1 |
| 0 | 1 | Match 0 |
| 1 | 1 | Impossible |
Lines
The extracted bits from the activation PLA are also encoded as two image files, as specfied below.
![activation_pla_bits](./images/activation_pla_01.png)
#### /images/activation_pla_01.png
#### /images/activation_pla_01.pbm
### /scripts/bit_classifier.py
A python script that uses the PyTorch framework to either train or run a convolutional neural network (CNN) to classify
input images as either 1's or 0's. The CNN trained by this script was used to extract the bits from the die photos.
The versions of pytorch used with this script were:
| package | version |
|------------|-------------|
|Python | 3.10.5|
|torch | 2.8.0+cu126|
|torchvision | 0.23.0+cu126|
### /models/microcode/model.pt
The trained PyTorch model used to extract the microcode bits. It was trained on an input size of 42x42.
### /models/activation_pla/model.pt
The trained PyTorch model used to extract the activation PLA bits. It was trained on an input size of 64x64.
### /scripts/extract_bits.py
This script takes the JSON file output by MaskRomTool and extracts square PNG files representing the area around each
indicated bit position, and will save the resulting images into a ZIP file to avoid thrashing your filesystem.
The resulting ZIP can be fed to the model via bit_classifier.py to reproduce the classification process, if you wish.
## Additional PLAS
Zoomed in views of the indicated PLAs:
![pla_locations](./images/pla_locations.jpg)
### /images/pla_1.jpg
### /images/pla_2.jpg
### /images/pla_3.jpg
### /images/pla_4.jpg
### /images/pla_5.jpg
### /v20_pla3.txt
The decoded PLA3 which is the V20's equivalent of the 8088's "Group Decode ROM".
The first two bits are a sort of opcode type field -
| bits | meaning |
|------|--------------------------|
| 00 | 8080 instruction |
| 01 | normal instruction |
| 10 | not present |
| 11 | extended NEC instruction |
The next 9 bits are provisionally identified as follows:
| bit | meaning |
|-----|---------|
| 0 | force byte operand |
| 1 | W bit is valid |
| 2 | one-byte non-microcoded instruction or prefix |
| 3 | uses AX or AL register |
| 4 | segment register operand |
| 5 | has modrm - this appears to only be valid for the 8088/80186 instructions |
| 6 | doesn't read EA operand |
| 7 | D bit is valid |
| 8 | set for all opcodes > 7F |
The final five bytes appear to identify individual instructions within their class.
For non-microcoded instructions there are exactly 16 variants:
|bits| meaning|
|----|--------|
| 0000 | Segment override |
| 0001 | 0F |
| 0010 | STD |
| 0011 | CLD |
| 0100 | STI / EI |
| 0101 | CLI / DI |
| 0110 | STC |
| 0111 | CLC |
| 1000 | REPC |
| 1001 | REPNC |
| 1010 | CMC |
| 1011 | HLT |
| 1100 | REPZ |
| 1101 | REPNZ |
| 1110 | F1 LOCK ALIAS(?) |
| 1111 | LOCK |
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 MiB

File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

+7
View File
@@ -0,0 +1,7 @@
{
"classes": [
"0",
"1"
],
"best_val_f1": 1.0
}
Binary file not shown.
+7
View File
@@ -0,0 +1,7 @@
{
"classes": [
"0",
"1"
],
"best_val_f1": 0.9891304347826086
}
Binary file not shown.
+501
View File
@@ -0,0 +1,501 @@
#!/usr/bin/env python3
"""
bit_classifier.py — Train and run a 0/1 bit classifier for microcode extraction
- Folder-based training via torchvision.datasets.ImageFolder with subdirs '0' and '1' (must pre-sort ~1000 bits)
- Saves best model and labels.json
- Predictor accepts: single image, a directory of images, OR a .zip containing images
- Optional CSV output for predictions
This software is released into the public domain as it was cobbled together from various tutorials.
NOTE!!: How you install pytorch is important. If you just do 'pip install torch' you will get the CPU-accellerated (slow) version.
Follow the instructions on pytorch's website if you have an nVidia GPU so you get CUDA accelleration.
Usage
Train:
python bit_classifier.py train --data ./data --out ./model_out --img-size 64 --grayscale
Predict (dir / file):
python bit_classifier.py predict --model-dir ./model_out --input ./some_dir --img-size 64 --grayscale
Predict (zip):
python bit_classifier.py predict --model-dir ./model_out --input ./images.zip --img-size 64 --grayscale --out-csv predictions.csv
"""
import argparse
import csv
import io
import json
import os
from dataclasses import dataclass
from pathlib import Path
from typing import Tuple, List, Iterable
import numpy as np
from PIL import Image
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, Subset
from torchvision import datasets, transforms, models
# ----------------------------
# Config / Utilities
# ----------------------------
@dataclass
class Config:
data_dir: Path
out_dir: Path
img_size: int = 64
batch_size: int = 64
epochs: int = 15
lr: float = 1e-3
weight_decay: float = 1e-4
train_split: float = 0.8
grayscale: bool = True
num_workers: int = 4
seed: int = 42
model: str = "cnn" # "cnn" or "resnet18"
freeze_backbone: bool = True # if using resnet18
aug: bool = True
def set_seed(seed: int):
import random
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True
# ----------------------------
# Models
# ----------------------------
class TinyCNN(nn.Module):
def __init__(self, in_ch: int, num_classes: int = 2):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(in_ch, 32, 3, padding=1), nn.ReLU(inplace=True),
nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(inplace=True),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 3, padding=1), nn.ReLU(inplace=True),
nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(inplace=True),
nn.MaxPool2d(2),
nn.Conv2d(64, 128, 3, padding=1), nn.ReLU(inplace=True),
nn.MaxPool2d(2),
)
# classifier will be adapted to img_size at runtime
self.classifier = nn.Identity()
def adapt_fc(self, img_size: int, num_classes: int = 2):
dummy = torch.zeros(1, self.features[0].in_channels, img_size, img_size)
with torch.no_grad():
feat = self.features(dummy)
n = feat.numel()
self.classifier = nn.Sequential(
nn.Flatten(),
nn.Linear(n, 128),
nn.ReLU(inplace=True),
nn.Dropout(0.25),
nn.Linear(128, num_classes),
)
def forward(self, x):
x = self.features(x)
return self.classifier(x)
def build_model(cfg: Config, in_channels: int, num_classes: int = 2) -> nn.Module:
if cfg.model == "resnet18":
m = models.resnet18(weights=models.ResNet18_Weights.DEFAULT)
if cfg.grayscale:
old = m.conv1
m.conv1 = nn.Conv2d(1, old.out_channels, kernel_size=old.kernel_size,
stride=old.stride, padding=old.padding, bias=False)
with torch.no_grad():
m.conv1.weight[:] = old.weight.mean(dim=1, keepdim=True)
if cfg.freeze_backbone:
for p in m.parameters():
p.requires_grad = False
for p in m.layer4.parameters():
p.requires_grad = True
m.fc = nn.Linear(m.fc.in_features, num_classes)
return m
else:
m = TinyCNN(in_channels, num_classes)
m.adapt_fc(cfg.img_size, num_classes)
return m
# ----------------------------
# Data & Transforms
# ----------------------------
def make_transforms(cfg: Config) -> Tuple[transforms.Compose, transforms.Compose]:
to_gray = [transforms.Grayscale(num_output_channels=1)] if cfg.grayscale else []
train_tf = [*to_gray, transforms.Resize((cfg.img_size, cfg.img_size))]
if cfg.aug:
train_tf += [
transforms.RandomApply([transforms.RandomRotation(5)], p=0.3),
transforms.RandomApply([transforms.ColorJitter(brightness=0.1, contrast=0.1)], p=0.3),
]
train_tf += [transforms.ToTensor()]
val_tf = [*to_gray, transforms.Resize((cfg.img_size, cfg.img_size)), transforms.ToTensor()]
return transforms.Compose(train_tf), transforms.Compose(val_tf)
def make_dataloaders(cfg: Config) -> Tuple[DataLoader, DataLoader, List[str], torch.Tensor]:
train_tf, val_tf = make_transforms(cfg)
# Base just to get samples/targets and class names
base = datasets.ImageFolder(str(cfg.data_dir), transform=None)
class_names = base.classes
targets = np.array([s[1] for s in base.samples])
class_counts = np.bincount(targets, minlength=len(class_names))
weights = 1.0 / np.maximum(class_counts, 1)
class_weights = torch.tensor(weights / weights.sum() * len(weights), dtype=torch.float32)
indices = np.arange(len(base))
rng = np.random.default_rng(cfg.seed)
rng.shuffle(indices)
split = int(cfg.train_split * len(indices))
train_idx, val_idx = indices[:split], indices[split:]
train_ds = datasets.ImageFolder(str(cfg.data_dir), transform=train_tf)
val_ds = datasets.ImageFolder(str(cfg.data_dir), transform=val_tf)
train_subset = Subset(train_ds, train_idx.tolist())
val_subset = Subset(val_ds, val_idx.tolist())
train_loader = DataLoader(train_subset, batch_size=cfg.batch_size, shuffle=True,
num_workers=cfg.num_workers, pin_memory=True)
val_loader = DataLoader(val_subset, batch_size=cfg.batch_size, shuffle=False,
num_workers=cfg.num_workers, pin_memory=True)
return train_loader, val_loader, class_names, class_weights
# ----------------------------
# Metrics
# ----------------------------
def confusion_matrix(y_true: np.ndarray, y_pred: np.ndarray, num_classes: int = 2) -> np.ndarray:
cm = np.zeros((num_classes, num_classes), dtype=int)
for t, p in zip(y_true, y_pred):
cm[t, p] += 1
return cm
def metrics_from_logits(logits: torch.Tensor, y: torch.Tensor):
preds = logits.argmax(dim=1)
correct = (preds == y).sum().item()
total = y.numel()
tp = ((preds == 1) & (y == 1)).sum().item()
fp = ((preds == 1) & (y == 0)).sum().item()
fn = ((preds == 0) & (y == 1)).sum().item()
precision = tp / (tp + fp) if (tp + fp) else 0.0
recall = tp / (tp + fn) if (tp + fn) else 0.0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) else 0.0
return correct, total, precision, recall, f1, preds
# ----------------------------
# EarlyStopper
# ----------------------------
class EarlyStopper:
def __init__(self, patience: int = 3, min_delta: float = 0.0):
self.patience = patience
self.min_delta = min_delta
self.best = float("-inf")
self.num_bad = 0
def step(self, metric: float) -> bool:
"""Return True if we should stop (no improvement for `patience` steps)."""
if metric > self.best + self.min_delta:
self.best = metric
self.num_bad = 0
else:
self.num_bad += 1
return self.num_bad >= self.patience
# ----------------------------
# Train / Eval
# ----------------------------
def train_one_epoch(model, loader, device, optimizer, criterion):
model.train()
total_loss = 0.0
total_correct = 0
total_count = 0
ps, rs, fs = [], [], []
for x, y in loader:
x, y = x.to(device), y.to(device)
optimizer.zero_grad(set_to_none=True)
logits = model(x)
loss = criterion(logits, y)
loss.backward()
optimizer.step()
total_loss += loss.item() * y.size(0)
correct, count, p, r, f1, _ = metrics_from_logits(logits, y)
total_correct += correct
total_count += count
ps.append(p); rs.append(r); fs.append(f1)
return {
"loss": total_loss / max(total_count, 1),
"acc": total_correct / max(total_count, 1),
"precision": float(np.mean(ps)) if ps else 0.0,
"recall": float(np.mean(rs)) if rs else 0.0,
"f1": float(np.mean(fs)) if fs else 0.0,
}
def evaluate(model, loader, device, criterion):
model.eval()
total_loss = 0.0
total_correct = 0
total_count = 0
ps, rs, fs = [], [], []
all_preds = []
all_labels = []
with torch.no_grad():
for x, y in loader:
x, y = x.to(device), y.to(device)
logits = model(x)
loss = criterion(logits, y)
total_loss += loss.item() * y.size(0)
correct, count, p, r, f1, preds = metrics_from_logits(logits, y)
total_correct += correct
total_count += count
ps.append(p); rs.append(r); fs.append(f1)
all_preds.append(preds.cpu().numpy())
all_labels.append(y.cpu().numpy())
cm = confusion_matrix(np.concatenate(all_labels), np.concatenate(all_preds)) if total_count else np.zeros((2,2), dtype=int)
return {
"loss": total_loss / max(total_count, 1),
"acc": total_correct / max(total_count, 1),
"precision": float(np.mean(ps)) if ps else 0.0,
"recall": float(np.mean(rs)) if rs else 0.0,
"f1": float(np.mean(fs)) if fs else 0.0,
"confusion_matrix": cm.tolist(),
}
def save_checkpoint(model, out_dir: Path, class_names: List[str], best_metric: float):
out_dir.mkdir(parents=True, exist_ok=True)
torch.save(model.state_dict(), out_dir / "model.pt")
with open(out_dir / "labels.json", "w") as f:
json.dump({"classes": class_names, "best_val_f1": best_metric}, f, indent=2)
# ----------------------------
# Prediction helpers (file/dir/zip)
# ----------------------------
IMG_EXTS = {".png", ".jpg", ".jpeg", ".bmp", ".tif", ".tiff"}
def load_tensor_from_pil(img: Image.Image, img_size: int, grayscale: bool) -> torch.Tensor:
tf = transforms.Compose(
([transforms.Grayscale(1)] if grayscale else []) +
[transforms.Resize((img_size, img_size)), transforms.ToTensor()]
)
return tf(img).unsqueeze(0)
def load_image_from_path(path: Path, img_size: int, grayscale: bool) -> torch.Tensor:
img = Image.open(path).convert("RGB")
return load_tensor_from_pil(img, img_size, grayscale)
def load_image_from_bytes(data: bytes, img_size: int, grayscale: bool) -> torch.Tensor:
img = Image.open(io.BytesIO(data)).convert("RGB")
return load_tensor_from_pil(img, img_size, grayscale)
def iter_images_in_dir(path: Path) -> Iterable[Path]:
if path.is_dir():
for ext in IMG_EXTS:
yield from path.rglob(f"*{ext}")
elif path.is_file() and path.suffix.lower() in IMG_EXTS:
yield path
def iter_images_in_zip(zip_path: Path) -> Iterable[Tuple[str, bytes]]:
import zipfile
with zipfile.ZipFile(zip_path, 'r') as zf:
for info in zf.infolist():
name_lower = info.filename.lower()
if any(name_lower.endswith(ext) for ext in IMG_EXTS):
with zf.open(info, 'r') as f:
yield info.filename, f.read()
# ----------------------------
# CLI entry points
# ----------------------------
def train_main(args):
cfg = Config(
data_dir=Path(args.data),
out_dir=Path(args.out),
img_size=args.img_size,
batch_size=args.batch_size,
epochs=args.epochs,
lr=args.lr,
weight_decay=args.weight_decay,
train_split=args.train_split,
grayscale=args.grayscale,
num_workers=args.num_workers,
seed=args.seed,
model=args.model,
freeze_backbone=args.freeze_backbone,
aug=not args.no_aug,
)
set_seed(cfg.seed)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
train_loader, val_loader, class_names, class_weights = make_dataloaders(cfg)
in_ch = 1 if cfg.grayscale else 3
model = build_model(cfg, in_ch, num_classes=2).to(device)
criterion = nn.CrossEntropyLoss(weight=class_weights.to(device))
optimizer = optim.AdamW(filter(lambda p: p.requires_grad, model.parameters()),
lr=cfg.lr, weight_decay=cfg.weight_decay)
best_f1 = -1.0
stopper = EarlyStopper(patience=args.patience, min_delta=args.min_delta)
for epoch in range(1, cfg.epochs + 1):
tr = train_one_epoch(model, train_loader, device, optimizer, criterion)
va = evaluate(model, val_loader, device, criterion)
print(f"[Epoch {epoch:02d}] "
f"train: loss={tr['loss']:.4f} acc={tr['acc']:.4f} f1={tr['f1']:.4f} | "
f"val: loss={va['loss']:.4f} acc={va['acc']:.4f} f1={va['f1']:.4f}")
print(f" val precision={va['precision']:.4f} recall={va['recall']:.4f} "
f"cm={va['confusion_matrix']}")
if va["f1"] > best_f1:
best_f1 = va["f1"]
save_checkpoint(model, cfg.out_dir, class_names, best_f1)
if stopper.step(va["f1"]):
print(f"Early stopping: no val F1 improvement >= {args.min_delta} for {args.patience} epoch(s).")
break
print(f"Best val F1: {best_f1:.4f}")
print(f"Saved best model to: {cfg.out_dir/'model.pt'}")
def predict_main(args):
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_dir = Path(args.model_dir)
with open(model_dir / "labels.json", "r") as f:
meta = json.load(f)
classes = meta["classes"]
grayscale = args.grayscale
img_size = args.img_size
arch = args.model
in_ch = 1 if grayscale else 3
model = build_model(Config(data_dir=Path("."), out_dir=Path("."), img_size=img_size,
grayscale=grayscale, model=arch), in_ch, num_classes=len(classes))
model.load_state_dict(torch.load(model_dir / "model.pt", map_location=device))
model.to(device).eval()
input_path = Path(args.input)
results = [] # list of (name, pred_label, p0, p1)
with torch.no_grad():
if input_path.suffix.lower() == ".zip":
for name, data in iter_images_in_zip(input_path):
x = load_image_from_bytes(data, img_size, grayscale).to(device)
logits = model(x)
probs = torch.softmax(logits, dim=1).cpu().numpy()[0]
pred_idx = int(np.argmax(probs))
results.append((name, classes[pred_idx], float(probs[0]), float(probs[1])))
else:
paths = list(iter_images_in_dir(input_path))
if not paths:
raise SystemExit(f"No images found in '{input_path}'.")
for p in sorted(paths):
x = load_image_from_path(p, img_size, grayscale).to(device)
logits = model(x)
probs = torch.softmax(logits, dim=1).cpu().numpy()[0]
pred_idx = int(np.argmax(probs))
results.append((str(p), classes[pred_idx], float(probs[0]), float(probs[1])))
for name, pred, p0, p1 in results:
print(f"{name}: pred={pred} P(0)={p0:.3f} P(1)={p1:.3f}")
# Optional CSV
if args.out_csv:
with open(args.out_csv, "w", newline="") as f:
w = csv.writer(f)
w.writerow(["name", "pred", "P0", "P1"]) # keep headers simple
for row in results:
w.writerow(row)
print(f"Wrote CSV: {args.out_csv}")
def build_argparser():
p = argparse.ArgumentParser(description="Train a 0/1 die-shot bit classifier.")
sub = p.add_subparsers(required=True, dest="cmd")
pt = sub.add_parser("train", help="Train the model")
pt.add_argument("--data", required=True, help="Path with folders '0' and '1'")
pt.add_argument("--out", default="model_out", help="Output dir for model + labels.json")
pt.add_argument("--img-size", type=int, default=64)
pt.add_argument("--batch-size", type=int, default=64)
pt.add_argument("--epochs", type=int, default=15)
pt.add_argument("--lr", type=float, default=1e-3)
pt.add_argument("--weight-decay", type=float, default=1e-4)
pt.add_argument("--train-split", type=float, default=0.8)
pt.add_argument("--num-workers", type=int, default=4)
pt.add_argument("--seed", type=int, default=42)
pt.add_argument("--grayscale", action="store_true", help="Force 1-channel input")
pt.add_argument("--model", choices=["cnn", "resnet18"], default="cnn")
pt.add_argument("--freeze-backbone", action="store_true", help="Freeze resnet18 backbone")
pt.add_argument("--no-aug", action="store_true", help="Disable data augmentation")
pt.add_argument("--patience", type=int, default=3, help="Early stopping patience (epochs without val improvement)")
pt.add_argument("--min-delta", type=float, default=0.0, help="Minimum F1 improvement to reset patience")
pp = sub.add_parser("predict", help="Run inference on an image, directory, or .zip of images")
pp.add_argument("--model-dir", default="model_out", help="Folder with model.pt and labels.json")
pp.add_argument("--input", required=True, help="Image path, directory, or .zip archive")
pp.add_argument("--img-size", type=int, default=64)
pp.add_argument("--grayscale", action="store_true")
pp.add_argument("--model", choices=["cnn", "resnet18"], default="cnn")
pp.add_argument("--out-csv", default=None, help="Optional path to write a CSV of predictions")
return p
def main():
parser = build_argparser()
args = parser.parse_args()
if args.cmd == "train":
train_main(args)
elif args.cmd == "predict":
predict_main(args)
else:
parser.print_help()
if __name__ == "__main__":
main()
+157
View File
@@ -0,0 +1,157 @@
#!/usr/bin/env python3
"""
Export square crops around MaskROMTool bit coordinates into a single ZIP file.
Usage:
python export_bit_windows_zip.py \
--json bits.json \
--image die.jpg \
--zip_out bits.zip \
--window_size 38
Notes:
- The input JSON is expected to have a large "bits" array with fields: x, y, value, ambiguous.
- Bits are sorted *column-first*, *bottom-up*.
- Logical coordinates are assigned so that (0,0) is the top-left of the bit grid.
- Each crop (window_size × window_size) is saved as bit_X_Y.png inside the ZIP.
"""
import argparse
import json
import math
import os
import io
import zipfile
from dataclasses import dataclass
from statistics import mean
from typing import List, Tuple
from PIL import Image
@dataclass
class Bit:
x: float
y: float
value: bool | None = None
ambiguous: bool | None = None
gx: int | None = None
gy: int | None = None
def parse_args() -> argparse.Namespace:
p = argparse.ArgumentParser(description="Export bit-centered crops into a single ZIP archive.")
p.add_argument("--json", required=True, help="Path to MaskROMTool JSON file.")
p.add_argument("--image", required=True, help="Path to source JPEG (very high resolution).")
p.add_argument("--zip_out", required=True, help="Output ZIP filename (e.g. bits.zip).")
p.add_argument("--window_size", type=int, required=True, help="Window size (pixels).")
p.add_argument("--tail_frac", type=float, default=0.05,
help="Fraction of largest x-diffs used for detecting column jumps (default: 0.05).")
return p.parse_args()
def load_bits(json_path: str) -> List[Bit]:
with open(json_path, "r", encoding="utf-8") as f:
data = json.load(f)
bits_json = data.get("bits")
if not isinstance(bits_json, list):
raise ValueError("JSON missing 'bits' array.")
return [Bit(
x=float(b["x"]),
y=float(b["y"]),
value=bool(b.get("value")) if "value" in b else None,
ambiguous=bool(b.get("ambiguous")) if "ambiguous" in b else None,
) for b in bits_json]
def estimate_column_threshold(x_diffs: List[float], tail_frac: float) -> float:
if not x_diffs:
return 0.0
diffs = sorted(abs(d) for d in x_diffs)
n = len(diffs)
if n == 1:
return diffs[0] / 2 if diffs[0] > 0 else 0.0
cut = max(1, min(n - 1, int(math.floor((1.0 - tail_frac) * n))))
small = diffs[:cut]
large = diffs[cut:]
if not large:
return (mean(small) if small else 0.0) * 3.0
return (mean(small) + mean(large)) / 2.0
def split_into_columns(bits: List[Bit], tail_frac: float) -> List[List[Bit]]:
x_diffs = [bits[i].x - bits[i - 1].x for i in range(1, len(bits))]
threshold = estimate_column_threshold(x_diffs, tail_frac)
columns: List[List[Bit]] = []
current_col: List[Bit] = [bits[0]]
for i in range(1, len(bits)):
dx = abs(bits[i].x - bits[i - 1].x)
if dx > threshold:
columns.append(current_col)
current_col = [bits[i]]
else:
current_col.append(bits[i])
columns.append(current_col)
columns.sort(key=lambda col: mean(b.x for b in col))
return columns
def assign_logical_grid(columns: List[List[Bit]]) -> Tuple[int, int]:
grid_width = len(columns)
grid_height_max = 0
for gx, col in enumerate(columns):
col_sorted = sorted(col, key=lambda b: b.y) # top→bottom
for gy, b in enumerate(col_sorted):
b.gx = gx
b.gy = gy
grid_height_max = max(grid_height_max, len(col_sorted))
columns[gx] = col_sorted
return grid_width, grid_height_max
def crop_with_padding(img: Image.Image, cx: int, cy: int, size: int) -> Image.Image:
half = size // 2
left = cx - half
top = cy - half
right = left + size
bottom = top + size
src_w, src_h = img.size
src_box = (max(left, 0), max(top, 0), min(right, src_w), min(bottom, src_h))
out = Image.new("RGB", (size, size), (0, 0, 0))
dst_left = max(0, -left)
dst_top = max(0, -top)
if src_box[0] < src_box[2] and src_box[1] < src_box[3]:
region = img.crop(src_box)
out.paste(region, (dst_left, dst_top))
return out
def main():
args = parse_args()
bits = load_bits(args.json)
print(f"[info] Loaded {len(bits)} bits.")
columns = split_into_columns(bits, args.tail_frac)
grid_w, grid_h_max = assign_logical_grid(columns)
print(f"[info] Detected grid {grid_w}×{grid_h_max}")
img = Image.open(args.image).convert("RGB")
ws = args.window_size
ordered_bits = [b for col in columns for b in col]
with zipfile.ZipFile(args.zip_out, "w", compression=zipfile.ZIP_DEFLATED) as zf:
for i, b in enumerate(ordered_bits, 1):
cx, cy = int(round(b.x)), int(round(b.y))
crop = crop_with_padding(img, cx, cy, ws)
buf = io.BytesIO()
crop.save(buf, format="PNG")
zf.writestr(f"bit_{b.gx}_{b.gy}.png", buf.getvalue())
if i % 500 == 0 or i == len(ordered_bits):
print(f"[progress] {i}/{len(ordered_bits)} written")
print(f"[done] {len(ordered_bits)} images saved to {args.zip_out}")
if __name__ == "__main__":
main()
+257
View File
@@ -0,0 +1,257 @@
00?00???0??00
00?00???10?00
00?000??11100
00?000??11000
00?0010011100
00?0010111100
00?0011011100
00?0011?11101
00?0011111100
00?0100????00
00?01010???00
00?01011???00
00?0110011?00
00?0111????00
00?0111????01
00?100000??00
00?100000??01
00?1000010?00
00?1000011?00
00?100010??00
00?100011?000
00?1000110100
00?1000111100
00?10010???00
00?1001100000
00?1001100100
00?1001101000
00?1001101100
00?1001101101
00?1001110000
00?1001110100
00?1001111000
00?1001111100
00?1010000?00
00?1010001?00
0001010010?00
1110001100010
0011010010?00
00?1010010?01
0001010011?00
0001010011?01
0011010?11?00
0011010011?01
0011010011?10
1110011000011
00?1010100?00
0001010101?00
0011010101?00
0011010101?01
0001010110?00
0011010110?00
0011010110?01
0001010111?00
0001010111?01
0011010111?01
0011010111?10
00?1011????00
00?1100?01000
00?1100001001
00?1100101001
00?1100001100
00?1100101100
00?1100010000
00?1100010100
00?1100011?00
00?1100110000
00?1100110100
00?1100111000
00?1100111100
00?1101000?00
00?1101001?00
00?1101010000
00?1101010001
00?1101010100
00?1101010101
00?1101011100
00?11011???00
00?1110000?00
00?111000??01
00?1110001000
00?1110001100
00?1110010?00
00?1110011?00
00?1110100000
00?1110100001
00?1110100100
00?1110101100
00?1110101000
00?1110101001
00?1110110?00
00?1110111?00
010??00????00
010??011???00
010??010???00
010??100???00
010??100???01
010??100???10
010??101???00
010??110???00
010??110???01
010??110???10
010??110???11
010??111???00
010??111???01
1110111100000
1110111100001
1111001000000
1111001000001
1111001000010
1111001000011
011??00????00
011??010???00
011??011???00
011??100???00
011??101???00
011??11????00
1110000001100
1110000001101
1110000000000
1110000001000
1110000001000
1110000100000
1110000100001
1110001?00000
1110001?00001
1110001000010
1110001?00011
1110001?00100
1000011?10010
1110010000000
1110010100000
1110011?00000
1110011?00001
1110011?00010
1110011000100
1110011100011
1110100000000
1110100000001
1110100100000
1110110100000
1110110100001
1111000000000
00?0110000000
1110101100000
1110101100001
1110101100010
1110101100011
00?0110000100
1110110000000
1110110000001
1110110000010
1110110000011
00?1100100000
1110101000000
1110101000001
1110101000010
1110101000011
00?1100100100
00?0110001000
00?0110001001
00?0110001010
00?0110101000
00?0110100000
00?1100000?00
00?011010?100
0000110110?00
0010110110?00
0010110110?01
0000110111?00
0010110111?00
0010110111?01
1000001000?00
1000001100?00
1000001010?00
1000001110?00
1000001001?00
1000001101?00
1000001011?00
1000001111?00
10000100??000
10000100??001
1000010000010
10000100??011
10000100??100
10000100??101
1000010001010
1000010011010
1000010100000
100001010?001
100001010?010
1000010101000
1000011001100
1000011?01101
1000011?01110
1000011?01111
1000011?10000
1000011?10001
1000011101100
1000011?00100
1000011000101
1000011?00110
1000011?00111
1110111000000
1110111000001
1110111000010
1110111000011
1110111000100
1110111000101
1110111000110
1000011100101
1001111111100
1100000000000
11001??????00
11000???11000
11000??000100
1100011101000
1100011001000
1100010101000
1100010001000
110000?101000
110000?001000
1101110001100
1101110101100
1101110100100
1101111100100
11000???10000
11000???10100
11000??001100
11000??101100
11010??????00
11011???11000
11000??100100
1100010011100
1100010111100
110000??11100
1101100001100
11011???01000
11011???01001
11011???11100
1101100110100
1101100110101
11011???10000
11011???10001
1101100100100
11011???00000
11011???00001
110110?010100
1101110010100
1101111010100
110110?000100
1101110000100
1101111000100
1101111000101
1101101001100
1101101101100
1011111110100
1011110110100
Binary file not shown.
+116
View File
@@ -0,0 +1,116 @@
001000000001000000000000001000000100000000101000010000000000100000000000000000000001000100000001000010000000010110101001100010100000000000001010000010000000001000100000000000000000000000000000000000000001010011100110111100100011000000001000100110111011101000
000000000000000100100001001010110110110010101000000000101010001110000010001101100100011100000001000011000000000000100000111001100000010000000010000001110000010001111001001000000000010010000100010011011100000100100111101001110000000000000001000100000100011100
010000000000000100110001101001010110001011001101001100001100010010000001100000100101110111010000000001001011010010001101100010100000000001101100000000000110010110010110010000000000000000000010001110110000000011000001111110100000000000001110101000000000110101
000000000000011100000000011000001111100110011010010011001100001110100001000000011111011110010000100000000001010100101100101101000110100110001110000000111100000100111100000000000000001000110110000100001000111110110011111100000000000100001100111000000100011101
011000101001000100000010001010100110001010010110010110110000110000000101011000100001011100010010001000000110100010000000110110000000101000101000000011110001011111010010110100001100000011001101011111101101000100100110111100100011000000010001100010111111011000
001111101011000000000010011011100001101110100011010010100010111100000101110101100101011100010010001100101010000110111011011101100010100000111111111011110010001111000100100011111111111101111001100100000001010011000000000001000011001001010001100110111011101100
110111101110001101000100001000000110110000010100100101101111001110000100011100011011010101111100000110110101001110110001111111000010010001011010000001110101101010111101001011111111111110111001111101101111111110110001111110100000110111101101101100011100100000
110000010100011111111011001000010110001010110000100101101111001111110111111000111111111100011111011110110000101111100010001010010000011000000010111101111111010110111100000111111111001001111001100010111110000100110111111111000011111110011100101000000000001101
000000101000000100000000000000000010001000010000000110010000000000000000000000001000000000000000000000100000000000001000000000000000000000000001100000000000000010000001100100000000000100000100000000001000000100000000000000000000000000000000000000000000000000
000000000010000000000000000000000000110000000011000000000000000000000000001000010000000000010000000000000000000000010001100001000000000000000000000000000000000100000101011000000000000010001001000111010010000000000000010100000000000000000000000000011000100000
000100000000000000000000000000000000000001000001101000100000010000000111010000000010000000100010001001010010000100001100000000000000000000101001100000000010000000001010010100000000000000001101110000000000010001000110000001010011001000010000000000000100001001
110011101100000001111001110000010001010101000111011010000000000000000010010101100000000001101110011100101000001001001101100100000000000001000000000000000000000010000011001011111111100000000000000001010110101000000100000011011111111011100000000000000000000000
010000101000000000000010000010100000001010111110000100110000010000000101011000101001011000010001001010000110100100101000010100000000001000101001010001110111110110110010110100001100000111001101011111100000010011000110010100100011000000011000100100011100111000
001111101001000100100011010011010111111100001000010010001100110010000110111000110001011000000001000111101010000110001001100111100010110000111101111010000011001010111001101011111111101111111101100111011111010111100111111001110011001001010001100110100111111000
101011101111001001110111100000100000111011011001101001000011011100000011111100111100100010001110000011011110001000111100011101100010010001011111010001110011100000100011011011111111111100110110000011011110101101100000000001000000110111110011000110111100001101
001111111011001010000010110001110001011101101111111110100011110000001000111101100000100010000001100110001001110110011101100110010110101111001001111111000011111010000001001100000000100001000110000011000000111010000000000000100000000001100001010010111011110010
011000101001000000000010000010100100010010000110011000100000110000000101011000100001011000010000001000100110110110000001110110100000001000101010000011110011111100010011011000001100100011001101011111101001010010000110111100100011000000011001100110111111011000
001111101001000000000010000011110001011110101000010010100110111100000110110100100101011000000001000110101010000110100001011110100010100000111111111011110010011111111001111011111111110101001001110000001011010111100111111001110011001001010001100110111111111100
101100000111001001110111000000100001110111110001011101000011001100000000111100111100000001001110001010010101011010110001111111100010010001110111111001110001110010100011011100000000111100110100101101011110101110100000000011110000110110110011000100011100101100
001111111011001010011010100001110001001110110110110111100011111100001000111100000000100011100001000110001000110110110001001010010110101110000111111111111011110100000010010100000000001001110010011111001000010110100000000011000011110011100000010000000000010010
000000101000000100000010000010000011010111000101001010100000110000000001011000100001011000010000001000100110100110101000110110100000001000101011111001100110100110100001001000000000111010111101000011010101101001000110110100100011000000011001100110111000001000
000011101010000100000000000010110110110010100011000000100110011100000100110100100000011000010000000100101010000010111000111111100010110000101011111010000011000111010111011011001100011010110000010111011010100111100000111101100000001001010001000100011100111100
001111101001001001000010000001100001111101110011011011100001011100000101011100001110100010100010001010011101000110101100110111100010010001111101111001110000011010001011111111111111101111110100001100001101100111100110000011000011001101110010000010100000001100
111100000111001001110011000001100001100110011110010011000011110000001011111000000000100011101111011110101001101111111101101011000010101101001111111011000001101110100010010011111111001001110000111111101001111101100100000011111011111011100001010010111011100010
011000000001000000000010001010000111010111001101011000100000100000000100000000101000011100010010001000000110010100101000010000100000100000101011111000000100000101100001001000001100111110110000010100011000111111100110010100100011000000001001100110111011101000
000000000010000000100000001000000110100000000011000000001110011110000011001001010100000100000010001101000000000010111011110101100010000000011010000000000010000010111010010011110011100000001001000000001101000000100111111101100011000000000001000100011100001000
110100000100001101110111001001010111011100110110010111001100001110000010100100101111110111111100000111101010001100100100010000100010000000001101111000000111010100010101101100000000000100001001110011110010011000010111111101000011111000001110101000000100011101
001011111001010110001000101000111110110001000001001000001101111111111100100101011111111111110000100000010000000001001110101111000000010010000100000010000101001000011111011000000000100000001111010010010111010011010011111111101000000100011100111010100111101111
011000000001000000000000000000000100001000011000010100010000000000000100001000001000000000000011000010000000010000000001000000000000100000000000000000000000000000000000100100001100000000000000010100100000010010000000101000000000000000010000000000000011000000
000011101000000000100001010000000000000000001000000000001000001110000011101100010100000000000011001011000000000000101000000000000000000000010010000000110000000000001000000000110011100000000100100000000101000000000111000000010011001001000000000000000000000100
100000000100000000110101100000000000000000001000100100000000000000000000100000010000000001001100000100100000011000000101000000100000000000000000000000000001000100000000000000000000000000000010000011010010001000010000000010110000110110100000000000000000100001
000000010000000010001000010000001000010001000001001000000000001100000100000001100000000010000000100000010000010000001100001000000100010110000100000000011000000000000001001000000000000000001101000000000000000010000000000000000000000000010000000000000000010000
000000101000000100000010000010100001011101011001001110010000110000000001011000101001011000000010000000100000010010101001110110100000100000100010000001110001111001010001101100000000111100111101010111111101111110100000100000000000000000011001000110100100010000
001111101001000100000011001011000110000010101000000000100110111000000111111101110001011100010011001011001010000110101011110110000000000000101111111010010001011101101110010000001100101010110100110101000111000011000000101000000000001001010000100010100011100100
001011101011001000000010100000100001101100100010110010100011011100000111111100110100000010000010001101110111000110110001111101100000010001110110000001110001101110101010110111111111101011111111110001111001110110110110000010000011001101110011000110111000100101
111111111111011101110011101001111110010011010101001001001111110011111110011101111111111111111101110110111000111111110110101010010110111101000101111111101110111000111111011011111111101001111001011101011111000111110111111111111111111111111101111010111111111111
001000000000000000000000000010100010000000101000000000000000110000000000001000100000011100000001000010000000110100101001000010100000001000101011111000010110010000110000010000000000000101000000001000101001000101100000100000000000000000011001100110100011100000
001111101011000100000011010001000001111110101011010000100010101000000000101101100001011100010001000011101000000100010000010001100000110000000100000001000000001001010101001000001100011000110100100010011000100100100111010100110011001001000001000100011100100100
010111101010001000100100101001010000000001001101001000000011000000000010100000000011100010100010000000001000010110010101001010000000000000101111111000000100111000110010010011111111010100000110111100100100010001000001111111000000110100101110101010100100111000
000000010000001001110010011000011001100100001010010111000010001100000001010100011111100000000010111000001001110101000101000001010100001110001010000100011110010100111000000100000000100000000000100100110110111100000111111100011000001111101100111000000100011100
000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000011000000100010000000000000010000000000101000001000000001100001000001000000000000000000001000110000001100000100010000000000000000000000000000000000000000000000000000
000011101000000000000000000000000000100000000000000000000000010000000011000000000001000000000010001000000000000000010010000001100000100000000000111010000000000000011000000000000000000100000000010000000010000000000000010100100000000001000000100000000000000000
000100000010000000000000000001000000100001100001001000000000000000000000000000000010000000000000000110100001000100000000010001100010000001000001000000110100101100100000000000000000000011000000100010110001000000010000000000000000000000000001000100011100001000
110000000000000001100000000000000000000000000100000000000001001101010100110000000000000000000010100000010000000000101010000000000000110000000100111101000010010110000000000001010101000000001001111000100100000001000000000000000000000000010000000000000000010000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000100000
000000000000000000000000000000000000000000000000000000000000000000000001001000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000001000000000000000000000000010000000000000000000000000010000000000000000000000000000000000000000000000
000000000000000000000001010000000000010001000001001000000000000001010101000100011000000000000000011000000000000000000010000000000000000000000000000000000000000000000001001010101010000000001001100000100000100000000000000000100000001110010000000000000000100000
000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000011000000100010000000000000010000000000001000001000000001100001000001000000000000000000001000110000001100000000010000000000000000000000000000000000000000000000100000
000011101000000000000000000000000000100000000000000000000100010000000010001000000001000000000000001000000000000000010010000001100000000000000000111010000000010000011000000000000000000100000000010000000010000000000000010100100000000001000000100000000000000000
000100000010000000000010000001000000100001100001001000000000000000000000000000000010000000000000000010000001000100000000010001100000000001000001000000110100101100100000000000000000000011000000100010110001000000010000000000100000000000000001000100011100011000
010000000000000000000001010000000000010001000101001000000001111101011101110000011001000000000000111000010000000100100010000000000000110000001100111111000110011100110001001011111111000000001000011000000100100001000000000000000000001100010000101000000111110010
000000000000000000000000000000000000000100000000001000000000000000000000000000000000000000000011000000100010000000000000010000000000101000001000000001100001000000000000001000000000101000110000001100000000010000000000000000000000000000000000000000000000100000
000011101000000000000000000000000000100000000000000000000100010000000011001000000001000000000010001000000000000000010010000001100000100000000000111010000000010000011000000000000000000101000000010000000010000000000000010100100000000001000000100000000000000000
000100000010000000000010000001000000101001100001001000000000000000000000000000000010000000000000000110100001000100000000010001100010000001000001000000110100101100100000010000000000000011000000100010110001000000010000000000000000000000000001000100011100001000
000000000000000000000001010000000001000100100000010000000001111101001101100000000001000000000010111000010000000100101010000000000000110000001100111111000100010100110000000000000000000000000001011000000100100001000000000000000000001100010000000000000000110010
000000000000000000000000000000000000010101000001001000000000000000000000000000000000000000000010000000100010000000000000010000000000101000001000000000000000000001000000001000000000100000000000000100000000000000000000000000000000000000000000000000000000100000
000000000000000000000000000000000001000100000000000000000100010000000001001000000000000000000010001000000000000000000000000000000000100000000000000000000000010000000000000000000000000101000000010000000000000000000000000000000000000000000000000000000000000000
000000000000000000000010000000000000001000100000000000000000000000000000000000000000000000000000000110100000000000000000010000100010000000000000000000000000000000000010110000000000000111000000100010100001000000010000000000100000000000000000000000000000010000
110000000000000001100001010000000001010101100111011010000001111100011101110100011001000000000010011000010000000100101010000000000000110000001000000010000110001110110001001011111111000000001001010000000100100001000000000000100000001110010000101000000111110010
000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000010000000100000000000000000010000000000100000000000000001100001000000000000000000000000100000000000001000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000100000000000000000000100010000000001001000000001000000000010001000000000000000010010000001100000000000000000111010000000000000010000000000000000000000000000010000000000000000000000010100100000000000000000100000000000000000
000100000010000000000000000001000000100000000000000000000000000000000000000000000010000000000000000100100000000100000000010001000000000000000001000000110100101100100000000000000000000101000000000000000001000000000000000000000000000000000001000100011100001000
110000000000000000000001000000000000000000000100000000000001110000011001000000000000000000000000001000010000000000100000000000000000110000000100111101000000010110000000000011111111000000001001000000000000000001000000000000100000000000000000000000000011010010
001000000001000000000000000000000100000000000000010000000000100000000000000000000000000000000000000000000000000010000000100010000000000000001001111010000100001000000000000000000000000000000000000000000000000000000000101000000000000000000000000010100011000000
000000000000000000000010000000100000100010100000000000100010001100000000000100000100000000000000000000000000000000100000011001100000000000000010000001110000000001000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000100
000000000000000000000000000000000000000000000000000100000000000000000000000000000000000001000000000000000000000010000001100010000000000000001001111000000000010010000000000000000000000000000000001100000000000010000000000010100000000000000000000000000000100000
000000000000000000000000000000000000100010010000000001000000001100000000000000000000000000000000000000000000000000100000001001000000000000000010000000111000000100000000000000000000001000110000000000001000000000100000000000000000000000000000000000000000000000
010000000000000000000000000000000000000010000100000000100000000000000000001000000000000000010000001000000100000000000000000000000000000000000000000000000000000100000000000000000000001010110000000000000000000000000000000000000000000000000000000000000000000000
000011101000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000100001000000000000000000000000000000000000000000000000000000010000000000011000000000000000000000000000010000000000000000000000011001001010000000000000000000000
100000000100000001000000000000000000000000010000000001000000000000000000000000000000000000001000000000000001001000000000000000000010000000010000000000000000000000000000000000000000001000110000000000000000000000000000000000000000000100000000000000000000000000
000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000
001000000001000000000010010010000101000000000000010000000000100000000100000001111000011000000000000010000000010100100000000000000001000000110010000000000000001000010000000000001100000000000000000000000000000001000000101000000000000000011101001110100011000000
010100000000010000000000000000100010000010000110000000001010001110000000001100000100000000010000000001000000000000010000001000000000000000000000000000000000010000100010010011110011000001000000000000000000000000000111010100100011000000000000000001011100010100
100011010010001000110001000101010000000000000000000001000000000000010000100000000010100011001100000000000000011000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001000000000000011010000001111000010000000000000001000
000000000100100011001100100000001000000000000000000000000000000000000000000010000000000000100000000000000000000001000100000000010100000000100000000100001000000001000000000000000000000000000010000000000000000000001000000000001100110000100000010000000000000000
000000101000000000000000000100000000000000100000000000100000000000000001010000000001000000000000001100101011000000000000000100000000110001000000000000000010100010000000000000000000000110001001011111101100000010100000000000000000000000000000000000000000100000
010000101000000100000010000010000001111001010101001110000000000000000111001001111000000000010011000010101111100000000000000010000000111001100000000000000011110100001101101100001100001100111001111111110000110011000000000000000000000000010100001000000000000000
001011101001010000000000010000100000010011010001001000000100110000000100110000000000010000000001001010001001100010000000000000000011011001011000000010000011001010000001001011111111101111110000111000001011110110100000000000100000000001010000000011100011010000
110111101110010101000010000111000001010101001111111010111010001110010010101000011011011000011111011010111111011100111000010100000010001001010011000000000101000110111101001011111111111011110100101011111101101100100000010100000011111111100001101000011100001000
000000000000000000000000000000000000100000100000000000100000000000000001010000000001000000000000000000000010000000000000000100000000010000000000000000000000100000000000000000000000000110001001010111101100000010100000000000000000000000000000000000000000100000
010000101000000100000010000010000001000000000100000010000000000000000111001000100000000000010000000000101110000000000000000011000001101000100000000000000011010100001100000000001100101000111001110110100000110011000000000000000000000000010000000000000000000000
001011101001000000000000000000100000110011010001001000000100110000000100110000000000000000000001000010100001100010000000000001000010010001011000000010000010001010000001001011111111101101110000110000001011110110100000000000100000000001010000000010100011010010
100111101110010001000010000001000001010101000011011010100010001100000010101000011011011000001111011010101101001100111100010100000011001001000011000000000101000100111001001011111111111001110100101011111100100100100000010100000011111111100001101000011100001000
000000101000000000000000000010000000100000100000000000100000100000000000010000100001011000000000000100101000000000101000000000000000100000100010000000000010000010000000000000000000000100000000011000000100000000000000000000000000000000001001000110100000000000
000000000000000000000000000000000001110001000101001010000110000000000001001000111001010000010011000010000101000000000010000001000000000001000000000000000000110100000001001000001100001100110000011001110000000010000000000000000000000000000000100000000000000000
000011101000001000000000000110000000110011010001001000000000000000000000010000100000001010000000001000000000000100101000010101000011001001000100000000000001001010000001001011110011100001000000111000000011000000000000000000000000000001000011000100000000000010
010000000000011101000000000000000001000100001110010010101010110011001000001000000000111010010000001000000010010011000111101100010010000000011010000000000000000010000100000000000000001011110000000000000101001000000000000000001000000010000000010010100000000010
000000101000000000000000000010000000000000100000000000100000100000000001010000100001011000000000001100001011000000101000000000000000000000100010000000000010000000000000000000000000000100001001011111000100000000000000000000000000000000001001000110100000000000
010000000000000100000000000000000001010001000101001010000110000000000101001000111001010000010000000000010110100000000010000000000000010001000000000000000000010100000001001000001100101000110000011001110000000001000000000000000000000000010000100000000000000000
000011101000001000000000010010000000010011010001001000000000000000000000010000100000011010000000000010001000000100101000010101000011011001010100000000000001001010000001001011110011001011110000111000001011100100100000000000000000000001000011000100000000000010
100011101100011001000000000010000001000100000010010010100010110001011000101000000000111010001101001010010010001011000011101100010010100000011010000000000000000000000000000011111111001110110000000000000101001000000000000000001000001111000000010010100000000010
000000101000000000000000001000000000101000010000000100110000010000010011010000000001000000000001001100011111000010000011100000000000110000000001000010000100000001001100100100000000000110001001000011001000000000100000000000000000000000000000000000000000000000
000000101000000000000000000010000001101000011000000100000100000000000000001001100001010000000000000000011010000000000010000000000010011000100000000000000010100000000000100100000000101100000000001100000010000001000000000000000000000000000000100000000000000010
000010100000000000000000000110000000010001010001101000000001000001001000010000100000011000000000010011000011100000101010010100000010011000000000000000000000001000000001001000111100000110000000010000001000100100110000000000000000000001000001000100000000000011
000000000000011000000000000110000001000100000010110010010010110001101000101000010000011010000001100010011110000010000011100100000011101110001010000000000001000000000000000000000000111010110000000000000101000000000000000000000011110010100000000010100000000010
000000000000000000000000001100000001011101110001001100110000000000010010010000000001000000000001001000010000000010000011110100100000100001000001000011100111100011001101101100000000111110101001011100011100101001100000000000000000000000000000100000000000000000
000000101000000000000000000010000111011001011101001110000100010000000001001001101000000000010000000000000101000110010000000110000010000001101001111010000111010100010011111100001100001000110000010101110010000010000000111100100000000000000001000100011100000010
001111101011000000000010000001100001111111110011111010000100111101001000010100000110110000000000010001000010000010100010010101100001000001001000000010110001101110100001101111110000101101110000111000000011010000010000000001000000000001000000000010100011011101
001111101011010001000010000011100001000100000010110010110011111100111000001000010001011001100000101000010010000100110000010110000010000110010111111111000101011110110010010000000000110011000000011100000100000000000000000010100011110011000001101010111111100010
000000101000000000000000000100000000010101000000001000100000010000010001010000000001000000000001001000101110000000000011110100000000100001000000000001100001000001000101001000000000110110001001000000011100001000100000000000000000000000000000000000000000000000
010000100000000100000000000000000101011000011101001100000100010000000100001001111000000000010010000000000011000010000000100100000010001001000000000010000000100000000101101100001100001100000000010100010000000001000000101000000000000000010100001000000000000010
001010100001010000000010010000100001010101110001011010000101111101001000010100000100010000000000011011001010000010100010010000000011000000010000000010110000001100000001001011001111001110110000010000000000010000010000000000000000000001000000000011100011010101
111011000101010101000010000110100001000100000110110010011011111110111000101000000000011001011100110010110110001000100001110110000010000110010010000011000000001100000110010000000000111010000000011100000100000000000000000010100010101111100000000010100011100010
000000000000000000000010000000000001001000110001000100010000010000010110010000000001000000000000000000000101000000000011100100100000010000000001000000000100100011001000100100001100001110101001010100101000100001100000000000000000000000000000100000000000100000
010000101000000100000010000010000010001001010100000110000000000010000110001000100000000000010001000000101001000100010000000010000000001000111001111000000111010000011110110100111111001100111001110111100000010010000110010100100011000000010001000100011100000010
101111101011000000110000010001100000101010000010100000000101110001001100110000000010110000001101000001000011001010000010000001100001001001011000000010000011101010100000100111111111101111110100111000000001000010010000000001100000000001010000000010100011011001
110111101110010111001010000111000000010001000101101000111010001110110010001000011011011000111100010000101111001100111000010100000010001001010111111100000101010110111101001011111111110011000100001001011100100100100000010100000011111111100001101000011100001000
000000101000000000000000001100000001001101110001000100110000010000000011010000000001000000000001000100101011000010000000000000000000110001000000000010000000000000001001100100000000011010100000010011111100101011100000000000000000000000000000000000000000000000
010000000000000100000010000000000001100000001101000010000000000000000001001001111000000000010011000000000111100000000000100100000010110001000000000000000000010100000010010000001100001000110000110001100000110001000000000000000000000000000100001000000000000010
000011101000010000000000000000000000011011010011101010000101110000001000000000000110000000000000001010000001100000000000000100000010010001000000000000000000001010000001101111111111000101000000110000001011110100100000000000000000000001000000000011100011001100
100000000000010001000000000010000001000100000010010010100010000000000010100000000010011001100011101010001001000000101001110010000000000110000010000000000000000100001010000011111111111000110000100010110100000000000000010100000000001111100000000000000000001000
000000000000000000000000000000000001001101110001000100110000010000010000010000000001000000000000000000000110000000000011110100100000010000000000000011100111100001000000100100000000011110100000011100111100101011100000000000000000000000000000000000000000100000
010000101000000100000010000010000001100000001100000010000100010000000011001001100000000000010011000010101100100100010000000010000000111001101001111010000111110100011110000000001100001000111001111111110010110000000000000000000000000000000000000000000000000000
001111101011010000000010000001100000111011010011101010000101110001000100110000000000110000000001011011001011100010000010010001100010000001001000000010110010101010100001101011111111101101110000110000000011010010000000000000100000000001010000000011100011010000
111111101111010101000010000011100001010101000111011010101011111110101010101000011011011000011110011000111111001100111000010100000010001111000111111111000101011110111101001011111111111001110100101011111101101100100000010100000011111111100001101000011100001010
+59
View File
@@ -0,0 +1,59 @@
01 111100?? 00100000001000
01 1111010? 00100000001000
01 1111?0?? 00100000000100
01 1111??0? 00100000000010
01 1111?0?0 00100000000001
01 1111?100 00100000000001
01 00001111 00100000000001
01 001??110 00100000000000
01 01100100 00100000000001
01 0110010? 00100000001000
01 0100???? 00000000011100
01 1111?11? 01000100011011
01 1??????? 00000000100000
01 00???0?? 01000101000000
01 1000???? 00000100000000
01 11000?0? 00000100000000
01 110100?? 01000100000000
01 11011??? 00000100000000
01 01100?1? 00000100000000
01 011010?1 00000100000100
01 1000101? 01000001000000
01 100011?1 00000010000000
01 10001100 00000010000000
01 00???00? 01000000000000
01 10000??? 01000000000100
01 11?0000? 01000001001110
01 100011?0 00001001000001
01 00???10? 01010000000000
01 1010???? 01010000000000
01 1110?1?? 01010000001111
01 011011?? 01000000000110
01 1010?11? 00000000001110
01 001??111 10000000001010
01 110101?? 10000000000000
01 1100011? 01000110000000
01 1000100? 01000111000000
00 00110111 00100000000110
00 11110011 00100000000101
00 11111011 00100000000100
00 01110110 00100000001011
00 00111111 00100000001010
00 01?????? 10000100000000
00 11???110 10000000000000
00 10?????? 10000100000000
00 00???10? 10000101001100
00 00???110 10000001000000
00 11101101 00100000000001
00 1101?011 10000000001111
00 00??1001 00000000001101
00 00100111 10000000001010
00 0011?010 10000000000000
00 000??010 10000000000000
00 000??111 10000000000000
11 0011???? 01010110000011
11 00100??? 10000000001010
01 000??111 00000000000001
11 0001???? 01000100000000
11 00101??? 01000110000000
01 10110??? 10000000000000