Skip to content

JIT Entry and Exit Code

nonarkitten edited this page Jul 31, 2019 · 2 revisions

Entry Code

The JIT only runs user opcodes; as such, we will only save the address and data registers before jumping. This is simply:

move.w #$4000,_intena            ; disable interrupts
movem.l a0-a7/d0-d7,host_state   ; save all current registers
movem.l jit_state,a0-a7/d1-d7    ; restore our JIT state
move.w #$C000,_intena            ; enable interrupts

Exit Code

Once complete, obviously the reverse of the above is required. We also need to eat some CPU cycles (for timing) and return the NEXT entry point decided by the flow-control instruction we're handling as the last instruction. This will be dependant upon the opcode we're emulating.

Jump Exit Handlers

When we need to terminate our block because of an unconditional jump or unhandled branch, we need to store the destination PC for the JIT engine to re-enter.

Bcc

  move.w       #$4000,_intena           ; disable interrupts
  movem.l      a0-a7/d0-d7,jit_state    ; save all current registers
  move.l       #jit_pc,d0               ; load PC into D0 (safe to abuse now)
  bxx          .not_taken               ; use reverse condition of bcc
  add.l        #displacement,d0         ; otherwise, add displacement
  
.not_taken
  movem.l      host_state,a0-a7/d1-d7   ; restore our HOST state
  sub[q].l     #<cycles_used>,cycles    ; consume some cpu cycles
  move.w       #$C000,_intena           ; enable interrupts
  rts                                   ; and return to the host

DBcc

  move.w       #$4000,_intena           ; disable interrupts
  dbxx         dx,.taken                ; need to do this before we shelve regs
  movem.l      a0-a7/d0-d7,jit_state    ; save all current registers  
  move.l       #jit_pc,d0               ; dbcc falls to next opcode
  movem.l      host_state,a0-a7/d1-d7   ; restore our HOST state
  sub[q].l     #<cycles_used>,cycles    ; consume some cpu cycles
  move.w       #$C000,_intena           ; enable interrupts
  rts                                   ; and return to the host

.taken
  movem.l      a0-a7/d0-d7,jit_state    ; save all current registers  
  move.l       #jit_pc+displacenet,d0   ; return new entry point
  movem.l      host_state,a0-a7/d1-d7   ; restore our HOST state
  sub[q].l     #<cycles_used>,cycles    ; consume some cpu cycles
  move.w       #$C000,_intena           ; enable interrupts
  rts                                   ; and return to the host

JMP

  move.w       #$4000,_intena           ; disable interrupts
  movem.l      a0-a7/d0-d7,jit_state    ; save all current registers  
  lea          <original-ea>,a0         ; compute address of JMP
  move.l       a0,d0                    ; and safe to return
  movem.l      host_state,a0-a7/d1-d7   ; restore our HOST state
  sub[q].l     #<cycles_used>,cycles    ; consume some cpu cycles
  move.w       #$C000,_intena           ; enable interrupts
  rts                                   ; and return to the host

JSR

  move.w       #$4000,_intena           ; disable interrupts
  move.l       #jit_pc,-(sp)            ; push PC like JSR
  movem.l      a0-a7/d0-d7,jit_state    ; save all current registers  
  lea          <original-ea>,a0         ; compute address of JSR
  move.l       a0,d0                    ; and safe to return
  movem.l      host_state,a0-a7/d1-d7   ; restore our HOST state
  sub[q].l     #<cycles_used>,cycles    ; consume some cpu cycles
  move.w       #$C000,_intena           ; enable interrupts
  rts                                   ; and return to the host

RTS/RTD These are identical operations; in RTS the offset #off below is 4 for RTS and 4 + diplacement for RTD.

  move.w       #$4000,_intena           ; disable interrupts
  lea          #off(sp),sp              ; move stack pointer
  movem.l      a0-a7/d0-d7,jit_state    ; save all current registers  
  move.l       -#off(sp),d0             ; grab return address
  movem.l      host_state,a0-a7/d1-d7   ; restore our HOST state
  sub[q].l     #<cycles_used>,cycles    ; consume some cpu cycles
  move.w       #$C000,_intena           ; enable interrupts
  rts                                   ; and return to the host