Z88dk
Skills for Agents to code 8085 Assembly Language
npx -y skills add feilipu/8085-skills --skill z88dkAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 23 days oldThe repository was created 23 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
z88dk newlib vs classic architecture for targets, CRT m4 driver instantiation, serial/character FILE* wiring, disk fcntl (asm_target_open, open_max, FCB vs FatFs), mixed multi-CPU trees, and target_io / ticks verification. Use when migrating targets, adding serial or disk drivers, debugging fopen/open link errors, dual-stack file I/O, CP/M stdio devices, or reviewing CRT/config lists. Complements z88dk-tooling (measure) and extended-usage (8085 codegen).
SKILL.md
11.6 KB, ~3.4k tokens by cl100k_base, as published. Nobody here has run it
z88dk target I/O architecture (newlib + classic)
General lessons from migrating hardware targets and enabling newlib CP/M file I/O. Measurement stays in z88dk-tooling. 8085 codegen stays in extended-usage / opcode-reference.
Assume a built tree with bin/ on PATH and ZCCCFG → lib/config.
1. Two library worlds (do not blur)
| World | Home | CPUs | Typical product |
|---|---|---|---|
| Classic | libsrc/target/<name>/ (historic fcntl/stdio/gfx) + libsrc/classic/ | Z80, IXIY, Z180, 8080, 8085, gbz80, … | *_clib.lib, cpm8085_clib.lib, … |
| Newlib | Was libsrc/newlib/target/<name>/; migrated → libsrc/target/<name>/ beside classic | Z80-class (-clib=new / sdcc_ix / sdcc_iy) | lib/clibs/{sccz80,sdcc_ix}/<target>.lib |
Hard rules
- Do not merge classic and newlib stdio cores or fcntl
openowners in one link without a designed bridge. - Prefer sharing device / thin driver layers, not cores.
- CLIB selects newlib; machine SUBTYPEs usually stay classic-owned (esp. CP/M’s 150+ machines).
- After a path move, put the target name in
MIGRATED_TARGETSinlibsrc/newlib/Makefileso builds use../target/<name>.
Mixed tree hazard: when newlib Z80+ sources land under libsrc/target/cpm/ next to classic multi-CPU code, isolation is list ownership (*.lst), never broad globs. Classic 8080/8085 images must never pull newlib objects (Z80-only opcodes / calling conventions).
2. Serial / character FILE* instantiation (newlib)
Layers
stdio (printf / FILE*)
→ console_01 (line-edited terminals; default on many CRTs)
→ character_00 (thin byte streams; good for multi-port + RDR/PUN/LST)
→ device (UART/SIO/ACIA/ASCI/HBIOS/BDOS CON…)
| Layer | Typical path |
|---|---|
| stdio core | libsrc/newlib/stdio |
| character_00 | libsrc/newlib/drivers/character/ |
| console_01 | libsrc/newlib/drivers/terminal/console_01/ |
| Target terminals | libsrc/target/<t>/driver/terminal/*.m4 + .asm |
| Devices | libsrc/target/<t>/device/… |
Defaults: most hardware CRTs still instantiate full console_01 / rc_01_* terminals. Thin character_00 is the additive multi-port pattern (keep m4_file_dup / optional crt_driver_instantiation.asm.m4).
CRT m4 wiring (where FILEs are born)
Startup *_crt_N.asm.m4 includes driver m4 macros inside:
clib_instantiate_begin.m4
m4_<driver>(_stdin, …)
m4_<driver>(_stdout, …)
m4_file_dup(_stderr, 0x80, __i_fcntl_fdstruct_1) ; often dup of stdout
… extra ports …
clib_instantiate_end.m4 ; builds fdtbl + FILE freelist + stdio heap
Each static driver m4 typically:
- Allocates a FILE + FDSTRUCT on the stdio heap sections.
- Pushes an entry into the fd table body.
- Chains a heap block header (
__i_fcntl_heap_N).
Multi-port and dups
| Pattern | Mechanism |
|---|---|
| Second console / teletype | Second input+output terminal pair → ttyin / ttyout; ttyerr = m4_file_dup of ttyout (same idea as stderr) |
| stderr | Almost always a dup of stdout’s FDSTRUCT (flag 0x80) |
| Extra static slots | m4_file_absent or more drivers |
Declared in newlib stdio.h even when a CRT does not instantiate them: stdrdr, stdpun, stdlst, ttyin, ttyout, ttyerr. Missing instantiation ≠ missing declaration — apps that reference an uninstantiated FILE* will fail at link or runtime.
CP/M character model (portable apps vs implementations)
Physical BDOS units (what drivers usually call):
| Unit | BDOS | Typical newlib FILE* |
|---|---|---|
| CON | 1/2/6/… | stdin / stdout / stderr |
| RDR | 3 | stdrdr |
| PUN | 4 | stdpun |
| LST | 5 | stdlst |
Logical names (CRT, TTY, LPT, PTR, PTP, BAT, U*) are selected by IOBYTE (page-0 $0003, BDOS 7/8). BIOS maps logical → physical UART/device.
| Audience | What to wire |
|---|---|
| CP/M implementation (e.g. CP/M-IDE) | CRT maps stdin/tty* to real ports; shell seeds IOBYTE; ASM BIOS interprets IOBYTE |
CP/M application (+cpm -clib=new) | BDOS only; FILE* + optional logical-name helpers; no UART registers |
Do not assume fopen("TTY:") is how implementations work — FILE selection + IOBYTE seed* is the real dual-port pattern.
Hybrid classic+newlib consoles (rc2014-8085 lesson)
When a CRT mixes classic fgetc_cons/fputc_cons with newlib-style startup:
- FILE init flags must match classic expectations (
18/20=_IOSYSTEM|_IOREAD/_IOWRITE). - Wrong flags (
19/21with spurious_IOUNGETC) made firstgetcharreturn NUL. - Hybrid clib lists must not pull full newlib fcntl/stdio/threads.
3. Disk / fcntl instantiation (newlib)
Open path
open / creat / fopen
→ asm_vopen
→ asm_target_open_p1 ; validate path; return EXTRA bytes for FDSTRUCT
→ heap_alloc(sizeof header + EXTRA) from __stdio_heap
→ asm_target_open_p2 ; fill FDSTRUCT; install JP to driver
Target must provide asm_target_open_p1 and asm_target_open_p2 (e.g. CP/M FCB driver cpm_01_file). If missing → link error:
undefined symbol: asm_target_open_p1
That is the classic newlib “stdio disk I/O missing” symptom (#3022-class), not a compiler bug.
CRT knobs that make or break open / fopen
Set in target crt_config.inc (TAR__clib_*):
| Knob | Role | Failure mode if wrong |
|---|---|---|
open_max | Size of fd table (static FDs + dynamic opens) | open_max=0 → only static fds; open() ENFILE / no room |
stdio_heap_size | Heap for FDSTRUCTs (FCB driver ~192 B each incl. 128 B sector buf) | Too small → heap_alloc fails on open |
fopen_max | Max FILE structures | Must be > static FILE count or freelist stays empty → fopen EMFILE even when open works |
Rule of thumb for CP/M-class newlib CRTs with 6 static streams (stdin…stdlst) + user files:
open_max = 16stdio_heap_size = 1024fopen_max = 10(or any value greater than static FILE count)
Dual-stack policy (when both exist)
| API | Backend |
|---|---|
Unprefixed open / read / write / lseek / close | Host / OS file driver (e.g. CP/M BDOS FCB) |
ChaN f_* | FatFs + target diskio (raw media) |
printf / console FILE* | Character/terminal drivers |
f_*is never an alias for FCB fcntl. Volumes stay independent.- Plain
+cpm -clib=new: BDOS FCB only is enough — no FatFs, no physicaldiskio. - Hardware
-subtype=cpm: FCB by default; optional-lffdual-stack.
One open owner per binary: do not mix classic libsrc/target/cpm/fcntl objects with newlib cpm_01_file in the same link.
Library list / rebuild traps
-
Driver must appear in the target
library/*_sccz80.lstchain (often viadriver/driver.lst). -
Newlib
Makefileoften depends only onconfig_private.inc— lst/source adds do not always rebuild. Force:rm -f lib/clibs/sccz80/<target>.lib lib/clibs/sdcc_ix/<target>.lib make -C libsrc/newlib <target> -
Prove the symbol is in the lib:
z88dk-z80nm lib/clibs/sccz80/<target>.lib | rg 'asm_target_open|cpm_01_file' -
Prove the app linked it:
rg 'cpm_01_file|asm_target_open|__fcntl_fdtbl_size' app.map
4. Testing I/O (test/suites/target_io)
Shared serial + disk suite for z88dk-ticks.
| File | Role |
|---|---|
io_tests.c | printf/scanf + creat/write/read/lseek/close/multi-fd |
fcntl_native.c | Native open/creat/… (CP/M BDOS / newlib FCB) |
fcntl_host.c + ticks_host_fcntl.asm | Host SYSCALL files (targets without OS fcntl) |
Makefile | Per-product recipes |
Design rules
- Shared tests call only
tio_*(io_port.h) — backends swap. - Classic CP/M breadth: default subtype only (
+cpmz80 /+cpm -clib=8085). Do not fan out to 150+ machine subtypes in this suite. - Newlib gates: plain
+cpm -clib=new(Z80) and hardware+… -subtype=cpm -clib=newwhere dual-stack FCB applies. Newlib CP/M is not an 8085 product — 8085 stays classic default CLIB. - Extend serial when CRTs expose more streams: RDR/PUN/LST (
stdrdr/stdpun/stdlst), latertty*if instantiated. - Extend disk when drivers claim flags: keep lseek (SET/END + overwrite); add
fopen/fread/fwritefor newlib stdio path; optional O_TRUNC/O_APPEND if implemented. - FatFs
f_*is a separate optional gate on hardware packages — not required for plain+cpm.
Run pattern
make -C test/suites/target_io # all recipes
make -C test/suites/target_io test_rc2014_cpm.com
# scanf tests need piped input (Makefile uses SCANF_INPUT)
CP/M outputs need .com for ticks CP/M mode; some newlib links produce *_CODE.bin that must be copied to .com.
What “green” means
- Suite:
N run, N passed, 0 failed - Map proof for newlib disk: driver +
__fcntl_fdtbl_size/open_max/ heap as expected - Classic default Z80 + 8085 still pass after mixed-tree moves (isolation)
5. Config / CRT pipelines (quick map)
| Pipeline | When | Outputs |
|---|---|---|
| Config m4 | library build | config_*_{private,public}.inc, config_*.h |
| CRT m4 | each zcc +target link | expand *_crt.asm.m4 + startup + drivers |
- Modes:
CFG_ASM_DEF/CFG_ASM_PUB/CFG_C_DEF. - zcc maps startup →
__STARTUP, pragmas →M4__*,-Itarget home +src/m4. - Edit only the CLIB lines that point at newlib CRT/lib paths when migrating; leave classic SUBTYPE lines alone unless intentional.
6. Agent checklist (new serial or disk work)
Serial
- Driver class:
character_00vsconsole_01(match peers) - CRT m4 instantiates FILE* + FDSTRUCT; dups for err streams
- Public
stdio.hnames match what the CRT actually builds - Multi-port: second triple uses
tty*+m4_file_dupfor err - Hybrid classic console: FILE flags and list isolation
Disk
-
asm_target_open_p1/_p2in target lib (nm proof) -
open_max,stdio_heap_size,fopen_maxsized for static + dynamic use - One
openowner; dual-stack docs if FatFs also present - Forced lib rebuild after lst changes; app map shows driver
Test
-
target_iorecipe for the product (native vs host fcntl) - Classic CP/M: default subtype only unless a specific machine is in scope
- Extend serial/disk cases only where the CRT/driver supports them
- ticks CPU model (
-m8085when relevant)
Related
- Host measurement / ticks / maps / copt: z88dk-tooling
- 8085 coding / stack rules: extended-usage
- Opcode map: opcode-reference
- Upstream: https://github.com/z88dk/z88dk
- Example dual-stack notes:
libsrc/_DEVELOPMENT/EXAMPLES/z80/stdio_target/readme.md - Suite:
test/suites/target_io/
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.