Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 238 additions & 0 deletions .ai/CONVERSATION.md

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions .ai/PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Nextor boot menu specification

## The problem

There are several keys that a Nextor user can press while booting in order to modify the boot behavior: slot keys to prevent specific Nextor kernels from booting (a key per slot number); and numeric keys for behavior like e.g. booting in DOS 1 mode or directly to BASIC.

This is confusing as the user needs to remember several keys and do some "gymnastics" if he wants to press several keys at once. So this is a proposal for a more user-friendly equivalent mechanism.

## The Nextor boot menu

The idea is that right when a Nextor 3 kernel boot sequence starts, and as soon as it detects that it is the first kernel in the system (or it's taking over a Nextor 2 or a MSX-DOS kernel) and if the user is pressing the N key, it displays a boot menu similar to this:

```
Nextor 3.0.0 boot menu
----------------------------------------

* R. MegaFlashROM SCC+ SD in slot 1-3
* S. Kernel with a vey lo... in slot 2-1
* Q. ...
* W. (no name) in slot 1-0
* E. ...
N. Disable all and boot

0. Disable permanent disk emulation
1. Boot in MSX-DOS 1 mode
2. Boot in MSX-DOS 1+R800 ROM mode
3. Boot in MSX-BASIC
4. Boot in R800 ROM mode
5. Reduced drive allocation mode
* 6. Single FDD drive (CTRL)
7. Disable MSX-DOS kernels (SHIFT)

---------------------------------------
ESC = Cancel, ENTER = Apply and boot
```

where the first half consists of all the Nextor 3 kernels present in the system, enabled (prepended by "*") by default; and the second half is the state of the numeric boot keys, by default those that have their bit set to 1 in KEYS_INV_0/1 in init.mac.

Thus the high level sequence of events would be:

1. The Nextor kernel detecting that it's the (new) master and that the N key is being pressed initializes the screen in text mode (40 columns in MSX1, 80 columns otherwise).
2. The Nextor kernels are detected by scanning all the existing slots (more on that later) and the name of each is requested via the device query routine.
3. All the kernel names and slots are displayed, together with their assigned slot disable key, and with a "*" indicating that in principle the kernel will boot normally.
4. All the numeric boot modification keys are shown (except 2 and 4 in non-Turbo-R computers). An asterisk is shown for the keys that are inverted according to KEYS_INV_0/1 in init.mac.
5. The kernel waits for the user to release the N key and waits for other key pressings.
6. If one of the keys shown is pressed (slot key or numeric key) the corresponded entry is toggled.
7. If the user presses ESC, the menu disappears and the boot proceeds normally, discarding any changes. It's as if the menu hadn't been shown.
8. If the user presses ENTER, the enabled entries are collected and the BOOTKEYS variable is set appropriately, including the NEXTOR_BOOT_KEYS signature. Then the menu disappears and the boot procedure continues.
9. If the user presses N, it's as when pressing ENTER, except that ALL the Nextor kernels are disabled. Thus an easy(ish) wait to disable all Nextor kernels is: press N, wait for the menu, release, press again.
10. The registered keys influence the boot procedure of all kernels as if the keys had been physically pressed or if the one-time boot keys mechanism had been used.

This is practical for one-off unusual boots, and also as a memory aid for users to remember which key does what without having to look for documentation.

## Technical details, nuances and challenges

- The menu needs to be shown before any Nextor driver has been initialized. Therefore all the existing slots need to be examined at that point in search for Nextor 3 kernels (there's no KERNEX table built yet). This implies that we need to put a short signature (like "NEXTOR3") at a reachable location in all the ROM pages of the Nextor kernel. The first 256 bytes page (dosehad.mac) seems like a good place, but that area is already quite cramped so some optimization work might be needed first.

- Theorically a MSX computer can have up to 16 slots (if all four main slots are extended), but the detection procedure can stop as soon as five kernels are detected: it's extremely unlikely that any real system will have more Nextor kernels, and only four are supported anyway given the current architecture of Nextor. Also this allows the full kernels list and the numeric keys list to fit in the screen.

- An interesting case is that the main kernel (the one showing the menu) can be itself disabled via the boot menu. But then there can be another Nextor kernel located in a higher slot, which hasn't been disabled. This one will become the effective master but it must NOT show the menu again, so some in-memory flag is probably needed for that.

- Drivers must support the "Get driver information string" driver query (and the "Get driver version number" query, for possible future enhancements of the boot menu) WITHOUT the "Initialize driver" query having been executed first. This needs to be very clearly documented.

- The boot menu layout needs to support 40 columns and 80 columns for MSX1 and MSX2/2+/Turbo-R. This implies adjustments on how the top and bottom lines are centered, the length of the hyphens lines, and the maximum string length provided to the driver when querying its name (and if the driver says that the name is truncated, "..." should be shown after it).

- Related to the above: in 40 columns mode the "in slot X[-Y]" text could be shortened to "in X[-Y]" so we can display five more characters of the driver name.

- Another interesting case: Nextor 3.0 boots and shows the menu, then later on a hypothetical Nextor 3.1 boots and becomes the new master. In this case too, care must be taken so the menu is shown only once. Also: Nextor 3.1 might have a newer version of the code that shows the menu, but it's the 3.0 kernel the one that needs to show it, because otherwise it wouldn't be possible for it to disable itself (not ideal but acceptable).

- For extra coolness we could temporarily redefine the asterisk character like a checkmark, but let's worry about that once a working implementation of the menu is in place.

- This needs to be compatible with the mechanism to disable Nextor 2 kernels that was implemented in https://github.com/Konamiman/Nextor/pull/193 .

## Additional information

- source/kernel/drivers/StandaloneASCII8/driver.mac for the structure of the Nextor 3 drivers.
- https://github.com/Konamiman/Nextor/blob/v2.1/docs/Nextor%202.1%20User%20Manual.md for the one-time keys configuration tool and the boot keys reference.
- https://github.com/Konamiman/Nextor/blob/v2.1/docs/Nextor%202.1%20Programmers%20Reference.md for the technical details on how the one-time boot keys works (section 7).
- https://github.com/Konamiman/MSX2-Technical-Handbook/blob/master/md/Appendix1.md and https://github.com/Konamiman/MSX2-Technical-Handbook/blob/master/md/Appendix4.md for the MSX BIOS and work area variables and buffers.

## Task for you

Validate the idea and the design. Is there something important I haven't taken in account? Can you suggest improvements or simplifications? Do you have questions?

162 changes: 162 additions & 0 deletions .ai/SESSION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Nextor Boot Menu - Design Review Session

## Date: 2026-02-08

## Context

Review and validation of the boot menu design described in `.ai/PLAN.md`. No code was written - this was a pure design discussion session.

## The Design (Summary from PLAN.md)

When a Nextor 3 kernel boots and detects it's the master, if the user is pressing the N key, it displays an interactive boot menu showing:
- All detected Nextor 3 kernels (with names from driver query) and their toggle keys
- Numeric boot key options (0-5 plus CTRL=6, SHIFT=7)
- ESC to cancel, ENTER to apply, N to disable all kernels and boot

## Key Design Decisions Made

### Signature placement
- "NXT3\0" signature already placed at 407Bh in doshead.mac (5-byte gap between `jp BIOS_IN##` at 4078h and RAMENT at 4080h)
- Avoids using 400Ah-400Fh reserved bytes (MSX standard says those should be zero)
- Slot scanning uses RDSLT to check for "NXT3" at 407Bh - safe, read-only operation

### One-time boot keys as the anti-re-display mechanism
- After the menu is shown, RAM keys (at A100h) are ALWAYS written for all three exit paths (ENTER, N, ESC), with the N bit cleared
- Subsequent kernels' `SCANKEYS_RAM` picks these up, never sees N, never triggers the menu
- No separate "menu already shown" flag is needed - the mechanism is self-consistent
- For ESC: write RAM keys = current BOOTKEYS with N bit cleared (preserves all other key states)
- For ENTER: write RAM keys = user's toggled selections with N bit cleared
- For N (disable all): write RAM keys = all slot disable keys set, N bit cleared

### Programmatic RAM keys (NEXBOOT.COM)
- If RAM keys already exist at A100h when booting (set by NEXBOOT.COM or similar), the menu is NEVER shown, even if those RAM keys have N set
- Rationale: programmatic boot keys imply the user knows exactly what boot configuration they want
- N-in-RAM-keys continues to mean "disable all kernels" the old way

### DISABLE_KEY modification
- Current `DISABLE_KEY` checks N first (disables all kernels) then per-slot keys
- New design: split the N check out of `DISABLE_KEY`, so DISABLE_KEY only checks per-slot keys
- N key triggers the menu instead of directly disabling
- After menu updates BOOTKEYS, DISABLE_KEY is re-run to check if the current kernel was disabled by the user's selections

### Init flow for the menu
```
CHK_DUP → DO_KEYS_INIT → DISABLE_KEY (per-slot only) → CHK_DRIVER →
DISKID check → [if master: reach OVERRIDE] →
OVERRIDE: set LINL40, call INITXT →
[if N pressed AND keys came from keyboard (not RAM): SHOW_MENU, update BOOTKEYS, write RAM keys] →
[re-run DISABLE_KEY with updated BOOTKEYS] →
continue normal OVERRIDE (set DOS_VER, NXT_VER, H.RUNC hook) → SLAVE (driver init)
```

The menu is shown AFTER INITXT (screen is ready) and AFTER CHK_DRIVER (own driver validated), but BEFORE driver initialization.

### Screen initialization
- The existing INITXT call at OVERRIDE (line 1032-1039) already sets 40/80 columns based on MSXVER
- The menu check is inserted right after INITXT, before version/hook setup
- The CLS at line 893 (first cartridge path) becomes redundant but harmless

### Korean MSX gotcha
- From `PrintRuler()` in fdisk.c: Korean MSX computers do weird things when printing at the last screen column
- Check if H_CHPH (FDA4h) != 0xC9 (hooked); if so, print separator lines with `width - 1` characters
- The boot menu's separator/ruler lines must implement this same check

### "(BAD DRIVER)" handling
- For the scanning kernel itself: CHK_DRIVER runs before the menu and halts on failure, so the scanning kernel always has a valid driver
- For other kernels found during scanning:
1. RDSLT to check "NXT3" at 407Bh (safe)
2. Try DRVQ_GET_STRING via CALSLT+CALDRV to get driver name
3. If query returns QUERY_OK or QUERY_TRUNCATED_STRING: display the name
4. If query returns anything else: display "(BAD DRIVER)"
- A kernel shown as "(BAD DRIVER)" is locked as disabled (no asterisk, toggle ignored)
- Risk of crash from corrupt ROM accepted as unlikely (NXT3 signature implies properly built kernel)

### Dead code cleanup
- The commented-out code at init.mac lines 1046-1063 (simulating N key via RAM keys to kill Nextor v2 kernels) is leftover and should be removed as part of this implementation

### Override case (newer kernel becomes master)
- If kernel A (3.0) shows the menu and writes RAM keys, then kernel B (3.1) overrides A and becomes master
- Kernel B's DO_KEYS_INIT loads RAM keys (no N set) → menu doesn't trigger again
- This is correct: the previous master already showed the menu

## Scanning Algorithm

For each slot/subslot combination (up to 16, but stop at 5 kernels found):
1. Check EXPTBL (FCC1h) to determine if primary slot is expanded
2. RDSLT at 4000h/4001h → check for "AB" ROM signature
3. RDSLT at 407Bh-407Eh → check for "NXT3" signature
4. If both match: set BK4_ADD = DRIVER.DRIVER_QUERY (412Bh), CALSLT with IX=CALDRV (4048h), IYh=target slot, A=DRVQ_GET_STRING, B=DRVQ_STR_DRIVER_NAME, D=buffer size, HL=buffer address
5. Handle result: QUERY_OK → name, QUERY_TRUNCATED_STRING → name+"...", other → "(BAD DRIVER)"

Buffer size for driver name query should be `available_width - 3` to leave room for "..." suffix when truncated.

## Screen Layout Analysis

Total lines with 5 kernels + 8 numeric options: ~21 lines. Fits in 24-line MSX text mode.

### 40-column mode (MSX1)
- Shorten "in slot X-Y" to "in X-Y" for 5 extra characters of driver name
- Separator: 40 (or 39 for Korean MSX) hyphens
- Max driver name display width: roughly 25-28 characters

### 80-column mode (MSX2+)
- Full "in slot X-Y" text
- Separator: 80 (or 79 for Korean MSX) hyphens
- Max driver name display width: roughly 55-60 characters

### Non-Turbo-R
- Keys 2 and 4 (R800-related) are hidden, saving 2 lines

## Key Mappings in the Menu

Kernel toggle keys use the existing per-slot disable keys from DISABLE_TBL:
- Slot 0-0 to 0-3: U, I, O, P
- Slot 1-0 to 1-3: Q, W, E, R
- Slot 2-0 to 2-3: A, S, D, F
- Slot 3-0 to 3-3: Z, X, C, V

Numeric keys: 0-5 as labeled, plus 6=CTRL, 7=SHIFT

Special: N = disable all and boot, ESC = cancel, ENTER = apply and boot

## Default States (Asterisks)

- All kernels: enabled (asterisk shown) by default
- Numeric keys: asterisk shown if the corresponding bit is set in KEYS_INV_0/KEYS_INV_1
- Default KEYS_INV_0 = 00h → no numeric keys inverted
- Default KEYS_INV_1 = 20h → CTRL inverted (key 6 "Single FDD drive" shows asterisk by default)

## Technical Notes for Implementation

### BOOTKEYS layout (5 bytes at F9B9h)
- Byte 0 (B): 76543210 (digit keys)
- Byte 1 (E): FEDCBA98
- Byte 2 (D): NMLKJIHG
- Byte 3 (L): VUTSRQPO
- Byte 4 (H): CAPS.GRAPH.CTRL.SHIFT.ZYXW

### RAM keys at A100h
- 17 bytes: "NEXTOR_BOOT_KEYS\0"
- 5 bytes: key data (same layout as BOOTKEYS: B, E, D, L, H)
- RAM keys bypass KEYS_INV (inversion already applied or not needed)

### Inter-slot call safety
- BK4_ADD is safe to use at this boot stage (no timer interrupt hooks set up yet)
- CALDRV/CALBNK in target ROM are doshead.mac code (ROM, no initialization needed)
- Bank switching code at CHGBNK is ROM code, works without initialization

### Existing code references
- `PRINT_INIT_KERNEL_AT_ASLOT` at init.mac:695 - existing driver name query logic (local slot only)
- `CALL_DRIVER_QUERY` at init.mac:3556 - calls DRIVER_QUERY in local slot via CALBNK
- `DISABLE_KEY` at init.mac:226 - current N + per-slot key check (to be split)
- `DO_KEYS_INIT` at init.mac:3024 - keyboard/RAM key scanning
- `SCANKEYS_RAM` at init.mac:634 - one-time RAM keys detection
- `OVERRIDE` at init.mac:1028 - master kernel setup (menu insertion point)
- `CLEAN_V2_KERNELS` at init.mac:3574 - Nextor 2 cleanup (separate from menu)

## Open Items / Nice-to-haves

- Redefine asterisk character pattern as a checkmark (VDP pattern table modification) - defer until working implementation exists
- Consider what happens with exactly 5 kernels (KERNEX only has 4 slots) - show all 5 in menu, accept that the 5th can't register
- Key 0 "Disable permanent disk emulation" always shown (can't check device before driver init)
- Driver query without initialization requirement must be documented for third-party driver developers
15 changes: 12 additions & 3 deletions source/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ B0RELS = $(addprefix bank0/,doshead.rel 40ff.rel b0.rel init.rel alloc.rel dskba
B1RELS = $(addprefix bank1/,dosinit.rel mapinit.rel msg.rel)
B2RELS = $(addprefix bank2/,kinit.rel char.rel dev.rel kbios.rel misc.rel seg.rel path.rel find.rel dir.rel handles.rel del.rel rw.rel files.rel buf.rel fat.rel val.rel err.rel)
B3RELS = $(addprefix bank3/,dos1ker.rel)
B4RELS = $(addprefix bank4/,jump.rel env.rel cpm.rel ramdrv.rel time.rel seg.rel misc.rel dskab.rel)
B4RELS = $(addprefix bank4/,jump.rel env.rel cpm.rel ramdrv.rel time.rel seg.rel misc.rel bootmenu.rel)
B5RELS = $(addprefix bank5/,b5.rel)
B6RELS = $(addprefix bank6/,b6.rel)

Expand Down Expand Up @@ -490,6 +490,15 @@ bank4/partit.rel: \

$(call assemble,bank4/partit.mac)

bank4/bootmsg.rel: \
macros.inc \
const.inc \
condasm.inc \
bank4/bootmsg.mac \
bank0/betainfo.mac

$(call assemble,bank4/bootmsg.mac)

bank4/ramdrvh.rel: \
macros.inc \
const.inc \
Expand All @@ -510,15 +519,15 @@ bank4/B4.BIN bank4/B4.SYM: \
$(COMRELS) \
$(B4RELS) \
bank4/partit.rel \
bank4/bootmsg.rel \
bank4/b4.rel \
bank4/ramdrv.rel \
bank0/b0labels.inc \
bank2/b2labels.inc \

$(call print_linking,"bank 4")
@$(LK80) --working-dir bank4 --symbols-file B4.SYM --output-file B4.BIN \
--code 40FFh ../codes.rel ../kvar.rel ../data.rel b4.rel jump.rel env.rel cpm.rel partit.rel ramdrv.rel time.rel seg.rel misc.rel \
--code 7BC0h dskab.rel \
--code 40FFh ../codes.rel ../kvar.rel ../data.rel b4.rel jump.rel env.rel cpm.rel partit.rel ramdrv.rel time.rel seg.rel misc.rel bootmenu.rel bootmsg.rel \
--code 7fd0h ../chgbnk.rel


Expand Down
33 changes: 22 additions & 11 deletions source/kernel/bank0/bdos.mac
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ DB_INIT::
ret
;
;
; Template for the KABJ/KDERJ hooks that get copied to page 3 RAM
; (KABJ_CODE and KDERJ_CODE) during initialization. These hooks switch
; to bank 0 via CHGBNK before jumping to KABR/KDERR, so they work
; regardless of which bank is currently paged in.
;
KABJ_HOOKS_TEMPLATE::
xor a
call 7FD0h ;CHGBNK - switch to bank 0
jp KABR
xor a
call 7FD0h ;CHGBNK - switch to bank 0
jp KDERR
;
;
;-----------------------------------------------------------------------------
;
KAB_ROUTINE:
Expand All @@ -46,8 +60,9 @@ KABR::
; the first BDOS call, switches back to the user's stack and jumps to the
; user's defined "BREAKVECT" routine.
;
; The hook at KAB_VECT is set to an intermediate hook KABJ instead of pointing
; directly here, see KABJ at the end of drv.mac for an explanation of why.
; The hook at KAB_VECT is set to an intermediate hook in page 3 RAM (KABJ_CODE)
; that switches to bank 0 via CHGBNK before jumping here.
; See KABJ_HOOKS_TEMPLATE above.
;
;
exx ;Save error code in B'
Expand All @@ -72,8 +87,9 @@ KDERR::
; routine returns then the KBDOS paging is re-enabled and control returned to
; the KBDOS.
;
; The hook at KDSK_VECT is set to an intermediate hook KDERJ instead of pointing
; directly here, see KDERJ at the end of drv.mac for an explanation of why.
; The hook at KDSK_VECT is set to an intermediate hook in page 3 RAM (KDERJ_CODE)
; that switches to bank 0 via CHGBNK before jumping here.
; See KABJ_HOOKS_TEMPLATE above.
;
; Entry: A' = Old error code (passed to DISKVECT in C)
; A = New error code (passed to DISKVECT in A')
Expand Down Expand Up @@ -186,14 +202,9 @@ DOS1_GO::
; Insure error vectors are directed to us. Just for bad mannered applications
; that call 0005h at one time and F37Dh at another time. ...HF...
;
; Note: KABJ and KDERJ need to be defined at the same address as defined at drv.mac

KABJ equ 7BC0h
KDERJ equ KABJ+7

ld hl,KABJ ; ;Setup the disk vector and
ld hl,KABJ_CODE## ; ;Setup the disk vector and
ld (KAB_VECT##),hl ; abort vector routines for
ld hl,KDERJ ; ; MSX-DOS 1.0 compatability.
ld hl,KDERJ_CODE## ; ; MSX-DOS 1.0 compatability.
ld (KDSK_VECT##),hl ;
LD HL,(BDOS_STACK##)
OR A ;If the current stack pointer
Expand Down
2 changes: 1 addition & 1 deletion source/kernel/bank0/betainfo.mac
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
if ALPHA gt 0
defb " alpha ",ALPHA+"0",ALPHAL," "
defb " alpha ",ALPHA+"0"," "
endif

if BETA gt 0
Expand Down
2 changes: 2 additions & 0 deletions source/kernel/bank0/doshead.mac
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ BASDEV: ld ix,DRIVER.BASDEV##
;
jp BIOS_IN## ;Version 1 compatible $IN entry

NXT3_SIGNATURE::
db "NXT3",0 ;407Bh - Signature for Nextor 3.0+ ROMs
defs ROMST+80h-$,0FFh
;
RAMENT:: ; RAM DISK DRIVER ENTRY POINTS
Expand Down
Loading
Loading