I've written an implementation of setjmp and longjmp in MMIX (assuming no name mangling).
I also hand-assembled it.
Are there any mistakes anyone can spot?
// Memory stack pointer is stored in $254.
// jmp_buf is rO, next address after setjmp call, memory stack pointer,
// frame pointer, then possibly other data (for sigsetjmp/siglongjmp).
// rG is preserved over a longjmp call
// (not that it should change over one, anyway)
setjmp IS @
GET $1,rO // FE01000A
STOU $1,$0,0 // AF010000
GET $1,rJ // FE010004
STOU $1,$0,8 // AF010008
STOU $254,$0,16 // AFFE0010
STOU $253,$0,24 // AFFD0018
SETL $0,0 // E3000000
POP 1,0 // F8010000
longjmp IS @
LDOU $254,$0,0 // 8FFE0000
SAVE $255,0 // FAFF0000
GET $1,rG // FE000013
// why 15? We save 13 special registers, two local registers,
// and the number 2, as well as any global registers.
// That's 256-rG + 16, and we add only 15 because $255 is the address
// of the saved rGA.
SETL $0,271 // E300010F
SUBU $1,$1,$0 // 26010100
SLU $1,$1,3 // 39000003
// now $255 is topmost saved register, $255+$1 is bottommost such,
// $254 is rO after.
SUBU $0,$254,$1 // 2600FE01
LDOU $2,$255,$1 // 8E02FF01
STOU $2,$0,$1 // AE020001
INCL $1,8 // E7010008
PBNZ $1,@-12 // 5B01FFFD
OR $255,$0,0 // C1FF0000
UNSAVE 0,$255 // FB0000FF
// now we have restored rO, but not other stuff
LDOU $253,$0,24 // 8FFD0018
LDOU $254,$0,16 // 8FFE0010
LDOU $0,$0,8 // 8F000008
PUT rJ,$0 // F6040000
OR $0,$1,0 // C1000100
POP 1,0 // F8010000
The register stack was the hard part here. Everything between the SAVE
and the UNSAVE
inclusive is essentially just “set rO
properly”; after that it takes no time at all to fix up the other registers and return.
If you have any other questions, I'm happy to explain my reasons for each tetra of that code.