Library — classic
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
open owners 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_TARGETS in libsrc/newlib/Makefile so 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).
Classic I/O patterns (from target work)
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/21 with spurious _IOUNGETC) made first getchar return NUL.
- Hybrid clib lists must not pull full newlib fcntl/stdio/threads.
- Build: classic
<stdio.h> must win include order (-I…/include before _DEVELOPMENT/common) when the hybrid needs classic stdin/stdout objects.
Cooked line input: newlib vs classic (general)
| World |
Line API |
Who echoes / edits |
| Newlib |
POSIX getline / getdelim |
console_01 (line mode, echo, BS, CR/LF cook) via tied oterm |
| Classic |
No getline |
fgets on stdin → fgets_cons (echo, DEL, optional soft cursor) |
| Classic raw |
fgetc / fgetc_cons |
No line editor — app must implement if needed |
Rules of thumb
getline is newlib-only. Never expect it on 8080/8085 classic products.
- One cook layer only. If the driver/
fgets_cons already echoes, do not also echo in app code (double echo).
- Hybrid CRTs that only bind
fgetc_cons/fputc_cons are raw. App-level line readers (e.g. shell ya_getline) are compensating for classic, not for the CPU.
- Prefer
fgets / fgets_cons on classic instead of reimplementing line edit. On serial targets, disable soft cursor if needed (CLIB_DISABLE_FGETS_CURSOR=1 — already set for rc2014-8085).
- Align dual-CPU apps (Z80 newlib + 8085 classic) at a single call site with
#ifdef, not by linking newlib stdio into 8085 images.
Dual-port FILE* vs classic ttyin macros
|
Newlib CRT |
Classic hybrid (e.g. uart85) |
| Second port |
Real drivers: m4_rc_01_input_uartb(_ttyin, …) etc. |
Often only stdin/out/err → primary UART/ACIA |
ttyin / ttyout in headers |
extern FILE * |
Classic macros → _sgoioblk[3]… slots |
| Meaning |
Instantiated streams |
Declaration/slots ≠ working UARTB console |
fgetc on classic special-cases stdin → fgetc_cons. Assigning input = ttyin does not create a second cooked port unless the CRT initialises that slot and a driver path exists. For dual-port on hybrid: either an active-console global in fgetc_cons, or real second-stream CRT work — do not copy newlib’s input = ttyin pattern blindly.
CP/M IOBYTE seeds (firmware shells)
Shell may seed bios_iobyte before handing off to CCP; BIOS copies it to page-0 IOBYTE.
- CON is low 2 bits (CRT vs TTY, etc.).
- Hardware-specific high bits (e.g. 8085 module LST → SOD) may require seeds like
0x81 / 0x80, not bare 1 / 0. Match the BIOS list/const decode, not “Z80 values”.
Agent rules
- Classic 8080/8085 images must never pull newlib objects (Z80 opcodes / conventions).
- Isolation is list ownership (
*.lst), never broad globs over mixed trees.
- Line input:
fgets → fgets_cons; no getline.
- Runtime:
libsrc/l/sccz80/7-8085/, 8-8080/, 8-gbz80/, … → crt0 libs in lib/clibs/.
Related
- Newlib world:
library-newlib
- Layout:
style-libsrc-layout
- Targets:
target-cpm, target-rc2014; host TIMER / suites use +test
1---2name: library-classic3description: z88dk classic library world: libsrc/target and classic trees, multi-CPU (8080/8085/gbz80/…), fgets_cons line input, hybrid CRT traps, isolation from newlib. Use when working on classic clib, 8085 products, or hybrid consoles.4---56# Library — classic78## 1. Two library worlds (do not blur)910| World | Home | CPUs | Typical product |11|-------|------|------|-----------------|12| **Classic** | `libsrc/target/<name>/` (historic fcntl/stdio/gfx) + `libsrc/classic/` | Z80, IXIY, Z180, **8080**, **8085**, gbz80, … | `*_clib.lib`, `cpm8085_clib.lib`, … |13| **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` |1415**Hard rules**16171. Do **not** merge classic and newlib **stdio cores** or **fcntl `open` owners** in one link without a designed bridge.182. Prefer sharing **device / thin driver** layers, not cores.193. **CLIB** selects newlib; machine **SUBTYPE**s usually stay classic-owned (esp. CP/M’s 150+ machines).204. After a path move, put the target name in `MIGRATED_TARGETS` in `libsrc/newlib/Makefile` so builds use `../target/<name>`.2122**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).2324---2526## Classic I/O patterns (from target work)2728### Hybrid classic+newlib consoles (rc2014-8085 lesson)2930When a CRT mixes **classic** `fgetc_cons`/`fputc_cons` with newlib-style startup:3132- FILE init flags must match classic expectations (**`18` / `20`** = `_IOSYSTEM|_IOREAD` / `_IOWRITE`).33- Wrong flags (`19`/`21` with spurious `_IOUNGETC`) made first `getchar` return NUL.34- Hybrid clib lists must **not** pull full newlib fcntl/stdio/threads.35- Build: classic `<stdio.h>` must win include order (`-I…/include` **before** `_DEVELOPMENT/common`) when the hybrid needs classic `stdin`/`stdout` objects.3637### Cooked line input: newlib vs classic (general)3839| World | Line API | Who echoes / edits |40|-------|----------|--------------------|41| **Newlib** | POSIX **`getline` / `getdelim`** | **console_01** (line mode, echo, BS, CR/LF cook) via tied oterm |42| **Classic** | **No `getline`** | **`fgets` on stdin → `fgets_cons`** (echo, DEL, optional soft cursor) |43| **Classic raw** | `fgetc` / `fgetc_cons` | **No** line editor — app must implement if needed |4445**Rules of thumb**46471. **`getline` is newlib-only.** Never expect it on 8080/8085 classic products.482. **One cook layer only.** If the driver/`fgets_cons` already echoes, do **not** also echo in app code (double echo).493. Hybrid CRTs that only bind `fgetc_cons`/`fputc_cons` are **raw**. App-level line readers (e.g. shell `ya_getline`) are compensating for classic, not for the CPU.504. Prefer **`fgets` / `fgets_cons`** on classic instead of reimplementing line edit. On serial targets, disable soft cursor if needed (`CLIB_DISABLE_FGETS_CURSOR=1` — already set for `rc2014-8085`).515. Align dual-CPU apps (Z80 newlib + 8085 classic) at a **single call site** with `#ifdef`, not by linking newlib stdio into 8085 images.5253### Dual-port FILE* vs classic `ttyin` macros5455| | Newlib CRT | Classic hybrid (e.g. `uart85`) |56|--|------------|--------------------------------|57| Second port | Real drivers: `m4_rc_01_input_uartb(_ttyin, …)` etc. | Often **only** stdin/out/err → primary UART/ACIA |58| `ttyin` / `ttyout` in headers | `extern FILE *` | Classic macros → **`_sgoioblk[3]`…** slots |59| Meaning | Instantiated streams | **Declaration/slots ≠ working UARTB console** |6061`fgetc` on classic special-cases **stdin** → `fgetc_cons`. Assigning `input = ttyin` does **not** create a second cooked port unless the CRT initialises that slot and a driver path exists. For dual-port on hybrid: either an **active-console** global in `fgetc_cons`, or real second-stream CRT work — do not copy newlib’s `input = ttyin` pattern blindly.6263### CP/M IOBYTE seeds (firmware shells)6465Shell may seed **`bios_iobyte`** before handing off to CCP; BIOS copies it to page-0 IOBYTE.6667- CON is **low 2 bits** (CRT vs TTY, etc.).68- Hardware-specific high bits (e.g. 8085 module **LST → SOD**) may require seeds like **`0x81` / `0x80`**, not bare `1` / `0`. Match the BIOS `list`/`const` decode, not “Z80 values”.6970---7172## Agent rules73741. Classic **8080/8085** images must never pull newlib objects (Z80 opcodes / conventions).752. Isolation is **list ownership** (`*.lst`), never broad globs over mixed trees.763. Line input: **`fgets` → `fgets_cons`**; no `getline`.774. Runtime: `libsrc/l/sccz80/7-8085/`, `8-8080/`, `8-gbz80/`, … → crt0 libs in `lib/clibs/`.7879## Related8081- Newlib world: `library-newlib`82- Layout: `style-libsrc-layout`83- Targets: `target-cpm`, `target-rc2014`; host TIMER / suites use `+test`