;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
  .size
}


;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_Memory		;11
			DCD Service_Reset		;27
			DCD Service_ModeChange		;46
			DCD Service_PreModeChange	;4D
			DCD Service_ModeExtension	;50
			DCD Service_WimpCloseDown	;53
#if compile_RO > 311 AND 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

 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]

 TEQ     R1, #Service_ModeChange	;has the mode changed?
 BEQ     _modechange			;YES

 #if compile_RO > 311
   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_WimpCloseDown	;is a wimp task shutting down?
   BEQ     _wimpclosedown
 #endif

 TEQ     R1, #Service_ValidateAddress	;validate address?
 BEQ     _validateaddress

 #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

 #if compile_RO > 311
   TEQ     R1, # Service_Memory		;is appspace about to be removed?
   BEQ     _memory			;YES
 #endif

 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
; R2 - mode specifier
; R3 - monitor type
; R4 - bandwidth limit
; R5 - memory limit

._modeextension				;PRM1-641
 LDR     R14, [R12, #modeextension_in_progress - VARS]
 TEQ     R14, #Service_ModeExtension	;is it us?
 LDMEQFD R13!, {R0-R2, PC}		;YES, exit
 STR     R1, [R12, #modeextension_in_progress - VARS]	;prevent re-entrancy

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

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

 TEQ     R1, #0				;was the call claimed?
 LDMNEFD R13!, {R0-R5, 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]			;R0=list format, R2=base mode
 CMP     R0, #1				;is it type 0 or 1?
 BLS     _modeextension_translate	;YES, change to type 3

 STR     R1, [R13, #1 * 4]		;return claim as-is
 STR     R3, [R13, #3 * 4]
 STR     R4, [R13, #4 * 4]
LDMFD   R13!, {R0-R5, PC}




;_modeextension_translate
;------------------------
;Will translate a type 0/1 ModeExtension
;
;Entry:
; R0-R5 - 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
 LDR     R5, [R13], #4
 STMFD   R13!, {R0-R11}			;stack now R0-R11, R14

 ADD     R5, R3, #8			;R5=start of VIDC parameters
 TST     R2, #1<<7			;shadow mode?
 LDR     R2, [R3, #4]			;base MODE
 ORRNE   R2, R2, #1<<7			;YES
 MOV     R3, R14			;monitor type

 STMFD   R13!, {R0-R2, PC}
 B       _premodechange
 NOP
 NOP
 #if compile_GPU == 1
  STMFD   R13!, {R0-R2, PC}
  B       _modechanging
  NOP
  NOP
  MOV     R14, #0			;tell _premodechange / _modechange its Service_ModeExtension
  STR     R14, [R12, #modeextension_in_progress - VARS]
 #endif
 STMFD   R13!, {R0-R2, PC}
 B       _modechange
 NOP
 NOP
 #if compile_GPU == 1
   STR     R13, [R12, #modeextension_in_progress - VARS]
 #endif
 #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
   LDR     R12, [R13, #0]		;preserve R12
 B       _modeextension_L1

 ._modeextension_build_VIDC3
 LDR     R12, [R13], #4			;preserve R12
 ADD     R11, R12, #vidc20_regs - (VIDC20_HCR << 2) - VARS
 ADD     R10, R12, #VIDC3 - VARS
 #if compile_IOMD == 1
   MOV     R1, #1
   STRB    R1, [R12, #ignore_next_mode_change - VARS]	;ignore the next mode change
 #endif
 
 LDRB    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?
 BNE     _hand_vidc3_to_OS		;NO, hand VIDC3 to RISCOS

 ._modeextension_L2
   LDR     R0, [R5], #4			;get register
   CMN     R0, #1			;last value
   BEQ     _hand_vidc3_to_OS		;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, [R10, #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, R10, R12}
     BL      calc_VMOD_RMOD		;set VIDC20 clock
     LDMFD   R13!, {R5, R10, 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

 ._hand_vidc3_to_OS
LDMFD   R13!, {R0-R11, PC}




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

; BL      unmap_screen_memory		;unmap it    ;2.84
 BL      find_MODE			;can we find a MODE table match?
 STRNE   R2, [R12, #closest_screen_mode - VARS]	;store the MODE
 LDMNEFD R13!, {R0-R2, PC}		;MODE unsupported

 #if JIT_debug == 1 AND compile_IOMD == 1
   STR     R13, dbg_pause		;pause debug whilst we switch mode
 #endif
 #if use_overlay == 1
   LDR     R14, [R12, #closest_screen_mode - VARS]
   CMN     R14, #1			;are handling this MODE?
   BNE     _we_are_handling
					;******* clear the GPU screen *******
   STMFD   R13!, {R2-R5, R8-R9}
   LDR     R8, current_display_driver
   MOV     R9, #Vector_GraphicsV
   MOV     R8, R8, LSL #24		;R8=driver ID
   MOV     R0, #3			;get the TCK
   MOV     R1, #0
   MOV     R2, #0			;TCK value
   ORR     R4, R8, #12
   SWI     XOS_CallAVector		;PRM1-70  GraphicsV 12
   ADR     R4, current_GPU_res+8	;start and size
   LDMIA   R4, {R3, R5}
   MOV     R0, R1
   MOV     R2, R1
   MOV     R4, R1
   ._clear_loop
     STMIA   R3!, {R0, R1, R2, R4}	;32 bytes
     STMIA   R3!, {R0, R1, R2, R4}
     SUBS    R5, R5, #32
   BGT     _clear_loop

   LDMFD   R13!, {R2-R5, R8-R9}
   ._we_are_handling
 #endif
 STR     R2, [R12, #closest_screen_mode - VARS]	;store the MODE

 #if compile_IOMD == 1
   MOV     R0, #DA2_magic_number	;get DA2 address
   SWI     XOS_ReadDynamicArea		;PRM1-396   
   ADD     R1, R12, #os_memory_block - VARS
   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, [R12, #hwd_framestore - VARS]

   ._premodechange_reset_IOMD
   MOV     R0, #0
   STR     R0, [R12, #IOMD_FSIZE_value - VARS]	;reset IOMD FSIZE

   ADD     R2, R12, #vidc20_regs - VARS		;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
   SWI     XHourglass_Smash		;turn off the Hourglass
   SWI     XOS_RemoveCursors		;hide text cursor
   STMFD   R13!, {R3-R9}
   MOV     R0, #%00			;turn hardware pointer off
   LDR     R4, current_display_driver
   MOV     R4, R4, LSL #24
   ORR     R4, R4, #5			;Update Pointer
   MOV     R9, #Vector_GraphicsV
   SWI     XOS_CallAVector		;PRM1-70
   LDMFD   R13!, {R3-R9}
 #endif

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







;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

 LDR     R1, [R12, #emulate_RISCOS - VARS]
 CMP     R1, #&300 << 8			;RO2 uses different VIDC parameters
 CMPLO   R2, #29			;only supports 29 modes
 ADRHS   R1, VIDC1_MODE_defaults	;R1 = VIDC1 default table
 ADRLO   R1, VIDC1_RO2_MODE_defaults

 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

 ADD     R0, R0, R1			;R0 = ptr to VIDC parameters for mode

 STMFD   R13!, {R3}			;pre-cache VIDC20 registers for MODE
 ADD     R2, R12, #vidc20_regs - VARS
 MOV     R14, #VIDC20_HBER - VIDC20_HCR
 ._modechanging_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     _modechanging_L1
 LDMFD   R13!, {R3}
LDMFD   R13!, {R0-R2, PC}
 #endif


#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

._modechange				;PRM1-638
 STMFD   R13!, {R3-R6}
 MOV     R0, #4				;XEigFactor
 MOV     R1, #5				;YEigFactor
 MOV     R2, #11			;X max
 MOV     R3, #12			;Y max
 MVN     R4, #0
 STMFD   R13!, {R0-R4}
 MOV     R0, R13
 MOV     R1, R13
 ORR     R1, R1, #1			;pass on to OS
 SWI     XOS_ReadVduVariables
 LDMFD   R13!, {R0-R4}
 ADD     R2, R2, #1
 ADD     R3, R3, #1
 MOV     R5, R2, LSL R0			;R5=X max
 MOV     R6, R3, LSL R1			;R6=Y max
 #if use_overlay == 1
   LDR     R1, [R12, #closest_screen_mode - VARS]
   CMN     R1, #1			;are we going to support this MODE?
   BNE     _its_us			;YES, we can skip getting GPU info
   BL      destroy_overlay
   ADR     R14, current_GPU_res
   STMIA   R14!, {R2, R3}		;store the width/height
   ADD     R0, R12, #readVDUstart - VARS
   ADD     R1, R0, #12 + 1		;+1 to force our handler to pass on
   MOV     R2, R14
   SWI     XOS_ReadVduVariables		;PRM1-730
   LDMIA   R1, {R0, R1}
   STMIA   R2, {R0, R1}			;store the address and size
   ._its_us
 #endif

 ADD     R4, R12, #Joystick_Mousemapping - VARS
 MOV     R3, #0
 STR     R5, [R4, #screen_OS_units_X - Joystick_Mousemapping]
 STR     R6, [R4, #screen_OS_units_Y - Joystick_Mousemapping]
 STR     R3, [R4, #Joystick_Mouse.X_offset]
 STR     R3, [R4, #Joystick_Mouse.Y_offset]
 LDMFD   R13!, {R3-R6}

 #if compile_RO == 311
   LDMFD   R13!, {R0-R2, PC}
 #endif
#if compile_RO > 311
 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_IOMD == 1
   LDRB    R14, [R12, #ignore_next_mode_change - VARS]
   TEQ     R14, #0			;ignore this MODE change?
   MOVNE   R14, #0
   STRNEB  R14, [R12, #ignore_next_mode_change - VARS]
   LDMNEFD R13!, {R0-R2, PC}
 #endif

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

 BL      unmap_screen_memory		;unmap it    ;2.84
 LDR     R2, [R12, #closest_screen_mode - VARS]	;get the MODE found during preMode
 CMN     R2, #1				;a MODE we support?
 LDMEQFD R13!, {R0-R2, PC}		;NO

 #if compile_GPU == 1
   CMP     R2, #first_custom_MODE	;custom MODE?
   BHS     _custom_MODE			;YES

   LDR     R1, [R12, #emulate_RISCOS - VARS]
   CMP     R1, #&300 << 8		;RO2 uses different VIDC parameters
   CMPLO   R2, #29			;only supports 29 modes
   ADRHS   R1, VIDC1_MODE_defaults	;R1 = RO3 VIDC1 default table
   ADRLO   R1, VIDC1_RO2_MODE_defaults	;R1 = RO2 VIDC1 default table
 #endif

 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_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
 #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
 STRB    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, #(12-3) * 4]		;restore R12 from stack

   LDR     R2, [R12, #VIDC20_clock - VARS]	;reference clock
   LDR     R3, [R12, #VIDC1_clock - VARS]	;pixel rate required
   BL      calc_VMOD_RMOD			;set VIDC20 clock
   LDR     R12, [R13, #(12-3) * 4]		;restore R12 from stack

   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
     STMFD   R13!, {R1, R12}
     ADD     R0, R6, R3, LSL #14	;add in command
     BL      translate_VIDC1_to_VIDC20	;translate the value
     LDMFD   R13!, {R1, R12}		;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
     LDR     R12, [R13, #(12-3) * 4]	;restore R12 from stack

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

 ._custom_MODE
 BL      get_DA2_size			;get DA 2's size
 BL      map_screen_memory		;map RISC OS 3.11 video memory
 #if JIT_debug == 1 AND compile_IOMD == 1
   MOV     R0, #1			;allow debug info
   TEMP    R14
   STR     R0, dbg_pause
   LOCK    R14
 #endif
 #if compile_GPU == 1
   #if use_overlay == 0 OR overlay_at_vsync == 1
     STMFD   R13!, {R3-R9}		;need to update the GPU so we can
     LDR     R1, [R12, #modeextension_in_progress - VARS]
     TEQ     R1, #0			;are we processing Service_ModeExtension
     STRNE   R13, [R12, #old_VIDC20_HCR - VARS]	;reset HCR/VCR
     BLNE    blit_update_VIDC		;NO, capture any VIDC/VIDC20 parameter
     LDMFD   R13!, {R3-R9}		;..changes done directly after VSync
   #endif
;   #if use_overlay == 1 AND overlay_at_vsync == 0
;     STR     R13, [R12, #old_VIDC20_HCR - VARS]	;reset HCR/VCR
;     STR     R13, HAL_vidc_list_dirty
;   #endif

   MOV     R0, #0
   STR     R0, [R12, #Cursor_state - VARS]	;ensure the cursor is off
   STR     R0, [R12, #blit_in_progress - VARS]	;resume blitter
 #endif

 SWI     XOS_RestoreCursors
LDMFD   R13!, {R0-R2, PC}
#endif




;Service_ValidateAddress - PRM1-368
;validate the old RO3.1 screen memory range on RISC OS 3.50+
;validate the floppy image buffer on RISC OS 3.11 so *ADFSave works
;
;Entry:
; stack - R0-R2, R14
; R2    - address to validate

._validateaddress			;PRM1-368
#if compile_RO > 311
 LDRB    R0, [R12, #is_screen_remapped - VARS]	;screen memory remapping off
 TEQ     R0, #0				;have we claimed the Data Abort vector?
 LDMEQFD R13!, {R0-R2, PC}		;NO, exit

 BL      check_taskID			;task we support?
 LDMNEFD R13!, {R0-R2, PC}		;NO
 
 SUB     R2, R2, #&1F88000		;validate start address
 CMP     R2, #480 * 1024 * 2		;old screen address?
 ADDLO   R0, R0, #1			;end address is +1
 SUBLO   R2, R3, #&1F88000		;validate end address
 CMPLO   R2, #480 * 1024 * 2
#endif
#if compile_RO == 311
 LDRB    R0, [R12, #Type_Mounted - VARS]
 TEQ     R0, #Type_None			;is an image mounted?
 LDMEQFD R13!, {R0-R2, PC}		;NO, exit
 LDR     R14, [R12, #DA_address - VARS]	;start address
 LDR     R0, [R12, #ADF_Buffer_Length - VARS]	;size
 SUB     R2, R2, R14			;validate start address
 CMP     R2, R0
 ADDLO   R0, R0, #1			;end address is +1
 SUBLO   R2, R3, R14			;validate end address
 CMPLO   R2, R0
#endif
 LDMFD   R13!, {R0-R2, R14}		;clear down stack
 MOVLO   R1, #0				;YES, valid address range
MOV     PC, R14




;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
 LDRB    R0, [R12, #BootFloppyRequested - VARS]
 TEQ     R0, #0				;has the filer requested a floppy boot?
 MOVNE   R0, #100			;YES
 ADRNE   R1, _Entry_ADFBootFloppyCB	; |
 MOVNE   R2, R12			; |
 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, R12
 SWI     XOS_AddCallBack		;PRM1-324
LDMFD   R13!, {R0-R2, PC}




#if Managed_ChannelHandler == 1
;Service_Sound - PRM4-17
;handle parts of the sound system starting or dying
;
; stack - R0-R2, R14

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

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

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

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

 MOV     R14, #&FF
 STRB    R14, [R12, #soundDMA_restarting - VARS]
 BL      release_ChannelHandler		;reset Channel Handler and Scheduler
 BL      reset_sound_modules
 BL      claim_ChannelHandler
 MOV     R0, #1
 STRB    R0, [R12, #soundDMA_restarting - VARS]
LDMFD   R13!, {R0-R2, PC}

 ._kill_channelhandler
 TEMP    R14
 MOV     R0, #0				;no need to reset Channel Handler
 STRB    R0, [R12, #dont_trap_sound_configure - VARS]	;pass Sound_Configure to OS
 LOCK    R14
LDMFD   R13!, {R0-R2, PC}
#endif




#if compile_RO > 311
;Service_Memory - PRM3-66
;shuts down the JIT if the task is running under it
;
; stack - R0-R2, R14
; R0 - amount applicaton space will change by
; R2 - CAO

._memory
 BL      check_JIT_and_taskID		;is the task one of ours?
 LDMNEFD R13!, {R0-R2, PC}		;NO

;BBB NEEDS TO CHECK IF CAO IS A 26bit Module

; CMP     R2, #jit_slotsize		;is the CAO in appspace?
; MOVLO   R1, #0				;YES,
; BLLO    Entry_GOARM3JIT		; |+ turn off screen mapping and the JIT
 MOV     R1, #0
 STR     R1, [R13, #1*4]

LDMFD   R13!, {R0-R2, R14, PC}




;_wimpclosedown
;--------------
;Watches for Wimp tasks running under the JIT and removes their filters

._wimpclosedown
 TEQ     R0, #0				;is a task closing down?
 LDMNEFD R13!, {R0-R2, PC}		;NO
 MOV     R0, R2				;R0=task
 BL      check_WimpID			;is this a task we're managing?
 BLEQ    Remove_Wimp_Filters
LDMFD   R13!, {R0-R2, PC}
#endif




#if compile_RO > 311
;find_MODE
;---------
;checks if the MODE matches a RO3.11 MODE
;
;Entry:
; R2 - < 256 - 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}

 SUB     R7, R2, #1			;ensure R7/R2 are different
 CMP     R2, #255			;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
#endif

#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
; #if compile_GPU == 1 AND use_overlay == 0
   CMP     R0, #640			;640x480 or lower @ 8bpp
   CMPLS   R1, #480
   CMPLS   R6, #3			;8bpp
; #endif
; #if compile_GPU == 1 AND use_overlay == 1
;   CMPLS   R6, #4			;16bpp
; #endif
 MOVLS   R2, #128			;custom MODE
 MOVLS   R7, #128
 B       _find_MODE_exit
#endif
