;Entry_service
;-------------
;Checks for a soft-reset and redirects the vectors if needed
;PRM1-213 / PRM1-254
;Checks for VDU mode changes and remaps memory if required

#if compile_RO > 311
STRUCT VIDC_Type3
{
  .list_type	DCD 0
  .log2bpp	DCD 0
  .hsync	DCD 0
  .hbpch	DCD 0
  .hlbdr	DCD 0
  .hdisp	DCD 0
  .hrbdr	DCD 0
  .hfpch	DCD 0
  .vsync	DCD 0
  .vbpch	DCD 0
  .vtbdr	DCD 0
  .vdisp	DCD 0
  .vbbdr	DCD 0
  .vfpch	DCD 0
  .pixel_rate	DCD 0
  .sync		DCD 0
}


;Entry:
; R12 - pointer to module private word

 ._service_table	DCD 0				;set R1 to service no.
			DCD Entry_service + 4		;entry for services
			DCD Service_Reset		;27
			DCD Service_ModeChange		;46
			DCD Service_PreModeChange	;4D
			DCD Service_ModeExtension	;50
#if Managed_ChannelHandler == 1
			DCD Service_Sound		;54
#endif
			DCD Service_ValidateAddress	;6D
			DCD Service_ShutdownComplete	;80
#if compile_GPU == 1
			DCD Service_ModeChanging	;89
#endif
			DCD 0

 ALIGN   32, 8
 DCD     _service_table
#endif

.Entry_service
 #if compile_RO > 311
   MOV     R0, R0	;magic word for RO4+
 #endif
 STMFD   R13!, {R0-R2, R14}

 LDR     R12, [R12, #0]

 #if compile_RO > 311
   TEQ     R1, #Service_ModeChange	;has the mode changed?
   BEQ     _modechange			;YES

   TEQ     R1, #Service_PreModeChange	;is the mode about to change?
   BEQ     _premodechange		;YES

   #if compile_GPU == 1
     TEQ     R1, #Service_ModeChanging	;is the mode change in progress?
     BEQ     _modechanging		;YES
   #endif

   TEQ     R1, #Service_ModeExtension	;non-standard mode?
   BEQ     _modeextension		;YES

   TEQ     R1, #Service_ValidateAddress	;validate address?
   BEQ     _validateaddress
 #endif

 #if Managed_ChannelHandler == 1
   TEQ     R1, #Service_Sound		;is the sound system changing?
   BEQ     _check_soundDMA
 #endif

 TEQ     R1, #Service_ShutdownComplete	;has the Desktop shutdown?
 BEQ     _check_boot			;YES

 TEQ     R1, #Service_Reset		;has a reset occurred? PRM3-67
 MOVEQ   R0, #0				;YES
 TEMP    R14				; |
 STREQ   R0, OS_SWI_Vector		; |
 LOCK    R14				; |
 BLEQ    Claim_SWI_Vector		; |+ we need to recapture the vectors

LDMFD   R13!, {R0-R2, PC}




#if compile_RO > 311
;Service_ModeExtension - PRM1-641
;
;translate ModeExtension VIDC 1 modes to VIDC20
;
;Entry:
; stack - R0-R2, R14
; R3 - monitor type

._modeextension				;PRM1-641
 LDR     R14, existing_DataAbort
 TEQ     R14, #0			;have we claimed the Data Abort vector?
 LDRNE   R14, [R12, #modeextension_in_progress - VARS]	;NO, check for re-entrancy
 TEQNE   R14, #Service_ModeExtension
 LDMEQFD R13!, {R0-R2, PC}		;DA not active or re-entrant, exit

 ;call all module service entries, looking for a type 0/1 claim

 STR     R1, [R12, #modeextension_in_progress - VARS]	;prevent re-entrancy
 LDMFD   R13!, {R0-R2}			;pull R0-R2 from stack
 STMFD   R13!, {R0-R8}			;and preserve R0-R8
 MOV     R3, #0				;force 50hz TV
 SWI     XOS_ServiceCall		;PRM1-254 re-issue the call
 MOV     R0, #0
 STR     R0, [R12, #modeextension_in_progress - VARS]	;allow us to capture calls again

 TEQ     R1, #0				;was the call claimed?
 LDMNEFD R13!, {R0-R8, PC}		;NO, exit

 ;call was claimed, now check for type 0 / 1 mode list
 ;R3 - pointer to VIDC list
 ;R4 - pointer to workspace list

 LDR     R0, [R3, #0]			;get type
 CMP     R0, #1				;is it type 0 or 1?
; LDMHIFD R13!, {R0-R8, PC}		;NO, exit
 BLS     _modeextension_translate	;YES, change to type 3

 TEQ     R0, #3				;type 3?
 LDMNEFD R13!, {R0-R8, PC}		;NO, exit

 STR     R1, [R13, #1 * 4]		;return claim
 STR     R3, [R13, #3 * 4]
 STR     R4, [R13, #4 * 4]
;					;the following breaks Lemmings 2, Rockfall
; ADD     R3, R3, #2 * 4		;R3=&HSW
; ADR     R8, vidc20_regs		;R8=&HCR
; LDMIA   R3!, {R1-R2, R4-R7}		;load horizontal values
; STR     R5, [R12, #VIDC20_width - VARS]
; ADD     R2, R2, R1			;HBSR
; ADD     R4, R4, R2			;HDSR
; ADD     R5, R5, R4			;HDER
; ADD     R6, R6, R5			;HBER
; ADD     R0, R6, R7			;HCR
; SUB     R0, R0, #8			;correct HCR
; SUB     R1, R1, #8			;correct HSWR
; SUB     R2, R2, #12			;correct HBSR
; SUB     R4, R4, #18			;correct HDSR
; SUB     R5, R5, #18			;correct HDER
; SUB     R6, R6, #12			;correct HBER
; STMIA   R8, {R0-R2, R4-R6}		;store HCR..HBER
; LDMIA   R3!, {R1-R2, R4-R7}		;load vertical values
; STR     R5, [R12, #VIDC20_height - VARS]
; ADD     R8, R8, #(VIDC20_VCR - VIDC20_HCR) << 2
; ADD     R2, R2, R1			;VBSR
; ADD     R4, R4, R2			;VDSR
; ADD     R5, R5, R4			;VDER
; ADD     R6, R6, R5			;VBER
; ADD     R0, R6, R7			;VCR
; SUB     R0, R0, #2			;correct VCR
; SUB     R1, R1, #1			;correct VSWR
; SUB     R2, R2, #1			;correct VBSR
; SUB     R4, R4, #1			;correct VDSR
; SUB     R5, R5, #1			;correct VDER
; SUB     R6, R6, #1			;correct VBER
; STMIA   R8, {R0-R2, R4-R6}		;store HCR..HBER

;					;the following breaks Gribbly's Day Out
; ADD     R3, R3, #2 * 4			;R3=&HSW
; LDMIA   R3!, {R1-R2, R4-R7}		;load horizontal values
; ADD     R2, R2, R1			;HBSR
; ADD     R4, R4, R2			;HDSR
; ADD     R5, R5, R4			;HDER
; ADD     R6, R6, R5			;HBER
; ADD     R0, R6, R7			;HCR
; SUB     R0, R0, #8			;correct HCR
; STR     R0, [R12, #vidc20_regs - VARS]
; LDMIA   R3!, {R1-R2, R4-R7}		;load vertical values
; ADD     R2, R2, R1			;VBSR
; ADD     R4, R4, R2			;VDSR
; ADD     R5, R5, R4			;VDER
; ADD     R6, R6, R5			;VBER
; ADD     R0, R6, R7			;VCR
; STR     R0, [R12, #vidc20_regs - VARS + ((VIDC20_VCR - VIDC20_HCR) << 2)]

LDMFD   R13!, {R0-R8, PC}



;_modeextension_translate
;------------------------
;Will translate a type 0/1 ModeExtension
;
;Entry:
; R0-R8 - stacked, R1-R4 need to be dropped
; R1 - 0 (claimed)
; R2 - MODE requested
; R3 - pointer to VIDC0/1 list
; R4 - pointer to workspace list
;
;Exit:
; R3 - pointer to our VIDC3 list
; all other registers preserved

._modeextension_translate
 LDR     R14, [R13, #3 * 4]		;R14=monitor type
 LDR     R0, [R13], #5 * 4		;preserve R0 and drop R0-R4
 LDMFD   R13!, {R5-R8}			;preserve R5-R8

 #if Trap_ModeExtensions == 1 AND compile_RO > 311
 ;@@@ for debug purposes, to trap ModeExtensions
   STR     R0, DAV_r0
   ADR     R0, DAV_r0 + 4
   STMIA   R0, {R1-PC}
   B       report_abort
 #endif

 STMFD   R13!, {R0-R11}			;stack now R0-R11, R14

 ADD     R5, R3, #8			;R5=start of VIDC parameters
 LDR     R2, [R3, #4]			;base MODE
 MOV     R3, R14			;monitor type

 STMFD   R13!, {R0-R2, PC}
 BL      _premodechange
 NOP
 NOP
 #if compile_GPU == 1
   STMFD   R13!, {R0-R2, PC}
   BL      _modechanging
   NOP
   NOP
   ADR     R11, HAL_vidc_list
   MOV     R10, #32
   STR     R10, [R11, #VIDC_Type3.hdisp]	;reset GPU size
   STR     R10, [R11, #VIDC_Type3.vdisp]
 #endif
 STMFD   R13!, {R0-R2, PC}
 BL      _modechange
 NOP
 NOP

 #if compile_IOMD == 1
   LDR     R7, [R12, #VIDC20_addr - VARS]	;R7 = VIDC20 address
 #endif

 STR     R12, [R13, #-4]!		;preserve R12

 ._modeextension_L1			;process VIDC register values
   LDR     R0, [R5], #4			;get register
   CMN     R0, #1			;last value
   BEQ     _modeextension_build_VIDC3	;YES, exit loop
   BL      translate_VIDC1_to_VIDC20	;translate the value
 B       _modeextension_L1

 ._modeextension_build_VIDC3
 LDR     R12, [R13], #4			;preserve R12
 ADR     R11, vidc20_regs - (VIDC20_HCR << 2)
 ADR     R10, _VIDC3
 #if compile_IOMD == 1
   STR     R10, _ignore_next_mode_change	;ignore the next mode change
 #endif
 
 LDR     R1, [R12, #current_mode_bitdepth - VARS]
 STR     R1, [R10, #VIDC_Type3.log2bpp]

 LDR     R4, [R11, #VIDC20_HSWR << 2]
 ADD     R4, R4, #8			;correct from N-8
 STR     R4, [R10, #VIDC_Type3.hsync]	;Horizontal sync width

 LDR     R1, [R11, #VIDC20_HBSR << 2]
 LDR     R2, [R11, #VIDC20_HDSR << 2]
 ADD     R1, R1, #12			;correct from N-12
 ADD     R2, R2, #18			;correct from N-18
 SUB     R4, R2, R1
 SUB     R1, R1, R4
 STR     R1, [R10, #VIDC_Type3.hbpch]	;Horizontal back porch
 STR     R4, [R10, #VIDC_Type3.hlbdr]	;Horizontal left border

 LDR     R3, [R11, #VIDC20_HDER << 2]
 LDR     R4, [R11, #VIDC20_HBER << 2]
 ADD     R3, R3, #18			;correct from N-18
 ADD     R4, R4, #12			;correct from N-12
 SUB     R1, R3, R2
 SUB     R2, R4, R3
 STR     R1, [R10, #VIDC_Type3.hdisp]	;Horizontal display size
 STR     R2, [R10, #VIDC_Type3.hrbdr]	;Horizontal right border

 LDR     R8, [R11, #VIDC20_HCR << 2]
 ADD     R8, R8, #8			;correct from N-8
 SUB     R2, R8, R4
 STR     R2, [R10, #VIDC_Type3.hfpch]	;Horizontal front porch


 LDR     R6, [R11, #VIDC20_VSWR << 2]
 ADD     R6, R6, #1			;correct from N-1
 STR     R6, [R10, #VIDC_Type3.vsync]	;Vertical sync width

 LDR     R1, [R11, #VIDC20_VBSR << 2]
 LDR     R2, [R11, #VIDC20_VDSR << 2]
 ADD     R1, R1, #1			;correct from N-1
 ADD     R2, R2, #1			;correct from N-1
 SUB     R4, R2, R1
 SUB     R1, R1, R6
 STR     R1, [R10, #VIDC_Type3.vbpch]	;Vertical back porch
 STR     R4, [R10, #VIDC_Type3.vtbdr]	;Vertical top border

 LDR     R3, [R11, #VIDC20_VDER << 2]
 LDR     R4, [R11, #VIDC20_VBER << 2]
 ADD     R3, R3, #1			;correct from N-1
 ADD     R4, R4, #1			;correct from N-1
 SUB     R1, R3, R2
 SUB     R2, R4, R3
 STR     R1, [R10, #VIDC_Type3.vdisp]	;Vertical display size
 STR     R2, [R10, #VIDC_Type3.vbbdr]	;Vertical bottom border

 LDR     R9, [R11, #VIDC20_VCR << 2]
 ADD     R9, R9, #1			;correct from N-1
 SUB     R2, R9, R4
 STR     R2, [R10, #VIDC_Type3.vfpch]	;Vertical front porch

 #if compile_GPU == 1
   MOV     R2, #50			;50Hz
 #endif
 #if compile_IOMD == 1
   MOV     R2, #60			;60Hz
 #endif
 MUL     R4, R8, R9			;work out pixel_rate
 MUL     R2, R4, R2
 MOV     R2, R2, LSR #10		;convert to kHz
 STR     R2, [R10, #VIDC_Type3.pixel_rate]

 LDR     R3, [R13, #3 * 4]		;restore R3
 STR     R10, [R13, #3 * 4]		;overwrite R3 with our VIDC list
 LDR     R1, [R3, #0]			;type of VIDC list
 TEQ     R1, #1				;type 1 list?
 LDMNEFD R13!, {R0-R11, PC}		;NO, hand VIDC3 to RISCOS

 ._modeextension_L2
   LDR     R0, [R5], #4			;get register
   CMN     R0, #1			;last value
   LDMEQFD R13!, {R0-R11, PC}		;YES, exit and hand VIDC3 to RISCOS

   MOV     R1, R0, LSR #24		;get command
   BIC     R0, R0, #&FF << 24		;strip command from value
   TEQ     R1, #0			;pixel rate in kHz?
   TEQNE   R1, #2			;VIDC clock rate?
   BNE     _modeextension_P1

   STR     R0, [R12, #VIDC1_clock - VARS]	;YES
   STR     R0, _VIDC3 + VIDC_Type3.pixel_rate	;YES

   #if compile_IOMD == 1
     LDR     R2, [R12, #VIDC20_clock - VARS]	;reference clock
     MOV     R3, R0			;pixel rate required
     STMFD   R13!, {R5, R12}
     BL      calc_VMOD_RMOD		;set VIDC20 clock
     LDMFD   R13!, {R5, R12}
   #endif
   B       _modeextension_L2

   ._modeextension_P1
   TEQ     R1, #1			;sync polarity
   BNE     _modeextension_L2		;NO

   LDR     R1, [R12, #VIDC1_CR - VARS]	;update our VIDC1 CR copy
   BIC     R1, R1, #%11 << 11
   ORR     R0, R1, R0, LSL #11		;add in sync bits
   STR     R0, [R12, #VIDC1_CR - VARS]
   #if compile_IOMD == 1
     LDR     R7, [R12, #VIDC20_addr - VARS]
     BL      set_HV_sync		;set VIDC20 HSync / VSync
   #endif
   B       _modeextension_L2

 ._VIDC3	DCD 3			;list format
		DBD 14			;values
		DCD 0			;sync/polarity
		DCD -1			;terminator
		DCD -1			;terminator
		DCD -1			;terminator




;Service_PreModeChange - PRM1-639
;If we've previously claimed the Data Abort vector, we need to ensure the
;video memory is remapped back to where RISCOS is expecting it
;
;entry:
; stack - R0-R2, R14
; R2 - selected mode

._premodechange				;PRM1-639
 TEMP    R1

 LDR     R0, existing_DataAbort
 TEQ     R0, #0				;have we claimed the Data Abort vector?
 #if compile_IOMD == 1 OR compile_GPU == 1
   MVNEQ   R2, #0			;NO
   STREQ   R2, [R12, #closest_screen_mode - VARS]
   LDMEQFD R13!, {R0-R2, PC}		;exit
 #endif
 #if compile_GPU == 1
   STR     R13, blit_in_progress	;pause the blitter
 #endif

 BL      _find_MODE			;can we find a MODE table match?
 STR     R2, [R12, #closest_screen_mode - VARS]	;store the MODE
 BEQ     _premodechange_mode_supported	;YES
					;MODE unsupported
 #if JIT_WIMP_support == 0 AND compile_RO > 311
   MOV     R1, #0			;turn JIT off
   BL      Entry_GOARM3JIT		; |
   MOV     R1, #0			; |
   BL      Entry_ADFRemapVideoMemory	; |+ shutdown the abort handlers
 #endif
 #if JIT_WIMP_support == 1
   BL      unmap_screen_memory		;unmap it
 #endif
 LDMFD   R13!, {R0-R2, PC}

 ._premodechange_mode_supported
 #if JIT_debug == 1 AND compile_IOMD == 1
   STR     R13, dbg_pause		;pause debug whilst we switch mode
 #endif

 #if compile_GPU == 1
   BL      get_screen_start		;get DA2 address and size
   LDR     R2, [R12, #readVDUstart + 16 - VARS]
   LDR     R1, DA2_size			;find the largest of the two
   CMP     R1, R2
   MOVHI   R2, R1
   MOV     R0, #DA2_magic_number	;read current screen size
   SWI     XOS_ReadDynamicArea		;PRM1-396
   SUBS    R1, R2, R1			;is DA2 delta positive?
   BLE     _skip_DA2_resize
   MOV     R0, #2			;YES, increase DA2 size
   BL      pass_SWI_on			; |  pass SWI to dispatch
   SWI     XOS_ChangeDynamicArea	; |+ PRM1-384
   BL      get_screen_start		;get DA2 address and size
   BL      get_DA2_size			;work out the DA size
   ._skip_DA2_resize
#endif

 #if compile_IOMD == 1 or compile_GPU == 1
   MOV     R0, #DA2_magic_number	;get DA2 address
   SWI     XOS_ReadDynamicArea		;PRM1-396
   ADR     R1, os_memory_block
   MOV     R2, #0
   STR     R2, [R1, #0]
   STR     R0, [R1, #4]			;logical address of DA2
   STR     R2, [R1, #8]
   MOV     R0, #0 + (1 << 9) + (1 << 13)	;PRM5a-64
   MOV     R2, #1				;no. of pages
   SWI     XOS_Memory
   LDR     R2, [R1, #8]			;physical address of DA2
   STR     R2, hwd_framestore
 #endif

 #if compile_IOMD == 1
   ._premodechange_reset_IOMD
   MOV     R0, #0
   STR     R0, IOMD_FSIZE_value		;reset IOMD FSIZE

   ADR     R2, vidc20_regs		;reset VIDC20 registers
   MVN     R0, #1024
   MOV     R1, #VIDC20_VCER - VIDC20_HCR
   ._premodechange_L2
     STR     R0, [R2], #4
     SUBS    R1, R1, #1
   BPL     _premodechange_L2
 #endif

 #if compile_GPU == 1
   LDR     R0, [R12, #is_screen_remapped - VARS]
   TEQ     R0, #0			;is the screen memory remapped?
   BNE     _skip_GPU_remap		;YES

   STMFD   R13!, {R3-R9}		;NO, we're about to take over GraphicsV
   BL      release_GraphicsV_Vector
   SWI     XOS_RemoveCursors		;hide text cursor

   MOV     R0, #%00			;turn hardware pointer off
   MOV     R4, #5			;Update Pointer
   MOV     R9, #Vector_GraphicsV
   SWI     XOS_CallAVector		;PRM1-70

   ADR     R8, Cursor_palette		;update pointer palette
   MOV     R1, #25
   MOV     R0, #3
   ._read_pointer_palette_L1
     SWI     XOS_ReadPalette		;PRM1-728
     MOV     R2, R2, ROR #8		;SSBBGGRR
     STR     R2, [R8, R0, LSL #2]
     SUBS    R0, R0, #1
   BNE     _read_pointer_palette_L1

   BL      claim_GraphicsV_Vector	;start the GraphicsV driver
   LDMFD   R13!, {R3-R9}

   ._skip_GPU_remap
 #endif

 LOCK    R1
LDMFD   R13!, {R0-R2, PC}




;_find_MODE
;----------
;checks if the MODE matches a RO3.11 MODE
;
;Entry:
; R2 - < 255 - MODE number
;      bit 0 set - Sprite MODE specifier
;      otherwise - MODE specifier
;Exit:
; R0-R1 - corrupted
; R2 - MODE no. if match found, -1 if not
; EQ if MODE supported by us

._find_MODE
 STMFD   R13!, {R3-R7, R14}

 CMP     R2, #256			;is it a shadowed MODE?
 BHI     _not_a_MODE_no
 BIC     R2, R2, #128			;possibly
 MOV     R7, R2

 CMP     R2, #last_valid_MODE		;is it a known MODE?
 BLS     _find_MODE_exit		;YES, supported

 CMP     R2, #first_custom_MODE		;is it a custom MODE?
 MVNLO   R2, #0				;NO, unsupported

 ._find_MODE_exit
 TEQ     R2, R7				;is the MODE valid?
LDMFD   R13!, {R3-R7, PC}

 ._not_a_MODE_no
 TST     R2, #1				;is it a sprite mode?
 MVNNE   R2, #0				;YES
 BNE     _find_MODE_exit		; |+ not supported, exit

					;must be a MODE specifier
 LDR     R0, [R2, #4]			;width
 LDR     R1, [R2, #8]			;height
 LDR     R6, [R2, #12]			;bpp

 ADR     R14, mode_translation_table
 ._find_MODE_L1
   LDMIA   R14!, {R2-R5}		;get MODE #, width, height, bpp
   CMN     R2, #1			;last known MODE?
#if compile_IOMD == 1
   BEQ     _find_MODE_exit		;YES
#endif
#if compile_GPU == 1
   BEQ     _check_for_legacy_OS_ScreenMode ;YES
#endif

   TEQ     R3, R0			;check width
   TEQEQ   R4, R1			;check height
   TEQEQ   R5, R6			;check bpp
 BNE     _find_MODE_L1
LDMFD   R13!, {R3-R7, PC}		;we found a match


#if compile_GPU == 1
;check for low res, low colour MODE's, which are probably legacy
;Entry:
; R0 - width
; R1 - height
; R6 - bpp
 ._check_for_legacy_OS_ScreenMode
 CMP     R0, #640			;640x480 or lower @ 8bpp
 CMPLS   R1, #480
 CMPLS   R6, #3
 MOVLS   R2, #128			;custom MODE
 MOVLS   R7, #128
 B       _find_MODE_exit
#endif



;Service_ModeChanging - PRM1-648
;The mode has changed.  If we're remapping video memory, we need to reset
;the memory and get the new screen limits
;
;entry:
; stack - R0-R2, R14
; R2 - mode number
; R3 - monitor type

#if compile_GPU == 1
._modechanging				;PRM1-648
 LDR     R2, [R12, #closest_screen_mode - VARS]	;get the MODE found during preMode
 CMP     R2, #last_valid_MODE		;is the MODE a default OS one?
 LDMHIFD R13!, {R0-R2, PC}		;NO

 MOV     R0, R2, LSL #3			;R0 = mode * 8
 ADD     R0, R0, R2, LSL #4		;R0 = mode * 24
 ADD     R0, R0, R2, LSL #2		;R0 = mode * 28
 ADR     R1, VIDC1_MODE_defaults	;R1 = VIDC1 default table
 ADD     R0, R0, R1			;R0 = ptr to VIDC parameters for mode

 STMFD   R13!, {R3}			;pre-cache VIDC20 registers for MODE
 ADR     R2, vidc20_regs
 MOV     R14, #VIDC20_HBER - VIDC20_HCR
 ._modechange_L1
   LDR     R3, [R0], #4
   MOV     R1, R3, LSR #16		;2nd parameter
   EOR     R3, R3, R1, LSL #16		;clear 2nd parameter from 1st
   STR     R1, [R2, #(VIDC20_VCR - VIDC20_HCR) << 2]	;VCR to VBER
   STR     R3, [R2], #4					;HCR to HBER

   SUBS    R14, R14, #1
 BPL     _modechange_L1
 LDMFD   R13!, {R3}
LDMFD   R13!, {R0-R2, PC}
#endif



;Service_ModeChange - PRM1-638
;The mode has changed.  If we're remapping video memory, we need to reset
;the memory and get the new screen limits
;
;entry:
; stack - R0-R2, R14
; R2 - mode number
; R3 - monitor type

 #if compile_IOMD == 1
   ._ignore_next_mode_change	DCD 0
 #endif

._modechange				;PRM1-638
 TEMP    R14

 BL      get_screen_start		;get the display screen start
 MVN     R0, #128			;must be lower than -16 due to DMA size
 STR     R0, [R12, #MEMC_Vend - VARS]	;ignore Vend unless its set later
 #if compile_GPU == 1
   STR     R0, [R12, #old_VIDC20_HCR - VARS]	;reset HCR/VCR
   STR     R0, [R12, #old_VIDC20_VCR - VARS]
 #endif
 #if compile_IOMD == 1
   LDR     R14, _ignore_next_mode_change
   TEQ     R14, #0			;ignore this MODE change?
   MOVNE   R14, #0
   STRNE   R14, _ignore_next_mode_change
   LDMNEFD R13!, {R0-R2, PC}
 #endif

 #if JIT_debug == 1
   #if JIT_debug == 1 AND compile_IOMD == 1
     MOV     R0, #4
     STR     R0, dbg_pause		;pause the JIT reporter
   #endif
   BL      our_VDU30
 #endif

 LDR     R2, [R12, #closest_screen_mode - VARS]	;get the MODE found during preMode
 #if compile_GPU == 1
   CMP     R2, #first_custom_MODE	;custom MODE?
   BGE     _custom_MODE			;YES
 #endif
 CMN     R2, #1				;a MODE we support?
 LDMEQFD R13!, {R0-R2, PC}		;NO

 SWI     XOS_RestoreCursors		;restore the cursor state

 MOV     R0, R2, LSL #3			;R0 = mode * 8
 ADD     R0, R0, R2, LSL #4		;R0 = mode * 24
 ADD     R0, R0, R2, LSL #2		;R0 = mode * 28
 #if compile_GPU == 1
   ADR     R1, VIDC1_MODE_defaults	;R1 = VIDC1 default table
 #endif
 #if compile_IOMD == 1
   ADR     R1, VIDC1_MODE_defaults_VGA	;R1 = VIDC1 default table
   STMFD   R13!, {R0-R1}
   MOV     R0, #161			;Read CMOS
   MOV     R1, #133			;MonitorType in bits 2..6
   SWI     XOS_Byte			;PRM1-369
   MOV     R2, R2, LSR #2
   AND     R2, R2, #%11111

   TEQ     R2, #0			;TV?
;   TEQ     R2, #3			;VGA?
;   TEQNE   R2, #4			;SVGA?
;   TEQNE   R2, #31			;Auto - probably not a TV
   LDMFD   R13!, {R0-R1}
;   ADREQ   R1, VIDC1_MODE_defaults_VGA	;YES, R1 = VIDC1 default VGA table
   ADREQ   R1, VIDC1_MODE_defaults
 #endif
 ADD     R0, R0, R1			;R0 = ptr to VIDC parameters for mode
 #if compile_IOMD == 1 AND JIT_debug == 1
   STR     R0, [R12, #current_screen_mode - VARS]	;needed for our XOS_WriteC replacement
 #endif

 LDR     R1, [R0, #24]			;load pixel rate
 MOV     R1, R1, LSR #16
 STR     R1, [R12, #VIDC1_clock - VARS]	;track VIDC1 clock rate
 MOV     R2, #%00			;8000
 CMP     R1, #11968
 MOVHI   R2, #%01			;12000
 CMP     R1, #16000
 MOVEQ   R2, #%10			;16000
 MOVHI   R2, #%11			;24000+

 LDRB    R1, [R0, #24]			;R1 = mode bitdepth
 STR     R1, [R12, #current_mode_bitdepth - VARS]	;store it for the VIDC code

 LDR     R14, [R12, #VIDC1_CR - VARS]
 BIC     R14, R14, #%1111		;clear bits/pixel
 BIC     R14, R14, #%11 << 11		;clear sync bits
 ORR     R2, R2, R14			;add in pixel rate
 ORR     R2, R2, R1, LSL #2		;add in bits/pixel
 #if compile_IOMD == 1
   LDRB    R1, [R0, #25]		;get sync
   ORR     R2, R2, R1, LSL #11		;add into CR
 #endif
 STR     R2, [R12, #VIDC1_CR - VARS]	;and store it

 #if compile_IOMD == 1
   STMFD   R13!, {R3-R12}
   MOV     R5, R0
   LDR     R7, [R12, #VIDC20_addr - VARS]	;R7 = VIDC20 address
   MOV     R0, R2
   BL      translate_VIDC1_to_VIDC20		;translate the CR value
   LDR     R12, [R13, #9 * 4]

   LDR     R2, [R12, #VIDC20_clock - VARS]	;reference clock
   LDR     R3, [R12, #VIDC1_clock - VARS]	;pixel rate required
   BL      calc_VMOD_RMOD			;set VIDC20 clock

   MOV     R6, #&80 << 24
   ._modechange_L1
     LDR     R3, [R5], #4
     MOV     R1, R3, LSR #16		;2nd parameter
     EOR     R3, R3, R1, LSL #16	;clear 2nd parameter from 1st
     STR     R1, [R13, #-4]!
     ADD     R0, R6, R3, LSL #14	;add in command
     BL      translate_VIDC1_to_VIDC20	;translate the value
     LDR     R1, [R13], #4		;pull 2nd parameter
     ADD     R1, R6, R1, LSL #14	;add in command
     ADD     R0, R1, #(&A0 - &80) << 24
     BL      translate_VIDC1_to_VIDC20	;translate the value

     ADD     R6, R6, #4 << 24
     CMP     R6, #&98 << 24
   BNE     _modechange_L1
   LDMFD   R13!, {R3-R12}
 #endif

 ._custom_MODE
 BL      get_DA2_size			;NO, get DA 2's size
 BL      map_screen_memory		;|+  map it
 #if JIT_debug == 1 AND compile_IOMD == 1
   MOV     R0, #1			;allow debug info
   STR     R0, dbg_pause
 #endif
 #if JIT_WIMP_support == 1 AND compile_GPU == 1
   BL      start_fifty_hz_ticker	;start Vsync counter
   MOV     R0, #0
   STR     R0, blit_in_progress		;resume the blitter
 #endif

 SWI     XOS_RestoreCursors
 LOCK    R14
LDMFD   R13!, {R0-R2, PC}




;Service_ValidateAddress - PRM1-368
;validated the old RO3.1 screen memory range
;
; stack - R0-R2, R14

._validateaddress			;PRM1-368
 #if JIT_WIMP_support == 1
   LDR     R0, [R12, #is_screen_remapped - VARS]	;screen memory remapping off
 #endif
 #if JIT_WIMP_support == 0
   LDR     R0, existing_DataAbort
 #endif
 TEQ     R0, #0				;have we claimed the Data Abort vector?
 LDMEQFD R13!, {R0-R2, PC}		;NO, exit

 SUB     R2, R2, #&1F88000
 CMP     R2, #480 * 1024 * 2		;old screen address?
 LDMFD   R13!, {R0-R2, R14}		;clear down stack
 MOVLE   R1, #0				;YES, valid address range
MOV     PC, R14
#endif




;Service_ShutdownComplete - PRM3-80
;If the desktop has quit, check if we have a floppy boot scheduled
;
; stack - R0-R2, R14

._check_boot				;PRM3-80
 LDR     R0, BootFloppyRequested
 TEQ     R0, #0				;has the filer requested a floppy boot?
 MOVNE   R0, #100			;YES
 ADRNE   R1, _Entry_ADFBootFloppyCB	; |
 MOVNE   R2, #0				; |
 SWINE   XOS_CallAfter			; |+ trigger giving Desktop time to quit
LDMFD   R13!, {R0-R2, PC}




;_Entry_ADFBootFloppyCB
;----------------------
;Trigger a floppy boot sequence
;
; stack - R0-R2, R14

._Entry_ADFBootFloppyCB
 STMFD   R13!, {R0-R2, R14}
 ADR     R0, Entry_ADFBootFloppy	;trigger ADFBootFloppy via callback
 MOV     R1, #0
 SWI     XOS_AddCallBack		;PRM1-324
LDMFD   R13!, {R0-R2, PC}




#if Managed_ChannelHandler == 1
._check_soundDMA
 TEQ     R0, #0
 BEQ     _start_channelhandler		;SoundDMA starting?
 TEQ     R0, #1
 BEQ     _kill_channelhandler		;SoundDMA dying?
LDMFD   R13!, {R0-R2, PC}

 ._start_channelhandler
 MOV     R0, #5
 ADR     R1, _claim_ChannelHandler	;trigger a callback
 MOV     R2, #0
 SWI     XOS_CallAfter			;PRM1-324
 ADR     R0, _claim_ChannelHandler	;trigger a callback
 MOV     R1, #0
 SWI     XOS_AddCallBack		;PRM1-324
LDMFD   R13!, {R0-R2, PC}

 ._claim_ChannelHandler
 STMFD   R13!, {R0-R2, R14}
 ADR     R0, _claim_ChannelHandler2	;trigger a callback
 MOV     R1, #0
 SWI     XOS_AddCallBack		;PRM1-324
LDMFD   R13!, {R0-R2, PC}

 ._claim_ChannelHandler2
 STMFD   R13!, {R0-R2, R14}

 BL      release_ChannelHandler		;reset Channel Handler and Scheduler
 BL      reset_sound_modules
 BL      claim_ChannelHandler
LDMFD   R13!, {R0-R2, PC}

 ._kill_channelhandler
 TEMP    R1
 MOV     R0, #0				;no need to reset Channel Handler
 STR     R0, dont_trap_sound_configure	;pass Sound_Configure to OS
 LOCK    R1
LDMFD   R13!, {R0-R2, PC}
#endif
