Ma version, je poste l'ensemble du handler. Ca compile, mais c'est pas testé, j'attends encore une fois le verdict avant de me casser les dents ...
Description : le but est de retourner une valeur dans d0 ou un pointeur dans a0 sans avoir détruit le moindre registre, ou encore d'appeler un ramcall sans rien avoir détruit non plus.
Pour ce, il faut distinguer deux cas, vu que le ramcall retournera au programme : si le vecteur a été appelé en mode superviseur (à priori ça devrait être rare), il faut mettre l'adresse de retour du handler sur la pile superviseur, sinon, il faut la mettre dans la pile utilisateur qui sera ajustée à cet effet. Encore une fois, tous les avis sont les bienvenus.
(au passage, il est possible de pousser un registre en moins sur la pile, pour deux octets de plus, avec un simple move.l a1,d1). Je le fais au cas où. Je fournirai aussi le patch.
; If $FFF0,
; ~ jsr abs.l (Return address +6 / jsr to a1 ->Crash code+2 a1+(a1)
; Ex: dc.w $FFF0 dc.l JumpAdr-*
; If $FFF2,
; ROM_CALL avec un word.
; Example: dc.w $FFF2, HeapAlloc*4
LINE_1111:
movem.l d0-d2/a0-a3,-(sp) ; Musn't trash any register for ramcalls. a3 won't be trashed, but it reserves space
move.w 4*7(sp),d1 ; Get Old SR
movea.l 4*7+2(sp),a0 ; Get Address of the 'crash'
move.w (a0)+,d0 ; We get the instruction and a0 ->next instruction
cmpi.w #$F800,d0 ; Is it > $F800 ?
bls.s \ramcall ; No, so it is perhaps a ramcall (FirstWindow is not a romcall)
lea.l 4*7+6(sp),sp ; Pop 7 registers + SR + Address of the 'crash'
subi.w #$F800,d0 ; Clean data
movea.l a0,a1 ; Jsr/Jmp with a 32 bits offset
cmpi.w #$FFF0-$F800,d0
bne.s \NoRelJsr
adda.l (a0)+,a1 ; Get the Sub Routine
bra.s \Jump
\NoRelJsr cmpi.w #$FFF1-$F800,d0
bne.s \NoRelJmp
adda.l (a0)+,a1 ; Get the Sub Routine
move.w d1,SR ; Restore SR
jmp (a1) ; Jmp with a 32 bits offset
\NoRelJmp cmpi.w #$FFF2-$F800,d0
bne.s \NoBigRomCall
move.w (a0)+,d0 ; Read Offset
lsr.w #2,d0
\NoBigRomCall movea.l ($C8).w,a1 ; The address of the rom_call table
cmp.w -(a1),d0 ; Compare rom_call and number of entries
bcc.s \crash ; Out of range ? => Crash
move.w d0,(VAR_SYSTEM1).w ; For debug purpose
lsl.w #2,d0 ; * 4
movea.l 2(a1,d0.w),a1 ; + ($C8) MAX: 8000 rom_calls
\Jump move.w d1,SR ; Restore SR
pea (a0) ; Push return address
jmp (a1) ; Jump to Rom_call function
\ramcall:
subi.w #$F000,d0 ; Clean data
cmpi.w #MAX_RAMCALL,d0 ; Valid ramcall ?
bcc.s \crash ; No, it's a crash
move.b RAM_TABLE_TYPE(pc,d0.w),d2 ; Read type of ramcall (table of bytes)
lea RAM_TABLE(pc),a1 ; Ptr to the ramcall table
lsl.w #2,d0 ; Table of longwords
movea.l 0(a1,d0.w),a1 ; Read ramcall
tst.b d2 ; What type of ramcall ?
bmi.s \ReturnPtr ; -1 : return a ptr in a0
beq.s \ReturnData ; 0 : return data in d0
btst.b #5,28(sp) ; Called in supervisor mode ?
beq.s \UserMode ; No
move.w 7*4(sp),6*4(sp) ; Rewrite SR (need another return adress on the stack)
move.l a1,6*4+2(sp) ; Set the ramcall ptr as the return adress of the handler
move.l a0,7*4+2(sp) ; Push the return adress of the ramcall
movem.l (sp)+,d0-d2/a0-a2 ; Restore registers, but not a3 which hasn't ben destroyed
rte ; And quit the handler, calling the ramcall
\UserMode:
move.l USP,a2 ; Read user stack pointer
move.l a0,-(a2) ; And push the return adress of the ramcall
move.l a2,USP ; Save the new stack pointer
move.l a1,4*7+2(sp) ; Set the ramcall ptr as the return adress of the handler
movem.l (sp)+,d0-d2/a0-a3 ; Restore all registers
rte ; Call ramcall
\ReturnPtr:
move.l a1,12(sp) ; Modify saved a0
bra.s \EndDataPtr ; Useless ?
\ReturnData:
move.l a1,(sp) ; Modify saved d0
\EndDataPtr:
movem.l (sp)+,d0-d2/a0-a3 ; Restore destroyed registers
addq.l #2,2(sp) ; Return adress points now after the 'crash'
rte ; And come back
\crash: lea Line1111_str(Pc),a0
bra FATAL_ERROR
RAM_TABLE_TYPE: ; -1 : ptr. 0 : data. +1 : routine
dc.b -1,0,0,-1,0,0,0,0,0,0,0,0,0,-1,-1,0,-1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,-1,-1,-1,1,0,0,0,0,0,1,1,1,1,-1,-1,-1
even