*
*  SofTag V3.31 -- By Greg Tibbs 10/25/1992
*
*             Inspired by ZKick 3.01 by Daniel Zenchelsky
*             Assemble with SAS/C 6.00 ASM
*

   NOLIST
   INCLUDE "exec/types.i"
   INCLUDE "exec/tasks.i"
   INCLUDE "exec/resident.i"
   INCLUDE "exec/execbase.i"
   INCLUDE "SoftBoot.i"
   LIST

   SECTION   code

   XDEF   _TC030
   XDEF   _Z3cache
   XDEF   _CRP0
   XDEF   _CRP1
   XDEF   _BusErr
   XDEF   _CatchRom
   XDEF   _SRP
   XDEF   @MakeRomTag
   XDEF   @CachesOff
   XDEF   @SF_Supervisor
   XDEF   _LogRomStart
   XDEF   _PhyRomStart
   XDEF   @JTRom
   XDEF   @MyColdReboot
   XDEF   @SpeedRom
   XDEF   @GetCPUType
   XDEF   @GetTC040
   XDEF   @GetTC030
   XDEF   @KillRomTags
   XDEF   _NumMemAreas
   XDEF   _MemListArray
   XDEF   @JTRom13030
   XDEF   @MakeRomTag13
   XDEF   _IDCpu
   XDEF   @ForceTTX
   XREF   _LVOSupervisor
   XREF   _LVODisable
   XREF   _LVOSuperState
   XREF   _LVOAllocAbs
   XREF   _LVOEnable
   XREF   _LVOSumKickData
   XREF   _LVOSetFunction

VERSION:    	EQU 	3
REVISION:   	EQU 	31
MYPRI       	EQU     127
_LVOColdReboot  EQU     -726
ABSEXECBASE 	EQU     (4)

                CNOP    0,4

;-----------------------------------------------------------------------
; From here on is protected from erasure during reboot
;-----------------------------------------------------------------------
; 128 byte Buffer Area in case of AllocMem Memlist tail overwrite!

_SaveMem:

        	DC.L  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                DC.L  0,0,0,0,0,0,0,0

KickMem:                ;Area for KickMemList data
       		DC.L   0,0,0,0
_MemListArray   DC.L   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                DC.L   0,0,0,0,0,0,0,0,0
KickTag:
        	DC.L    initDDescrip
        	DC.L    0       ;Next Romtag initDescrip Pointer

_CRP0:      	DC.L    $7fff0002
_CRP1:      	DC.L    0
_TC030:     	DC.L    $80f0d400
_SRP:       	DC.L    0
_PhyRomStart:   DC.L    0
_LogRomStart:   DC.L    $00f80000
_BusErr:    	DC.L    0
_CatchRom:  	DC.L    0
_Z3cache    	DC.L    1
_NumMemAreas:   DC.L    3
ROMColdReboot:  DC.L    0
Zero:       	DC.L    0
        	DC.L    0

;-----------------------------------------------------------------------
; A romtag structure.  Both "exec" and "ramlib" look for
; this structure to discover magic constants about you
; (such as where to start running you from...).
;-----------------------------------------------------------------------

   ; Most people will not need a priority and should leave it at zero.
   ; the RT_PRI field is used for _configuring the roms.  Use "mods" from
   ; wack to look at the other romtags in the system

initDDescrip:
                        	; STRUCTURE RT,0
     DC.W    RTC_MATCHWORD      ; UWORD RT_MATCHWORD
     DC.L    initDDescrip       ; APTR  RT_MATCHTAG
     DC.L    _EndTag            ; APTR  RT_ENDSKIP
     DC.B    RTF_COLDSTART      ; UBYTE RT_FLAGS
     DC.B    VERSION            ; UBYTE RT_VERSION
     DC.B    NT_UNKNOWN         ; UBYTE RT_TYPE
     DC.B    MYPRI              ; BYTE  RT_PRI
     DC.L    modName            ; APTR  RT_NAME
     DC.L    idString           ; APTR  RT_IDSTRING
     DC.L    _InitRoutine       ; APTR  RT_INIT


   ; this is the name that the module will have

modName:    	DC.B   'SoftBoot.romtag  ',0

idString:       DC.B   'SoftBoot.romtag 3.31 (10/25/92)',13,10,0

    CNOP 0,4

_InitRoutine:           

    movem.l d0-d7/a0-a6,-(a7)   ;Save Registers
    move.l  ABSEXECBASE,a6      ;Get Execbase

;
;   The following code protects the ROM by allocating its RAM image
;   at 7f80000. Normally this would be done in the KickMemList,
;   but 2.0 has a wonderful feature that if it detects a 68030CPU
;   with its MMU on at boot time, it will autoallocate that area,
;   causing the kickmemlist allocation to fail. By using the ROM at
;   the same address and not caring whether or not the AllocABs
;   passes or fails, similar memory models can be had for the
;   68040 CPU as well as the 030. This is all done for the nice 
;   feature of making RAD work when switching CPUs. This risks
;   another romtag allocating something in this area, so the 
;   priority has been increased to the maximum of 127. If some
;   future OS takes away the autoallocate SuperKickstart 'feature',
;   the current code will continue to work. It also pushes the
;   Largest memory fragment to the end of A3000 motherboard RAM,
;   reducing memory clutter.
;
;   The following code also allocates the 16 bytes in front of the
;   ROM to prevent a MemList tail from overwriting it. That allocation
;   will also overwrite the first two long words, so they are copied to
;   the stack and restored after the allocation.
;
    move.l  #$7f80000,a0        ;Ram Address of Start of Rom
    move.l  (a0)+,a2        	;Get 1st Long Word
    move.l  (a0)+,a3        	;Get 2nd Long word
    movem.l a2-a3,-(a7)     	;Save on stack

    moveq   #$10,d0         	;Number of bytes ahead of ROM to protect
    move.l  #$7f7fff0,a1        ;Address to allocate
    jsr     _LVOAllocAbs(a6)

    move.l  #$80000,d0      	;# of bytes to allocate in ROM
    move.l  #$7f80000,a1        ;Rom Address
    jsr     _LVOAllocAbs(a6)   	;If fails, 2.0 must have already allocated
                    		; this area for me - how nice! thumppp!
    movem.l (a7)+,a2-a3     	;Fix MemList tail overwrite of 1st two Rom
    move.l  #$7f80000,a0        ;   long words
    move.l  a2,(a0)+        	;Restore 2nd Longword of ROM
    move.l  a3,(a0)+        	;Restore 1st Longword of ROM
;
; Now take over ColdReboot() so My MMU tables will be loaded at a software reset
;
    jsr SFColdReboot
;
;   Now Check CPU and handle if a reboot or a pass thru, if a particular
;   CPU does not have MMU tables setup, then it will pass thru, although
;   MMU tables for the other CPU will continue to be protected if they
;   were ever generated in the first place.
;
    btst.b  #AFB_68040,ATNFLGS(a6)
    beq.b   Do030           	;Jump to next test if not 040

    move.l  _SRP,d0         	;Test if 040 MMU tables are setup
    cmpi.l  #0,d0           	;No MMU tables if SRP = 0
    beq.b   ExitInit
    
    lea.l    My040InitCode,a5   ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode
    bra.b    ExitInit       	;Return to OS

Do030:
    btst.b  #AFB_68030,ATNFLGS(a6)  ;Test for 030
    bne.b   Ok030   

    btst.b  #AFB_68020,ATNFLGS(a6)  ;Test for 020 (851 assumed)
    beq.b   ExitInit        	    ;Just return if not a 020 or better

Ok030:
    move.l  _CRP1,d0        	;Test if 030/020&851 MMU tables are setup
    cmpi.l  #$0,d0          	;No MMU tables if CRP = 0
    beq.b   ExitInit
    
    lea.l    My030InitCode,a5   ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode

ExitInit:

    movem.l (a7)+,d0-d7/a0-a6   ;Restore Registers
    rts             		;Return to OS

My030InitCode: 

    bsr     SetMMU030   ;This Must be called for the hardware reset conditon
    btst.l  #31,d1
    beq     Reboot      ;MMU off, turn on to initial state and reboot
    rte

;Load Exception handler and take care of Software and Hardware reset conditions

SetBusErrorHandler:
    
    move.l  _BusErr,d0      	;Check if we want to disable Bus Errors
    cmpi.l  #0,d0           
    beq.b   DoneBus         	;Branch if non zero
    move.b  #0,($DE0000)    	;Set Buster to no Bus Error time out

DoneBus:

    move.l  _CatchRom,d0        ;load and test Error Handler Bypass
    cmpi.l  #0,d0           
    bne.b   SBEHend
    _MOVEC  vbr,d0          	;Get VBR. Should be zero, but never know
    move.l  d0,a0       
    move.l  $8(a0),a1       	;Get Old Bus Error Handler Address
    move.l  a1,OH1          	;Store it
    lea.l   _BusErrorHandler,a1 ;Get new handler address
    move.l  a1,$8(a0)       	;Write to exception table
    move.l  a1,8            	;Write to address 8 for good measure 

SBEHend:    
    rts

My040InitCode:

    bsr     SetBusErrorHandler
    bsr     SetMMU      ;This Must be called for the hardware reset conditon
    cmpi.l  #0,d1
    beq     Reboot      ;MMU off, turn on to initial state and reboot

                	;Change Cache code for Fast Ram 

    _CPUSHA040      	;Dump Caches to RAM
    _PFLUSHA040     	;Clear ATC
    _CINVA040       	;Invalidate caches - Note SetMMU cleared cacr

    move.l  _Z3cache,d1 	; if d1 is non-zero, turn on dttx copyback mode
    cmpi.l  #0,d1
    beq     BypassMMU  		; Zero, therefore leave dttx as is  

    move.l  #$08f7c020,d0   	;Turn on Copyback mode for data acesses
    _MOVEC  d0,dtt1
    move.l  #$04fbc020,d0
    _MOVEC  d0,dtt0

    _PFLUSHA040     		;Kill ATC and Caches again for extra good measure
    _CINVA040

BypassMMU:
    rte

Reboot: 
    nop
    move.l  _LogRomStart,a0
    adda.l  #2,a0
    bra     LongAddr1
    CNOP    0,4

LongAddr1:

    reset
    jmp (a0)
    
SetMMU: 

    _MOVEC  tc,d1       	;Move Get Translation Control Register

    cmpi.w  #$0,d1      	;Test if MMU is already on
    bne     mmu_on      	;if so, bypass and return with TC contents 
                		;  as status
SetMMU1:

    moveq   #0,d1       	;Clear out VBR, TC, and CACR
    _MOVEC  d1,vbr

SetMMU2:

    _MOVEC  d1,tc
    _MOVEC  d1,cacr

    _CPUSHA040      		;Dump Caches
    _PFLUSHA040     		;Clear out ATC
    _CINVA040       		;Invalidate caches

    move.l  _SRP,d1     	;Write MMU Root table pointer to SRP & URP
    _MOVEC  d1,srp
    _MOVEC  d1,urp

    move.l  #$04fbc040,d1   	;Set up MMU for default memory translation setup
    _MOVEC  d1,dtt0
    move.l  #$08f7c040,d1
    _MOVEC  d1,dtt1

    move.l  #$04fbc000,d1
    _MOVEC  d1,itt0
    move.l  #$08f7c000,d1
    _MOVEC  d1,itt1

    _CPUSHA040      		;Dump and Kill caches once again
    _PFLUSHA040
    _CINVA040
   
    move.w  #$C000,d0   	;Load TC (8K tables)
    _MOVEC  d0,tc           	; Activate TC
    move.l  #0,d1       	;Return code for testing if MMU was on at
                		;Start of SetMMU - 0 indicates it was off
mmu_on:
    rts
    
SetMMU030:      

    lea.l   StackCopy,a0    	;Clear tc

    _PMOVE  tc,(a0)     	;Save Translation Control Register
    move.l  StackCopy,d1    	;Load it back from Ram

    btst.l  #31,d1      	;Test if MMU is already on
    bne     mmu_on030   	;if so, bypass and return with TC contents 
                		;  as status
SetMMU031:

    moveq   #0,d1       	;Clear out VBR, TC, and CACR
    _MOVEC  d1,vbr

SetMMU032:

    lea.l   Zero,a0     	;Clear TC and cacr
    _PMOVE  (a0),tc

    move.l  #$0808,d1
    _MOVEC  d1,cacr     	;Turn off & dump Data and Instruction Caches
       
    lea.l   _CRP0,a0    	;Write MMU Root table pointer to SRP & URP
    _PMOVE  (a0),crp

    lea.l   _TC030,a0   	;Load TC and activate the MMU
    _PMOVE  (a0),tc

    move.l  #0,d1       	;Return code for testing if MMU was on at
                		;Start of SetMMU - 0 indicates it was off
mmu_on030:
    rts

; Crude way of handling invalid and write access errors, 
;  all others will be sent to guru land via CBM's handler


    CNOP    0,4         ;Align Stack

StackCopy:

    dc.l   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

_BusErrorHandler: 

    move.l  a5,SafeA5       	;Save on end of temporary stack
    lea.l   _TempStack,a5       ;New Temporary storage area
    movem.l d0-d2/a0-a2,-(a5)   ;Save minimal registers

    move.l  a7,a0           	;Copy the Stack Frame for Later Perusal
    lea.l   StackCopy,a1
    moveq   #14,d0         	;Do 15 times (does a copy on d0 = 0 count)

SCL:

    move.l  (a0)+,(a1)+
    dbra    d0,SCL

    move.w  $c(a7),d0       ;Get Special Status Word
    move.l  d0,d1           ;Save it for other tests
    btst.l  #10,d0          ;Check for ATC fault
    beq.w   BusError        ;Not an ATC fault - Probably a Bus Error
    andi.l  #$18,d0         ;Check for TT=$0
    bne.w   NotNormal       ;Not a Data Access Error
    andi.l  #5,d1           ;Mask TM field from SSW
    cmpi.l  #5,d1           ;Check TM=$5
    beq.b   DoWB1           ;Supervisor, jump
    cmpi.l  #1,d1           ;Check TM=$1 (User)
    bne.w   NotNormal       ;Again, Not a data access error

                    ;We are an ATC Invalid access or 
                    ; write fault error
DoWB1:
    move.l  $2C(a7),d2      ;Get WB1D
    move.l  $28(a7),a2      ;Get WB1A
    move.w  $12(a7),d0      ;Get WB1S
    btst.l  #7,d0           ;Valid Write?
    beq.b   DoWB2
    bsr     WriteBack1      ;Perform WriteBack1

DoWB2:
    move.l  $24(a7),d2      ;Get WB2D
    move.l  $20(a7),a2      ;Get WB2A
    move.w  $10(a7),d0      ;Get WB2S
    btst.l  #7,d0           ;Valid Write?
    beq.b   DoWB3
    bsr     WriteBack       ;Perform WriteBack2
DoWB3:  
    move.l  $1c(a7),d2      ;Get WB3D
    move.l  $18(a7),a2      ;Get WB3A
    move.w  $e(a7),d0       ;Get WB3S
    btst.l  #7,d0           ;Valid Write?
    beq.b   Done
    bsr     WriteBack       ;Perform WriteBack3
Done:
    movem.l (a5)+,d0-d2/a0-a2   ;Restore Registers
    move.l  SafeA5,a5       
    rte             		;Return from exception

BusError:               	;Routine to handle Bus Errors via Exceptions
                    		;Under Construction
    
NotNormal:
    movem.l (a5)+,d0-d2/a0-a2   ;Restore Registers
    move.l  SafeA5,a5       
    dc.w    $4ef9
OH1:    dc.l    $0          	;jmp (OldHandler) - Address filled in
                    		; by SetupBusErrorHandler()

WriteBack:              	;At this point we only care about the 
                    		;load Fault Address (jsr adds 4 to stack offset)
    move.l  $18(a7),a1
    cmpa.l  a2,a1           ;Compare against WBXA
    beq.b   NotDo           ;Return if same-We don't want another fault!
    andi.l  #$60,d0         ;Mask off Size + check for Longword
    beq.b   LongWord        ;Yep, LongWord
    cmpi.w  #$20,d0         ;Check for Byte access
    beq.b   Byte            ;Yep, Byte
    cmpi.w  #$40,d0         ;Check for Word Access
    bne.b    Line           ;Nope, 16 Byte Line Access
Word:
    move.w  d2,(a2)         ;Perform Word Write
NotDo:
    rts

LongWord:

    move.l d2,(a2)          ;Perform Long word write
    rts

Byte:   
    move.b d2,(a2)          ;Perform Byte Write
    rts


Line:   
    addq.l  #4,A7           ;I can't handle a line error here so I
    bra NotNormal           ; punt and run CBM's handler (guruland) 

;--------------------------------------------------------------------------------
;WriteBack1 handler for WB1X 68040 Access Error stack frame, Test code
;A0 unaltered
;WB1A in A2, WB1D in D2, WB1S in D0. D0,D1 & A1 are destroyed by the code  
;-------------------------------------------------------------------------------


WriteBack1:         
                    	    ;TT=0 Already tested for!
    move.l  $18(a7),a1      ;Load Fault Address from Stack frame
    cmpa.l  a2,a1           ;Compare against WB1A
    beq.w   W1End           ;Return if same-We don't want another fault!
    move.b  d0,d1           ;Copy WB1S for trashing
    andi.b  #$18,d1         ;Mask off TT field of WB1S
    beq.w   W1End           ;Jump if not Normal Access Type
    move.l  a2,d1           ;Copy Dest Address
    andi.l  #3,d1           ;Get last two address bits
    move.l  d1,a1           ;Save for Later
    andi.l  #$60,d0         ;Mask off Size + check for Longword
    beq.w   W1LongWord      ;Yep, LongWord
    cmpi.b  #$20,d0         ;Check for Byte access
    beq.w   W1Byte          ;Yep, Byte
    cmpi.b  #$40,d0         ;Check for Word Access
    bne.w   W1Line          ;Nope, 16 Byte Line Access

W1Word:                     ;If not one of above, must be Word

    cmpa.l  #0,a1           ;Check if WB1A Address is xxxxxx00
    bne.b   WA1
WA0:
    moveq   #16,d1          ;Shift data right to fit d15:d0
    ror.l   d1,d2   
    move.w  d2,(a2)         ;Write Word to Address
    bra.b   W1End           ;Done
WA1:
    cmpa.l  #1,a1           ;Check if WB1A Address is xxxxxx01  
    bne.b   WA2 
    moveq   #8,d1           ;Shift data right  to fit D15:0
    ror.l   d1,d2           ;  instead of D23:8
    move.w  d2,(a2)         ;Write word to address
    rts             	    ;Done
WA2:
    cmpa.l  #2,a1           ;Check if WB1A address is xxxxxx10
    bne.b   WA3         
    move.w  d2,(a2)         ;Data register aligned OK, Write Word
    rts             	    ;Done
WA3:
    cmpa.l  #3,a1           ;Check if WB1A address is xxxxxx11
    bne.b   W1End           ;Something wrong if not == 3!
    moveq   #8,d1           ;Shift data from 7:0,31:24 to 15:0
    rol.l   d1,d2   
    move.w  d2,(a2)         ;Perform Byte Write

W1End:
    rts

W1LongWord:

    cmpa.l  #0,a1           ;Check if WB1A is xxxxxx00
    bne.b   LA1
LA0:
    move.l  d2,(a2)         ;Everything aligned, write long word
    rts                     ;Done
LA1:
    cmpa.l  #1,a1           ;Check if WB1A is xxxxxx01
    bne.b   LA2
    moveq   #8,d1           ;Rotate left to align data from 23:0,31:24
    ror.l   d1,d2           ;  to 31:0
    move.l  d2,(a2)         ;Perform long word write
    rts             	    ;Done
LA2:
    cmpa.l  #2,a1           ;Check if WB1A is xxxxxx10
    bne.b   LA3
    moveq   #16,d1          ;Rotate from 15:0,31:16 to 31:0
    ror.l   d1,d2   
    move.l  d2,(a2)         ;Perform long word write
    rts             	    ;Done
LA3:
    cmpa.l  #3,a1           ;Check if WB1A is xxxxxx11
    bne.b   LAEnd           ;Something wrong if not!
    moveq   #8,d1           ;Rotate from 7:0,31:8 to 31:0
    rol.l   d1,d2   
    move.l  d2,(a2)         ;Perform long word write    
LAEnd:
    rts

W1Byte:         ;a0 contains WB1A, a1 is masked WB1A, d2 = WB1D 

    cmpa.l  #0,a1           ;Check if WB1A is xxxxxx00
    bne.b   BA1
BA0:
    moveq   #8,d1           ;Rotate from 31:24 to 7:0
    rol.l   d1,d2   
    move.b  d2,(a2)         ;Perform Byte Write
    rts             	    ;Done
BA1:
    cmpa.l  #1,a1           ;Check if WB1A is xxxxxx01
    bne.b   BA2
    moveq   #16,d1          ;Rotate from 23:16 to 7:0           
    ror.l   d1,d2   
    move.b  d2,(a2)         ;Perform Byte Write
    rts             	    ;Done
BA2:
    cmpa.l  #2,a1           ;Check if WB1A is xxxxxx10
    bne.b   BA3         
    moveq   #8,d1           ;Rotate from 15:8 to 7:0
    ror.l   d1,d2   
    move.b  d2,(a2)         ;Perform Byte Write
    rts
BA3:
    cmpa.l  #3,a1           ;Check if WB1A is xxxxxx11
    bne.b   BAEnd   
    move.b  d2,(a2)         ;Perform Byte Write - Alignment ok  
BAEnd:
    rts

W1Line:                 
    addq.l  #4,a7           ;I can't handle a line error here, so I
    bra NotNormal           ;punt and run CBM's handler (guruland)

;
; SFColdReboot is required to ensure my MMU tables are loaded prior to reboot.
;
SFColdReboot:

    movem.l d0-d7/a0-a6,-(a7)   ;Save Registers

    move.l ABSEXECBASE,a6       ;ensure ExecBase is in a6
    movea.l a6,a1           	;Library for SetFunction to operate on
    lea.l NewColdReboot,a0      ;Address of replacement routine in a0
    move.l a0,d0            	;move address to d0
    lea.l _LVOColdReboot,a0     ;Load library offset into a0
    jsr _LVOSetFunction(a6)     ;Perform the Setfunction
    move.l  d0,ROMColdReboot    ;Save Old Vector

    movem.l (a7)+,d0-d7/a0-a6   ;Restore registers
    rts

;NewColdReboot restores the MMU for the 030 or 040 as other people's MMU
;  tools may have taken over. For guranteed ROM replacement, this code
;  will jam the original SRP/URP for the 040 and CRP0 & CRP1 for the 030. 

NewColdReboot:
    btst.b  #AFB_68040,ATNFLGS(a6)
    beq.b   ResetTest030        ;Jump to next test if not 040
    
    lea.l    My040ResetCode,a5  ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode
    rts             		;We won't return here

ResetTest030:
    btst.b  #AFB_68030,ATNFLGS(a6)  ;Test for 030
    bne.b   Reset030    

    btst.b  #AFB_68020,ATNFLGS(a6)  ;Test for 020 (851 assumed)
    beq.b   NOMMUResetCode          ;Run RomColdReboot if not a 020 or better

Reset030:
    lea.l    My030ResetCode,a5  ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode
    rts             		;We will Never Return here

NOMMUResetCode:
    lea.l   ROMColdReboot,a0    ;Load Old Reset Vector
    jmp     (a0)            	;Reboot Machine
                    		;Never get back here!
    rts             		;Not needed, but here for safety

My040ResetCode:
    moveq   #0,d1           	;0 clears out TC etc in SetMMU2
    jsr     SetMMU2         	;Turn on 040 MMU
    bra     Reboot          	;Reboot

    rte             ;Will Never Return

My030ResetCode:

    jsr     SetMMU032       	;Turn on 030 MMU
    bra     Reboot          	;Reboot
                    		;Will Never Return
    rte             		;Not Needed, but just to be safe

    CNOP 0,4        		;LongWord align stack

                DC.L 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
_TempStack:     DC.L $0 
SafeA5:         DC.L $0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; Buffer for overwrites

_EndTag:

;--------------------End of Protected Romtag Space-------------------------------
@CachesOff:

    movem.l d0-d7/a0-a6,-(sp)   ;Save Registers
    move.l  ABSEXECBASE,a6      ;Load Execbase

    btst.b  #AFB_68040,ATNFLGS(a6)
    beq.b   CS030        	;Don't mess with anything if not 040

CS040:
    lea.l   CachesOff040,a5     ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode
    bra     COExit

CS030:
    lea.l   CachesOff030,a5
    jsr	    _LVOSupervisor(a6)

COExit:
    movem.l (a7)+,d0-d7/a0-a6   ;Restore Registers
    rts             		;Return to OS

CachesOff030:

     move.l  #$0808,d1
     _MOVEC  d1,cacr     	;Turn off & dump Data and Instruction Caches
     rte

CachesOff040:

     moveq   #0,d1
     _MOVEC  d1,cacr
    _CPUSHA040      		;Dump Caches
    _PFLUSHA040     		;Clear out ATC
    _CINVA040       		;Invalidate caches
     rte

;
; SF_Supervisor is required because when OVRMMU option is used, the previous
; ROM could be in RAM, and in particular, the new ROM will probably overwrite
; the contents of the old, invalidating all library LVOs. Thus, Supervisor
; must be setfunctioned to prevent MakeRomTag, JTROM, JTROM13030 et.al from
; going blooey only for the duration it takes to move the rom and reboot. 
; Supervisor is not Setfunctioned unless the rom is to be overwritten and a
; new OS loaded! 
;
; Note - the calling 'C' code must Disable() before calling this routine!
;

@SF_Supervisor:

    movem.l d0-d7/a0-a6,-(a7)    ;Save Registers
    move.l ABSEXECBASE,a6        ;ensure ExecBase is in a6

				 ;By being in Supervisor mode before
				 ;the SetFunction(), it prevents a privlege
				 ;exception from occuring until I can mash
				 ;down my vector immediately after SetFunction() 
    jsr _LVOSuperState(a6)	
 
    movea.l a6,a1           	;Library for SetFunction to operate on
    lea.l MySupervisor,a0       ;Address of replacement routine in a0
    move.l a0,d0            	;move address to d0
    lea.l _LVOSupervisor,a0     ;Load library offset into a0
    jsr _LVOSetFunction(a6)     ;Perform the Setfunction

   lea.l MyExcepHndlr,a1	;Address of Privlege violation handler
    _MOVEC vbr,d0		;Get vbr
    move.l  d0,a0		;Move to address register
    move.l  a1,$20(a0)       	;Write to exception table
    move.l  a1,$20            	;Write to address $20 for good measure 

    andi  #$fdff,sr		;Go back to User mode
    movem.l (a7)+,d0-d7/a0-a6
    rts

MySupervisor:                 	;This routine is relocatable

	ORI.W	#$2000,SR   	;In user mode, creates exception #8 and
			    	;control never returns to here
			    	;If already in Supervisor mode, pass thru
        SUBQ.L	#8,SP	    	;Reduce the Stack pointer to create space for
                                ;a simulated exception frame $0, so the user's
                                ;RTE will run the desired instruction without
				;messing up his stack! 	
	MOVE.W	SR,(SP)	    	;Push the current SR onto the stack so after
			    	;the user code's RTE, SR will be loaded from
				;stack and we will still be in Supervisor mode.
	MOVE.L  A0,SV1		;Save A0
	LEA.L	MyRTS,A0	;Load address of RTS
	MOVE.L	A0,2(SP)	;Change the Return address, so an RTS will be
				;run to exit the Supervisor() function
	MOVEA.L	SV1,A0		;Restore A0
	MOVE.W	#$20,6(SP)      ;Write Privilege exception vector code (frame
				;format $0) to complete exception fake
	JMP	(A5)		;Jump to User code

MyExcepHndlr:			;The address of this routine must be written 
				;to vbr+$20
	MOVE.L	A0,SV1		;SAVE A0 as we need it for address comparisons
	LEA.L	MySupervisor,A0	;Get Address of opcode which might have caused
				;the exception
 	CMPA.L	2(SP),A0	;Check address of the instruction which created
				;the exception
	BNE.W	Reboot    	;It wasn't from Supervisor(), so jump to Reboot
	LEA.L	MyRTS,A0	;Load Address of RTS into A0
	MOVE.L	A0,2(SP)     	;Change value of return address on the stack
				;so that Supervisor() will RTS immediately 
				;after the RTE
        MOVEA.L  SV1,A0		;Restore A0
	JMP	(A5)		;Perform User's code, his RTE will return
				;from the exception to the following RTS
MyRTS:	RTS			;Return from the Supervisor() function
SV1:	DC.L	 0

@JTRom:                 	;Jump To MMUed Rom 
    move.l  ABSEXECBASE,a6      ;Load Execbase
    lea.l   JTSRom,a5
    jsr     _LVOSupervisor(a6)  ;In Supervisor state when you jump to ROM
    rts			    	; Should never get here!!!

JTSRom:

    move.l  ABSEXECBASE,a6      ;Load Execbase
    btst.b  #AFB_68040,ATNFLGS(a6)
    beq.b   JTRom030        	;Don't mess with anything if not 040

    bsr     SetMMU1         	;Turn MMU on and set up default MMU state
    bra     Reboot

JTRom030:                   ;Jump To MMUed Rom

    bsr     SetMMU031       ;Turn MMU on and set up default MMU state
    bra     Reboot          ;jump to longword aligned routine

@MakeRomTag:

    movem.l d0-d7/a0-a6,-(a7)   ;Setup romtag in memory
    move.l  ABSEXECBASE,a6      ;Get execbase
    lea.l   KickMem+14,a0       ;Set up KickMemPtr
    move.l  _NumMemAreas,d0     ;Variable length number of ram areas
    move.l  d0,d1
    addq.l  #1,d0           	;Add extra to romtag list
    move.w  d0,(a0)+        	;  to KickMemList
    lsl     #3,d1           	;8 bytes per memory entry
    adda.l  d1,a0           	;Point to End of List
    lea.l   _SaveMem,a1
    move.l  a1,(a0)+        	;Add  Romtag Allocation Start
    lea.l   _EndTag-_SaveMem,a1
    move.l  a1,(a0)+        	;Add  Romtag Allocation Length

    lea.l   KickMem,a0
    move.l  KickMemPtr(a6),(a0) ;old pointer in ln_Succ
    move.l  a0,KickMemPtr(a6)

;
; Set up KickTagPtr
;
    lea     KickTag,a0

    move.l  KickTagPtr(a6),4(a0)    ;Old pointer at the end of the table
    beq.s   .nomore

    bset.b  #7,4(a0)        ;Bit 31 = Extend table

.nomore:
    move.l  a0,KickTagPtr(a6)

;
; Calculate checksum
;

    jsr     _LVOSumKickData(a6)
    move.l  d0,KickCheckSum(a6)
    movem.l (a7)+,d0-d7/a0-a6
    rts

@MyColdReboot:              	;KILLROM function

    move.l  ABSEXECBASE,a6      ;Get Execbase
    jsr     _LVODisable(a6)
    jsr     _LVOSuperState(a6)  ;Goto Supervisor mode
    moveq   #0,d0
    move.l  d0,$7fc5000     	;Blow Away 1.3 Romtag
    move.l  d0,$6a0
    jsr     _IDCpu
    btst.l  #AFB_68040,d0
    beq.b   ColdReboot030       ;Don't mess with anything if not 040

    bsr     SetMMU          	;Setup MMU to default

    moveq   #0,d0           	;Turn off MMU (SetMMU turned it on)
    _MOVEC  d0,tc

    _CPUSHA040
    _PFLUSHA040
    _CINVA040
   
    bra.b   CommonReboot

ColdReboot030:
                
    bsr     SetMMU030   	;Setup MMU to default
    lea.l   Zero,a0
    _PMOVE  (a0),tc

CommonReboot:
    moveq   #0,d0
    _MOVEC  d0,cacr
    moveq   #$52,d1     	;Number of longwords to kill
    move.l  d0,(a6)     	;blow away exec!
tloop:  
    move.l  d0,(a6)+    	;kill area above execbase
    dbra    d1,tloop

    moveq   #0,d0       
    moveq   #$52,d1
tloop1: 
    move.l  d0,-(a6)    	;Kill area below execbase
    dbra    d1,tloop1
                
    clr.l   ColdCapture(a6) 
    clr.l   CoolCapture(a6)
    clr.l   WarmCapture(a6) 	;Clear vectors and reboot
    clr.l   KickTagPtr(a6)
    clr.l   KickMemPtr(a6)
    bra     Reboot

@KillRomTags:

    move.l  d0,-(a7)        	;Push d0
    move.l  #0,d0           	;Load Zero
    move.l  d0,initDDescrip     ;Kill Romtag header 2.0+
    move.l  d0,initDDescrip2    ;Kill Romtag header 1.3
    move.l  (a7)+,d0        	;Pop d0
    rts             		;Return

;--------------------------------------------------------------------------------
; Note: FastRom is not recoverable due to when program exits, romtag and Bus Error
; Handler are susceptible to getting overwritten. So it was chosen not to load
; the romtag into exec, and to have the setup die on reset. Because of this the
; NoCatchRom option is ignored when entered with the Fastrom parameter. Bus
; error generation (NOBUSERRORS option) is settable in Fastrom.
;---------------------------------------------------------------------------------  

@SpeedRom: 

    movem.l d0-d7/a0-a6,-(a7)   ;Save Registers
    move.l  ABSEXECBASE,a6      ;Load Execbase
    cmpi.w  #36,LIB_VERSION(a6)
    blt.b   SRExit          	;1.3 we are already in MMU!
    btst.b  #AFB_68040,ATNFLGS(a6)
    beq.b   _SpeedRom030        ;Don't mess with anything if not 040

    lea.l   SpeedCode,a5        ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode
SRExit:
    movem.l (a7)+,d0-d7/a0-a6   ;Restore Registers
    rts             		;Return to OS

SpeedCode:
        
    move.l  _BusErr,d0      	;Check if we want to disable Bus Errors
    cmpi.l  #0,d0           
    beq.b   DoneBus2        	;Branch if non zero
    move.b  #0,($DE0000)        ;Set Buster to no Bus Error time out

DoneBus2:

    moveq   #0,d1           	;Bypass clearing VBR in SetMMU
    bsr     SetMMU2         	;Set up MMU

    _CPUSHA040  ;MMU will be on at this time, this code is sensitive
    _PFLUSHA040 ; to what the previous mttx registers were. In particular,
    _CINVA040   ; The area representing the area that this code resides
            	; in must be adjusted such that it doesn't go 'away'.

    move.l  _Z3cache,d1 	;if d1 is non-zero, turn on dttx copyback mode
    cmpi.l  #0,d1
    beq     BypassMMU2 		; Zero, therefore leave dttx as is  

    move.l  #$08f7c020,d0   	;Setup Ram for Copyback cacheable
    _MOVEC  d0,dtt1     	; Had to be previously noncacheable, nonserialized
    move.l  #$04fbc020,d0   	; for OS memory determination.
    _MOVEC  d0,dtt0     

    _CPUSHA040
    _PFLUSHA040 ;Flush ATC to make sure changes don't mess up anything
    _CINVA040   ;Dump D & I caches for good measure

BypassMMU2:
    move.l  #$80008000,d1
    _MOVEC  d1,cacr         	;Turn on Data and Instruction Caches
    rte

_SpeedRom030:

    lea.l   SpeedCode030,a5     ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode
    movem.l (a7)+,d0-d7/a0-a6   ;Restore Registers
    rts             		;Return to OS

SpeedCode030:

    bsr     SetMMU032       	;Set up MMU
    move.l  #$2111,d1
    _MOVEC  d1,cacr         	;Turn on Data and Instruction Caches
    rte

@ForceTTX:              	;Turn on nttx registers

    movem.l d0-d1/a5-a6,-(a7)   ;Save d0 & d1 & a5 - a6
    move.l  ABSEXECBASE,a6      ;Get Execbase
    
    lea.l    ResetTTX,a5        ;Load code pointer 
    jsr     _LVOSupervisor(a6)  ;Run code in Supervisor Mode

    movem.l (a7)+,d0-d1/a5-a6   ;Restore d0 & d1
    rts

ResetTTX:

    _MOVEC  tc,d0       	;Save tc

    move.l  #0,d1
    _MOVEC  d1,tc       	;Turn tc off

    _CPUSHA040      		;Dump and Kill caches 
    _PFLUSHA040
    _CINVA040

    move.l  _Z3cache,d1 	;if d1 is non-zero, turn on dttx copyback mode
    cmpi.l  #0,d1
    beq     BypassMMU3  	;Zero, therefore leave dttx as is  

    move.l  #$04fbc020,d1   	;Set up MMU for default memory translation setup
    _MOVEC  d1,dtt0
    move.l  #$08f7c020,d1
    _MOVEC  d1,dtt1
    bra     DoIttx

BypassMMU3:

    move.l  #$04fbc040,d1   	;Set up MMU for default memory translation setup
    _MOVEC  d1,dtt0
    move.l  #$08f7c040,d1
    _MOVEC  d1,dtt1

DoIttx:
    move.l  #$04fbc000,d1
    _MOVEC  d1,itt0
    move.l  #$08f7c000,d1
    _MOVEC  d1,itt1

    _CPUSHA040      		;Dump and Kill caches once again
    _PFLUSHA040
    _CINVA040

    _MOVEC  d0,tc       	;Turn tc back on

    rte

@GetTC040:

    movem.l d1-d7/a0-a6,-(a7)
    move.l  ABSEXECBASE,a6      ; Get ExecBase
    lea     5$,a5           	; Get the start of the supervisor code
    jsr     _LVOSupervisor(a6)
    movem.l (a7)+,d1-d7/a0-a6
    rts
5$
    _MOVEC  tc,d0
    rte

@GetTC030:
    movem.l d1-d7/a0-a6,-(a7)
    move.l  ABSEXECBASE,a6      ; Get ExecBase
    subq.l  #4,sp           	; Make a place to dump TC
    move.l  sp,a0
    lea     2$,a5           	; Get the start of the supervisor code
    jsr     _LVOSupervisor(A6)
    move.l  (sp),d0         	; Here's the result
    addq.l  #4,sp
    movem.l (a7)+,d1-d7/a0-a6
    rts
2$
    _PMOVE  tc,(a0)
    rte

@GetCPUType:
    movem.l a4-a6,-(sp)     	; Save this register
    move.l  ABSEXECBASE,a6      ; Get ExecBase
    btst.b  #AFB_68040,ATNFLGS(a6)  ; Does the OS think an '040 is here?
    beq     0$
    move.l  #68040,d0       	; Sure does...
    movem.l (sp)+,a4-a6
    rts

0$  btst.b  #AFB_68030,ATNFLGS(a6)  ; Does the OS think an '030 is here?
    beq     10$
    move.l  #68030,d0       	; Sure does...
    movem.l (sp)+,a4-a6
    rts

10$ btst.b  #AFB_68020,ATNFLGS(a6)  ; Does the OS think an '020 is here?
    beq     20$
    move.l  #68020,d0       ; Sure does...
    movem.l (sp)+,a4-a6
    rts

20$ moveq   #0,d0           ; Not an '040
    movem.l (sp)+,a4-a6
    rts

@JTRom13030:     
    jmp     $7fc000c	    ;init routine in 1.3 Bonus

    CNOP 0,4
;-----------------------------------------------------------------------
; From here on is protected from erasure during reboot
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; A romtag structure.  Both "exec" and "ramlib" look for
; this structure to discover magic constants about you
; (such as where to start running you from...).
;-----------------------------------------------------------------------

   ; Most people will not need a priority and should leave it at zero.
   ; the RT_PRI field is used for _configuring the roms.  Use "mods" from
   ; wack to look at the other romtags in the system

initDDescrip2:
                        ; STRUCTURE RT,0
     DC.W    RTC_MATCHWORD      ; UWORD RT_MATCHWORD
     DC.L    initDDescrip2      ; APTR  RT_MATCHTAG
     DC.L    _EndTag2           ; APTR  RT_ENDSKIP
     DC.B    RTF_COLDSTART      ; UBYTE RT_FLAGS
     DC.B    VERSION            ; UBYTE RT_VERSION
     DC.B    NT_UNKNOWN         ; UBYTE RT_TYPE
     DC.B    MYPRI              ; BYTE  RT_PRI
     DC.L    modName2           ; APTR  RT_NAME
     DC.L    idString2          ; APTR  RT_IDSTRING
     DC.L    _InitRoutine2      ; APTR  RT_INIT

    CNOP 0,4

;
; It is assumed that _InitRoutine will only be run under 1.3 as
; it is mapped into f05xxx by the 1.3 MMU routine. Since 2.0
; requires a kicktag pointer for non-fxxxxx romtags, it should
; not be found and executed under 2.0. Under 1.3, it will install
; the ColdInit routine as the ColdCapture vector. Should the 
; System be hardware rebooted via keyboard, the 2.0 rom will take
; over, but will use the pre-existing 1.3 execbase for Coldcapture
; if it passes the checksum consistancy checks. The ColdCapture
; routine then IDs the OS version. If 1.3, then it returns, if 
; 2.0, it then jumps to one of the two CPU routines which reenable the
; MMU and restart 1.3. The near impossible is achievable!
;
; Note that I blast over the ColdCapture vector rather than chaining
; as I am at such a high priority in the boot sequence that no one is
; supposed to be able to get to ColdCapture ahead of me. Now if 
; another program blows away Coldcapture, then reboot will not survive
; a hardware reset.
;

_InitRoutine2:  
    
    movem.l d0-d7/a0-a6,-(a7)   ;Save Registers
    move.l  ABSEXECBASE,a6      ;Get Execbase

    lea.l   ColdInit,a0     	;Romtag ColdCapture address
    lea.l   initDDescrip2,a1    ;Romtag Start Address
    suba.l  a1,a0           	;length to ColdInit
    move.l  #$7fc5000,a1        ;Final Start Address of Romtag
    add.l   a1,a0           	;Add Offset to get Final ColdInit address
    move.l  a0,ColdCapture(a6)  ;Move to ColdCapture

; Recalculate checksum

    lea    $22(a6),a0
    moveq  #$16,d0
    moveq  #0,d1

sumloop2:

    add.w  (a0)+,d1
    dbra   d0,sumloop2
    not.w  d1
    move.w d1,$52(a6)

InitExit2:

    movem.l (a7)+,d0-d7/a0-a6   ;Restore Registers
    rts

ColdInit:               ;Remember, we are in Supervisor Mode
                    	;during ColdCapture

    movem.l d0-d1/a0,-(a7)      ;Save Registers
    cmpi.w  #$1114,($f80000)    ;Test if 2.0
    bne     ExitCold

    bsr     _IDCpu          	;CPU Type returned in d0

    btst.l  #AFB_68040,d0
    beq.b   Do0302          	;Jump to next test if not 040

    bra.b   My040InitCode2      ;Load code pointer 
    

Do0302:
    btst.l  #AFB_68030,d0       ;Test for 030
    beq.b   ExitCold        	;Just return if not a 020 or better

Ok0302:

    lea.l   TC0302(pc),a0
    _PMOVE  (a0),tc


    CNOP 0,4

RB030:
    reset
    jmp    $fc0002        	;Load code pointer 

TC0302:    DC.L $80f08630

ExitCold:

    movem.l (a7)+,d0-d1/a0      ;Restore Registers
    jmp     (a5)            	;Return to OS

My040InitCode2:

    moveq   #0,d1       	;Clear out VBR, TC, and CACR
    _MOVEC  d1,vbr

    _MOVEC  d1,tc
    _MOVEC  d1,cacr

    _CPUSHA040      		;Dump Caches
    _PFLUSHA040     		;Clear out ATC
    _CINVA040       		;Invalidate caches

    move.l  #$04fbc040,d1   	;Set up MMU for default memory translation setup
    _MOVEC  d1,dtt0
    move.l  #$08f7c040,d1
    _MOVEC  d1,dtt1

    move.l  #$04fbc000,d1
    _MOVEC  d1,itt0
    move.l  #$08f7c000,d1
    _MOVEC  d1,itt1

    move.l  #$7fc6000,d1        ;Write MMU Root table pointer to SRP & URP
    _MOVEC  d1,srp
    _MOVEC  d1,urp

    _CPUSHA040      		;Dump and Kill caches once again
    _PFLUSHA040
    _CINVA040

    move.w  #$C000,d0   	;Load TC and activate the MMU
    _MOVEC  d0,tc

    bra     RB030

_IDCpu:
    _MOVEC    cacr,d1           ; Get the Cache Control Register
    move.l   #$8000,d0          ; Make a copy
    _MOVEC   d0,cacr            ; Try to set the CACR
    _MOVEC   cacr,d0            ; Save the real value
    _MOVEC   d1,cacr            ; Restore it
    cmpi.l   #$8000,d0      	; Check for 040 bit
    beq      Load040        	; Yup, an 040
    moveq    #0,d0  
    bset.l   #AFB_68030,d0      ; Must be 020 or 030 
    rts

Load040:
    moveq   #0,d0
    bset.l  #AFB_68040,d0       
    rts

   ; this is the name that the module will have

modName2:   DC.B   'ReBoot13.romtag  ',0

idString2:  DC.B   'ReBoot13.romtag 3.31 (10/25/92)',13,10,0

_EndTag2:


;--------------------End of Protected Romtag Space-------------------------------

;
; Move Romtag to $7fc5000 which appears at f05000 via MMU tables
;

@MakeRomTag13:
        movem.l d0-d1/a0-a3,-(a7)      ;Save Registers

        lea.l   _EndTag2,a0      ;Romtag End address
        lea.l   initDDescrip2,a1 ;Romtag Start Address
        suba.l  a1,a0            ;Romtag length
        move.l  a0,a3
        move.l  #$f05000,a2      ;Remapped romtag Start Address
        add.l   a2,a3            ;Relocated _EndTag2 Address
                move.l  a0,d0    ;Number of Bytes to copy
        move.l  #$7fc5000,a0     ;Final Address of Romtag
MRTLoop:    
        move.b 	(a1)+,(a0)+      ;Copy romtag to new location
        dbra    d0,MRTLoop

;
;Patch relocated Romtag
;
        move.l  a2,($7fc5002)       ;New initDDescript2
        move.l  a3,($7fc5006)       ;EndTag2

        lea.l   modName2,a1         ;Calc New modname after reloc
        lea.l   initDDescrip2,a3    ;Start of Existing romtag
        sub.l   a3,a1
        add.l   a2,a1
        move.l  a1,($7fc500e)       ;Store in RT_NAME

        lea.l   idString2,a1        ;Calculate loc of new idString2
        sub.l   a3,a1
        add.l   a2,a1
        move.l  a1,($7fc5012)       ;Store in RT_IDSTRING

        lea.l   _InitRoutine2,a1    ;Calc relocated InitRoutine2
        sub.l   a3,a1
        add.l   a2,a1
        move.l  a1,($7fc5016)       ;Store in RT_INIT
 
    	movem.l (a7)+,d0-d1/a0-a3   ;Restore Registers
        rts

        end
