# IMD CP/M Tools (VFII)

Small, self-contained CP/M file utility for VFII-style IMD images (SD Systems VersaFloppy II, CP/M 2.2). It can list files, extract/insert/delete files, and patch VFII BIOS tables inside the IMD.

## What this is

`imd_cpmtools_vfii.py` works directly on IMD images without external tools. It is tuned for a specific, common VFII CP/M 2.2 layout:

- 35 cylinders, 2 heads, 9 sectors/track, 512 bytes/sector, MFM 250kbps
- CP/M 128-byte records, 2KB allocation blocks, EXM=1
- Directory track detected automatically
- Writes IMD tracks back as uncompressed sector records (type 0x01)

If you need a fully general CP/M tool (arbitrary DPB, skew tables, >256 blocks, etc.), this script is intentionally narrower.

## Requirements

- Python 3.8+ (no external dependencies)

## Quick start

```bash
# Show geometry, inferred CP/M layout, and free space
python3 imd_cpmtools_vfii.py info disk.IMD

# List CP/M directory
python3 imd_cpmtools_vfii.py ls disk.IMD

# Extract a file
python3 imd_cpmtools_vfii.py get disk.IMD MYPROG.COM --out MYPROG.COM

# Insert or replace a file (writes a new IMD)
python3 imd_cpmtools_vfii.py put disk.IMD localfile.bin --as MYFILE.BIN --overwrite --out disk_patched.IMD

# Delete a file (writes a new IMD)
python3 imd_cpmtools_vfii.py rm disk.IMD OLDPROG.COM --out disk_pruned.IMD
```

## Commands

All commands share the `--skew` option (see "Sector skew" below).

### `info`
Show physical geometry, inferred CP/M parameters, directory location, and disk usage.

```bash
python3 imd_cpmtools_vfii.py info <image.imd> [--long] [--skew ...]
```

### `ls`
List CP/M directory entries and file sizes.

```bash
python3 imd_cpmtools_vfii.py ls <image.imd> [--skew ...]
```

### `get`
Extract a CP/M file to the host filesystem.

```bash
python3 imd_cpmtools_vfii.py get <image.imd> <CPMFILE> [--out <path>] [--skew ...]
```

### `put`
Insert or replace a local file into the CP/M directory.

```bash
python3 imd_cpmtools_vfii.py put <image.imd> <local_path> [--as NAME.EXT] [--overwrite] [--out <image.imd>] [--inplace] [--verify] [--skew ...]
```

Notes:
- Default behavior writes a new IMD named `*_patched.IMD` unless `--out` is given.
- `--inplace` updates the input IMD atomically (temp file + replace).
- `--verify` re-opens the output image and checks the stored bytes against the input file.

### `rm`
Delete a CP/M file (marks directory entries as 0xE5) and writes a new IMD.

```bash
python3 imd_cpmtools_vfii.py rm <image.imd> <CPMFILE> [--out <image.imd>] [--skew ...]
```

### `spdtab`
Show or patch VFII V2BIOS SPDTAB entries (drive class/step bits) embedded in the IMD.

```bash
python3 imd_cpmtools_vfii.py spdtab <image.imd> [--drive A|B|C|D] [--class 8|5] [--step 0..3] \
  [--target all|system|files|first] [--out <image.imd>] [--inplace] [--skew ...]
```

Behavior:
- Without `--drive`, it only reports found tables.
- With `--drive`, it patches the selected SPDTAB copies and writes a new IMD (or in-place).

### `console`
Patch console I/O port operands in VFII IMDs (SBC548N fixed offsets by default).

```bash
python3 imd_cpmtools_vfii.py console <image.imd> --data <byte> --status <byte> \
  [--from-data <byte>] [--from-status <byte>] [--scan] [--out <image.imd>] [--inplace] [--verbose] [--skew ...]
```

Notes:
- Default mode expects the SBC548N fixed offsets and validates opcode context.
- `--scan` uses a heuristic scan and may patch more bytes than intended.

## Sector skew

VFII disks often use a BIOS sector translation table (skew). The tool builds an internal RAW image in logical order and maps back to physical sector IDs when writing.

Use `--skew` to control this mapping:

- `auto` (default): heuristically detect a skew table
- `identity` / `none`: no translation
- `default` / `vfii`: use the built-in VFII 9-sector interleave if applicable
- explicit list: e.g. `--skew "1,4,7,2,5,8,3,6,9"`

You can add `--skew-verbose` to show detection scoring.

## How it works (high level)

- Parses the IMD header and track records.
- Builds a raw byte stream in logical sector order using the selected skew mapping.
- Infers the directory track and CP/M layout parameters from the raw image.
- Reads/writes CP/M directory entries and allocation blocks to implement `ls/get/put/rm`.
- Rebuilds a new IMD from the modified raw bytes, preserving original track metadata.

## Examples

```bash
# Info with skew auto-detect
python3 imd_cpmtools_vfii.py info SBC548N_vector_ZCB_serialA_04_05.IMD --skew auto --skew-verbose

# List directory
python3 imd_cpmtools_vfii.py ls SBC548N_vector_ZCB_serialA_04_05.IMD

# Extract a file
python3 imd_cpmtools_vfii.py get SBC548N_vector_ZCB_serialA_04_05.IMD V2FORMAT.COM --out V2FORMAT.COM

# Insert/replace a file (creates a new IMD)
python3 imd_cpmtools_vfii.py put SBC548N_vector_ZCB_serialA_04_05.IMD V2FORMAT_patched.COM --as V2FORMAT.COM --overwrite --out SBC548N_patched.IMD

# Put inplace (add file to IMD in-place)
python3 imd_cpmtools_vfii.py put SBC548N_MORE_SPACE.IMD mbasic.com --overwrite --inplace --verify

# Delete a file (creates a new IMD)
python3 imd_cpmtools_vfii.py rm SBC548N_vector_ZCB_serialA_04_05.IMD GWV2BIO5.ASM --out SBC548N_MORE_SPACE.IMD

# Modify SPDTAB
python3 imd_cpmtools_vfii.py spdtab SBC548N_vector_ZCB_serialA_04_05.IMD --drive B --class 8 --target system --out SBC548N_spdtabB8.IMD --skew auto

# Patch Console Ports
python3 imd_cpmtools_vfii.py console SBC548N_VANILLA.IMD --data 02 --status 03 --out SBC548N_Test_Serial_02_03.IMD --verbose
```

## Limitations

- CP/M 2.2 directory handling only (no timestamps, no user areas > 15).
- Assumes 8-bit allocation block numbers (<= 255) and 2KB blocks.
- Writes IMD sectors back as uncompressed data records.

## Files

- `imd_cpmtools_vfii.py` - main script
- `sample_commands.md` - example command lines
