Commit 865e89

2026-10-30 07:28:07 Bob Green: -/-
project ideas/operating system/netbsd port.md ..
@@ 22,3 22,100 @@
- The final step takes a Long Time(tm) and builds the userspace, which will need to be added to the root filesystem.
I've still got to document how to build the root filesystem.
+
+ ## Device Driver Templates
+ I asked Claude about templates for coding device drivers. Here's what it said:
+
+ ### Uart
+ The template is myuart.c. It’s a complete single-channel UART driver for hb68k: it attaches through the device tree, can be the system console, and gives you a normal tty with interrupt-driven I/O.
+
+ What you change: the two CHIP-SPECIFIC sections near the top
+
+ - Register map: placeholder offsets and bit definitions for data, status, control, baud divisor and interrupt enable. The real byte offset is reg << reg-shift, so register spacing comes from the device tree rather than the code.
+ - Eight small hardware functions, the only code that touches the chip:
+ - `rx_ready` / `getc`
+ - `tx_ready` / `putc`
+ - `clear_errors`
+ - `set_intr`
+ - `intr_pending`
+ - `program`, which sets speed and frame format from termios flags. The example assumes a 16× divisor UART.
+ - The `compatible` string your device-tree node will use.
+
+ Everything below those sections is generic, and you shouldn’t need to touch it for a first version: console, autoconfiguration, interrupt handling, soft interrupt, and the tty and cdevsw entry points. Each part has a comment explaining its role and the locking.
+
+ #### How data moves:
+
+ - Receive: the hard interrupt copies bytes into a ring buffer. A soft interrupt later passes them to the tty layer, because the hard interrupt mustn’t call into it.
+ - Transmit: the tty layer hands over a chunk of output. The transmit interrupt feeds it to the chip, then switches itself off when the chunk is done.
+ - Console: the console uses polling and works from very early in boot. BREAK on the console drops into DDB.
+
+ Setup steps, all listed at the top of the file:
+
+ 1. Add the device/attach/file lines to files.hb68k.
+ 1. Add a major number to majors.hb68k. 14 is free in your tree.
+ 1. Add a myuart* at fdt? pass 5 line to the kernel config.
+ 1. Add a device-tree node.
+ 1. On the target, make the device node by hand (mknod /dev/ttyM0 c 14 0), since MAKEDEV won’t know about the driver.
+
+ Deliberately left out:
+
+ - modem control (carrier is treated as always present)
+ - hardware flow control
+ - split input/output speeds
+ - sending BREAK
+
+ The ioctl function marks where the last of these goes. Your mc68681_duart.c is a worked example of the same structure extended to a two-channel chip, with an IVR, if you want to compare.
+
+ One constraint carries over from your board: the driver’s lock is a spin mutex at IPL_VM, so the chip’s interrupt level in the device tree must be 5 or lower.
+
+ Myuart
+ C
+
+ ### Timer
+
+ Confirmed: a NULL argument makes the dispatcher pass the interrupt frame. Now a compile test:
+
+ The timer template is mytimer.c, built the same way as the UART one. I compiled it into an SBC3 kernel twice, once each way for the auto-reload setting, and both built cleanly. Then I took it back out of the tree.
+
+ What you change: the CHIP-SPECIFIC sections
+
+ - Registers: a placeholder register map for a simple down-counter (control, status, 24-bit reload).
+ - Limits and reload behaviour:
+ - MYTIMER_COUNT_MAX is the largest reload value.
+ - MYTIMER_PRESCALE is any fixed divider in front of the counter.
+ - MYTIMER_AUTO_RELOAD says whether the chip restarts itself at zero. If it doesn’t, the driver restarts it by hand on every tick. That loses a little time per tick, so the clock runs slightly slow.
+ - Three hardware functions:
+ - hw_stop() stops the counter and clears pending interrupts.
+ - hw_start(count) loads the count and starts periodic interrupts.
+ - hw_ack() clears the interrupt. Getting this wrong makes the machine appear to hang, because the CPU re-enters the handler immediately.
+
+ How it fits into hb68k: a timer driver provides only mechanism. The clock code in hb68k/clock.c owns the policy and calls the driver through four functions in a small table (struct clock_if):
+
+ Function When it’s called What it does
+ clk_init once, late in boot establishes the interrupt at IPL_SCHED
+ clk_arm(interval_us) once, right after init starts periodic interrupts, e.g. every 10 000 µs for 100 Hz
+ clk_intr at the start of every tick acknowledges the interrupt, and reloads if needed
+ clk_disarm shutdown or error stops the timer
+
+ The file header explains:
+
+ - How netbsd,hardclock / netbsd,statclock under /chosen pick each timer’s role, and what happens without them.
+ - Why the timer belongs at IPL 6.
+ - Which HZ values are allowed (they must divide 1 000 000).
+ - Why the interrupt handler’s argument must be NULL. I checked this in the dispatcher: with NULL, the clock code receives the interrupt frame, which it needs.
+
+ Setup is lighter than the UART’s:
+
+ - Add device/attach/file to files.hb68k.
+ - Add mytimer* at fdt? pass 3 to the config.
+ - Add a device-tree node with clocks or clock-frequency, plus an interrupts entry.
+
+ There’s no major number or /dev node, since nothing opens a timer.
+
+ Left out deliberately:
+
+ - A high-resolution timecounter. That needs a free-running counter, not a counter that resets every tick, so it depends on what your chip offers.
+ - Randomising the statclock interval. hb68k’s clock code doesn’t do this yet either.
+
+ Mytimer
+ C
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9