bl791/IFDB / infocom /tools /interl5.py
bl791's picture
download
raw
3.61 kB
# SPDX-FileCopyrightText: 2025 Jeff Epler
#
# SPDX-License-Identifier: GPL-3.0-only
import sys
import pathlib
if len(sys.argv) != 4:
raise SystemExit(f"Usage: interl5.py stub.bin filename.z5 filename.dsk")
with open(sys.argv[1], "rb") as f:
stub = f.read()
with open(sys.argv[2], "rb") as f:
zcode = f.read()
if len(stub) != 16384:
raise SystemExit(f"stub {sys.argv[1]} has unexpected size (expected 16384, got {len(stub)})")
def make_gcr():
for i in range(128):
b = f"{i:07b}" # All these tests apply to the low 7 bits
if '000' in b: continue # 3 consecutive zeros disallowed
if b.count('00') > 1: continue # only one pair of consecutive 0s allowed
if not '11' in b: continue # one pair of consecutive 1s required
yield i | 128 # top bit is always a 1
gcr = list(make_gcr())
twobit_count = 86
oneside = 35*16
interleave = [0, 7, 0xe, 6, 0xd, 5, 0xc, 4, 0xb, 3, 0xa, 2, 0x9, 1, 8, 0xf]
def togcr(trackno, data):
result = bytearray(b"\xff" * 6656)
index = 0
def put(*values):
nonlocal index
for value in values:
result[index] = value
index += 1
put(0xd5, 0xaa, 0xad)
# 3/4 = gcr4,4 encoding of 0-based track number
put((trackno >> 1) | 0xaa, trackno | 0xaa)
# Now, 18 times: 86 'twobit' + 256 'sixbit' areas
for s in range(18):
checksum = 0
d = data[s*256:(s+1)*256+2] + b'\0\0'
print(d[:2], len(d))
for i in range(256 + twobit_count):
if i < twobit_count:
tmp = d[i]
value = ((tmp & 1) << 1) | ((tmp & 2) >> 1)
tmp = d[i + twobit_count]
value |= ((tmp & 1) << 3) | ((tmp & 2) << 1)
j = i + 2 * twobit_count
tmp = d[j]
value |= ((tmp & 1) << 5) | ((tmp & 2) << 3)
# C implementation of interlz5 has inconsistent behavior for
# the last 2 bits which makes it difficult to exactly reproduce
else:
value = d[i - twobit_count] >> 2
checksum ^= value
put(gcr[checksum])
#put(value)
checksum = value
put(gcr[checksum])
# Remainder pre-filled with 0xff already!
return result
empty_block = b"\0" * 256
disk1 = {}
disk2 = {}
def put_linear_sector(blocks, l, data):
print("pld", l, data[:2])
if len(data) < 256:
data = [data + empty_block][:256]
blocks[l] = data
for i in range(64):
put_linear_sector(disk1, i, stub[i*256:(i+1)*256])
side1_limit = 394
for i in range(len(zcode)//256):
if i < side1_limit:
l = 64 + (i & 0xff0) + interleave.index(i & 0xf)
put_linear_sector(disk1, l, zcode[i*256:(i+1)*256])
else:
l = i - side1_limit
print("sideb", l)
put_linear_sector(disk2, l, zcode[i*256:(i+1)*256])
with open(sys.argv[3], "wb") as f:
for i in range(oneside):
f.write(disk1.get(i, empty_block))
if disk2:
print(disk2.keys())
sidea = pathlib.Path(sys.argv[3])
sideb = sidea.with_stem(sidea.stem.removeprefix("-sidea") + "-sideb").with_suffix(".nib")
with open(sideb, "wb") as f:
for i in range(35):
trkdata = b"".join(disk2.get(i * 18 + j, empty_block) for j in range(19))
f.write(togcr(i, trkdata))
with open(sideb.with_suffix(".raw"), "wb") as f:
for i in range(35):
trkdata = b"".join(disk2.get(i * 18 + j, empty_block) for j in range(19))
f.write(trkdata)

Xet Storage Details

Size:
3.61 kB
·
Xet hash:
307817a8a72ea3aff1c29ac74e3e94050d2315da4dc01b1748214e4e3ed1c89c

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.