Hi Kyle,
This assembles, but I haven't run it as the version of that stack I have checked out today doesn't run yet so I'll test it later. I noticed a couple of things in the original implementation:
first, it clobbers the current status register setting to disable interrupts, no so bad, but then it restores them by setting the sr interrupt mask to 0. This may not be what you want if you are being careful with interrupt levels and priorities. My version preserves the current sr.
Second, (I haven't had time to properly investigate this) the discrepancy in struct size and reserved space in the tk_frame function may be to reserve space for the registers that are pushed in tk_switch.
Code:/*************************************************** * tk_switch * * Called with the new task pointer as the first * address on the stack. All registers are copied * to the stack. Interrupts are masked on entry * and returned to previous state on exit. * */ _tk_switch:tk_switch: move.w %sr, %d1 /* Preserve sr */ move.w #0x2700, %sr /* Disable interrupts */ link %a6, #-44 /* Push a6 and reserve space for the other registers */ /* a6 = sp - 4, sp = sp - 48 */ movem.l %d2-%d7/%a1-%a5, (%sp) /* Push d2 to d7 and a1 to a5 onto the stack */ /* Now we have stacked all the registers that matter */ move.l 12(%a6), %d0 /* Get the task pointer that was passed to the function */ /* This will be the first 4 bytes on the stack after the */ /* return address */ movea.l (tk_cur), %a1 /* Get a pointer to the current task */ move.l %a7, tk_fp(%a1) /* Save sp (a7) in the task struct */ move.l %d0, tk_cur /* Install new (passed) task */ movea.l %d0, %a1 /* Address new task */ movea.l tk_fp(%a1), %a7 /* Install new task's stack */ movem.l (%sp), %d2-%d7/%a1-%a5 /* Pop registers from the new stack */ lea 44(%sp), %a6 /* Adjust a6 based on the new task's sp */ unlk %a6 /* Pop a6 from the new task's stack */ move.w %d1, %sr /* Restore old sr */ rts /* Return in new task context */
Let me know if you try it.
Cheers,
Paul.