SPLIT-i + ALPHA-DOS の中身を眺めたかったのですが、あいにく手元にPC-8801実機がなく、エミュレータを(合法的に)動かすのも結構ハードルが高そう。
仕方がないのでバイナリを直接眺めていたら何となく構造がわかったので、突貫でバラすプログラムを作ってみた。
d88やALPHA-DOSの仕様をちゃんと調べたわけではないので、他では使えないと思います。あと、BASICのプログラムは、シングルクォートのコメント以外非対応です。
Python 3.6以降なら動くと思います。その場にあるSPLIT-i 2014.d88
を読んで、勝手にAlpha
というフォルダを作ってそこにファイルを作ります。
import os
OUT_DIR = 'Alpha'
D88_HEADER = 0x2B0
SECTOR_INFO = 0x10
SECTOR_BODY = 0x100
SECTOR = SECTOR_INFO + SECTOR_BODY
ALPHA_DOS_INFO = 0x25000
ALPHA_DOS_SYSTEM = 0x3000
ENCODING = 'shift_jis'
with open('SPLIT-i 2014.d88', 'rb') as f:
d88 = f.read(-1)
d88 = d88[D88_HEADER:]
raw = bytes()
for i in range(0, len(d88), SECTOR):
raw += d88[i + SECTOR_INFO:i + SECTOR]
offset = ALPHA_DOS_INFO
os.makedirs(OUT_DIR, exist_ok=True)
with open(os.path.join(OUT_DIR, 'ALPHA_DOS.BIN'), 'wb') as f:
f.write(raw[:ALPHA_DOS_SYSTEM])
current_address = ALPHA_DOS_SYSTEM
while True:
if len(raw) < offset + 0x10 or raw[offset] == 0xFF:
break
base = raw[offset:offset + 6].rstrip().decode(encoding=ENCODING)
suf = raw[offset + 6:offset + 9].rstrip().decode(encoding=ENCODING)
name = base + '.' + suf if suf != '' else base
typ = raw[offset + 9]
if typ == 0xFF:
break
block = raw[offset + 10]
address = block * 0x800
if address < current_address:
print(f'! Overrun detected ({address:X} < {current_address:X})')
current_address = address
tmp = raw[address:]
if typ == 0x01:
start = int.from_bytes(bytes=tmp[0:2], byteorder='little')
end = int.from_bytes(bytes=tmp[2:4], byteorder='little')
size = end - start
tmp = tmp[4:4 + size]
print(f'{name}: Binary 0x{start:04X}-0x{end:04X} (size 0x{size:04X})')
with open(os.path.join(OUT_DIR, name), 'wb') as f:
f.write(tmp)
current_address += 4 + size
elif typ == 0x80:
print(f'{name}: Basic Text')
with open(os.path.join(OUT_DIR, name), 'w') as f:
p = 0
while True:
eol = int.from_bytes(bytes=tmp[p:p + 2], byteorder='little')
p += 2
if eol == 0:
break
eol -= 2
if tmp[eol] != 0:
print(f'! {name}: Unexpected EOL 0x{tmp[eol]:02X} at {address + eol:X}.')
break
number = int.from_bytes(bytes=tmp[p:p + 2], byteorder='little')
print(f'{number} ', end='', file=f)
p += 2
line = tmp[p:eol]
if line[:3] == b'\x3A\x8F\xE9':
print(f"'{line[3:].decode(encoding=ENCODING)}", file=f)
else:
print('(SOME BASIC STATEMENT)', file=f) # NOT SUPPORTED
p = eol + 1
current_address += p
else:
print(f'! {name}: Unknown type 0x{typ:02X}.')
offset += 0x10
(実は既に良いツールがある、というオチはありそう。)