KN7000 Tasks & Scheduler
KN7000 Tasks & Scheduler
The KN7000 firmware runs as two cooperative tasks on top of the MILK kernel:
a main task (the foreground UI / panel loop) and an AP (“application”)
task (background work — song/data processing, longer operations). They take turns
by explicitly sleeping and waking each other through a small message API. This
page documents that mechanism as decoded from kn7000_program.rom; it is the
companion to the Event & Dispatch System, which is what
each task actually runs while awake.
The two tasks
The currently-running task and the main task are identified by handles kept in work RAM:
| Global | Meaning |
|---|---|
0x50380004 |
handle of the currently running task |
0x5038002C |
handle of the main task |
Code decides “am I the main or the AP task?” by comparing them — exactly what the
event layer’s GetCurrentObjectId helper does before it picks the active task’s
focused-object id (0x500D3C60 for main, 0x500D3C5C for AP; see the
event page). So each task carries its own focused UI
object, and the event dispatcher always acts on the running task’s object.
Sleep / wake API
Four thin entry points let code hand control back and forth:
| Function | CPU addr | Effect |
|---|---|---|
SleepMainTask |
0x48414B8D |
suspend the main task |
WakeUpMainTask |
0x48414BA7 |
resume the main task |
SleepApTask |
0x48414BC1 |
suspend the AP task |
WakeUpApTask |
0x48414BDB |
resume the AP task |
Each is a one-line wrapper that builds a task-control message and dispatches
it — decoded straight from the source (SleepMainTask):
SleepMainTask: # CPU 0x48414B8D
add -0x14, sp
clr d0
mov d0, (0x10, sp) # message param slot = 0
mov 0x00020009, d0 # message opcode/class
mov 0x0006009D, d1 # message id (see table)
call 0x48414A77 # task-control message handler
ret
The opcode in d0 is the constant 0x00020009 for all four; the message id in
d1 is what selects the action, and the ids form a small contiguous block:
| Message id | Action |
|---|---|
0x0006009D |
sleep main |
0x0006009E |
wake main |
0x0006009F |
sleep AP |
0x000600A0 |
wake AP |
0x000600A1 |
(a fifth task-control message) |
The handler at 0x48414A77 (with a sibling at 0x48414AFD for the AP side) is a
switch on d1 that runs the matching sleep/wake code — from its first
instructions:
cmp 0x6009F, d1 ; beq … # sleep AP
cmp 0x600A0, d1 ; beq … # wake AP
cmp 0x6009D, d1 ; beq … # sleep main
cmp 0x6009E, d1 ; beq … # wake main
cmp 0x600A1, d1 ; beq …
The underlying context switch / run-queue lives in the MILK kernel (the
banner MILK MN10300 Ver1.0R1 at 0x3B8AAC), part of which is in the
still-undumped library ROM at 0x4C000000.
Task refresh
RefreshApTask (0x48414BF5) and RefreshSwEvent (0x48414C98) reset a small
block of task-state globals (0x50021FD8, 0x50021FDC, 0x50021FE0) and then
re-broadcast events (mov -1, d0 with event-category ids 0x00050006 /
0x00050005) so the UI redraws after a task transition. This is the seam where
the scheduler hands back to the event system.
Relationship to the KN5000
Cooperative main/AP tasking on the MILK kernel is shared with the KN5000
(same source tree — Shared Codebase Map); the
message opcode/id convention and the sleep/wake naming carry across. What is
observed here for the KN7000 specifically are the concrete addresses — the task
handles (0x50380004 / 0x5038002C), the per-task focused-object pointers, the
message-id block (0x6009D…0x600A1) and the handler entry points.
The same kernel is in four processors, across two products
The sharing reaches considerably further than the KN5000. The SX-WSA1R, a physical-modelling synthesiser built on a different CPU family (two TMP95C061s against the KN7000’s MN10300), runs the same multitasking kernel — and so does each of the KN5000’s two processors. One kernel, four processors, two products.
The proof for the WSA1R pair is a build, not a resemblance: wsa1/kernel/kernel.s
is a single source that assembles into 2,180 bytes of prom_a and 2,180 bytes of
prom_c, both byte-identical to the real EPROMs. Over the union of the two
blocks there are 941 instruction slots; 735 needed no reconciliation, 129 differed
only in house style, and the remaining 81 reduce to 21 named constants (twelve
RAM addresses, six array sizes, three ROM pointers) — with no conditional assembly
anywhere in the file.
For the KN5000 the identification rests on control-flow shape, not byte identity. Byte identity is the wrong measure across products: two processors in the same product, from the same build, running the same source, still differ in 81 of 941 instruction slots, so a third built years apart cannot be closer. The score is measured against a foil control of non-kernel code cut to the same instruction counts:
| kernel routines (≥ 20 instr) | 20 | 1.000 | 0.909 | 20 |
| non-kernel foils | 26 | 0.333 | 0.212 | 0 |
No overlap, and a gap of 0.41.
⚠ Do not trust the KN5000’s kernel labels. The measured alignment does not
match them: the site that actually corresponds to MsgQueue_Send is labelled
TaskSched_Wait, the one matching Kernel_SemaSignal is labelled
TaskEvent_Wait, and on the main CPU the site matching Kernel_StartTask at 0.978
is called Show_ScreenGroup_Entry. Several KN5000 kernel labels are simply wrong —
a renaming pass waiting to happen, and a reminder that names point an instrument at
a region without being evidence about it.
Not established: who wrote it, and that the sources are identical.
Kernel_Dispatch scores only 0.742, because the KN5000 version has no tick-drain
loop and its lock depth has moved out of a control register the TMP94C241 does not
have. The same program; not the same file.