BPLCON1  EQU   $DFF102
INTENA   EQU   $DFF09A
INTREQ   EQU   $DFF09C
DMACON   EQU   $DFF096
DMACONR  EQU   $DFF002

   code  code

; m/c subroutine to do all the dirty work for L_QDOS.
; the following is passed on the stack:
;
; $04(A7) safe address for the subroutine that moves things about
; $08(A7) lomem for QDOS
; $0C(A7) himem for QDOS
; $10(A7) address where to move the ROM images
; $14(A7) address where the QDOS is currently loaded
; $18(A7) address where the ROM images are currently loaded
; $1C(A7) length of QDOS
; $20(A7) sum of the lengths of the ROM images
; $24(A7) date for QDOS
; $28(A7) SSP for QDOS

_sub:
   movem.l  $4(a7),a0-a5
   movem.l  $1C(a7),d0-d3

   clr.b    $BFEA01        ; reset CIA-A event counter
   clr.b    $BFE901
   clr.b    $BFE801
   lea      trap0,a6
   move.l   a6,$80         ; initialise TRAP #0 to enter supervisor mode
   trap     #0             ; enter supervisor mode
   or       #$0700,sr      ; disable all interrupts

waitblit:
   btst     #14,DMACONR    ; wait for blitter DMA to stop
   bne.s    waitblit

   move.w   #$3FFF,INTENA     ; disable all possible interrupt sources
   move.w   #$3FFF,INTREQ     ; clear all pending interrupts
   move.w   #$01FF,DMACON     ; disable DMA (bitplane, copper, blitter)

   move.w   #0,BPLCON1        ; scroll value=0. Messed up by rolling title?

   lea      _toclear-_theworks(a0),a7

   lea      _theworks(pc),a6
   move.l   #(_dummy-_theworks)>>1-1,d6
   move.l   a0,d7
mvlup:
   move.w   (a6)+,(a0)+
   dbra     d6,mvlup
   move.l   d7,a0
   jmp      (a0)

trap0:
   addq.l   #2,a7             ; trap to enter supervisor mode
   rts

_theworks:
   sub.l    a0,a0
   lsr.l    #1,d0
   subq.l   #1,d0
qmvlup:
   move.w   (a4)+,(a0)+       ; move QDOS code
   dbra     d0,qmvlup

   tst.l    d1
   beq.s    clrmem

   cmp.l    a5,a3             ; check which direction we should
   blt.s    rmvdn             ; move roms and act accordingly.

rmvup:
   add.l    d1,a5             ; after last word in ROM code
   add.l    d1,a3             ; after last word of destination area
   lsr.l    #1,d1

   bra.s    rmvuptst
rmvuphilup:
   swap     d1
rmvuplolup:
   move.w   -(a5),-(a3)       ; move the ROM code
rmvuptst:
   dbra     d1,rmvuplolup
   swap     d1
   dbra     d1,rmvuphilup
   bra.s    clrmem

rmvdn:
   lsr.l    #1,d1

   bra.s    rmvdntst
rmvdnhilup:
   swap     d1
rmvdnlolup:
   move.w   (a5)+,(a3)+       ; move the ROM code
rmvdntst:
   dbra     d1,rmvdnlolup
   swap     d1
   dbra     d1,rmvdnhilup

clrmem:
   moveq    #0,d0
   bra.s    getrange
clrlup:
   move.l   d0,(a3)+
clrtst:
   cmp.l    a5,a3
   blt.s    clrlup
getrange:
   move.l   (a7)+,a3
   move.l   (a7)+,a5
   cmp.l    d0,a5
   bne.s    clrtst

doql:
   move.l   $4,a0             ; get initial PC

   move.l   d3,a7             ; get initial SSP
   move.l   a7,$0             ; and store it

   move.l   a1,$4             ; store new lomem

   and.l    #-$8000,d3        ; calculate address of system variables
   move.l   d3,a6

   move.w   #$D254,(a6)       ; set QDOS id
   move.l   a2,$20(a6)        ; store himem
   move.l   d2,$A2(a6)        ; store time

   jmp      (a0)              ; start QDOS

   rts

;  this area is filled by the c code with the address ranges
;  that it is necessary to clear (a maximum of 8, zero terminated).

_toclear:
   dcb.l    18,0

_dummy:
   xdef  _sub
   xdef  _toclear
   xdef  _dummy
   xdef  _theworks
   end
