;AutoVIDC module source - * commands implemetation
;-------------------------------------------------
;
;VIDC Enhancer software control
;For software controlled VIDC Enhancers
;
;Author: Andreas Barth (1995)
;Author: Paul Vernon (Retro-Kit) (2012-2013)
;   www: http://www.retro-kit.co.uk

; ---------------------------------------------------------------------------
; AutoVIDCXXmap shows the map of the current settings for each screenmode.
; The Format is 'Map; <Modenumber>+ <Modenumber>- ...' for all 128 Modes.
; The + and - shows whether Aux1 is switched or not.

.mapIgnore
     STMFD	R13!,{R0-R6,R14}
     MOV	R5,#ignoreModes
     B		map

.mapOC
     STMFD	R13!,{R0-R6,R14}
     MOV	R5,#ModeListOC
     B		map

.map36
     STMFD	R13!,{R0-R6,R14}
     MOV	R5,#ModeList36
     B		map

.map25
     STMFD	R13!,{R0-R6,R14}
     LDRB	R5,internal_flags
     TST	R5,#RISCOS3
     MOVNE	R5,#ModeList25RO2
     MOVEQ	R5,#ModeList25
     B		map

.mapVGA
     STMFD	R13!,{R0-R6,R14}
     MOV	R5,#MappedModes
     ADR	R0,strVGAReadOnly
     BL		writeStringNewLine
     SWI	XOS_NewLine

.map
     LDR	R12,[R12,#0]		;R12->VARS
     ADD	R5,R5,R12
     SWI	XOS_WriteS
     DCB	"Map: ", 0
     ALIGN
     MOV	R4,#0			; Modenumber

._stloop1
     LDR	R6,[R5],#4		; Load first Byte from Map and increment pointer.

._stloop2
     ; print modenumber
     MOV	R0,R4
     BL		convertCardinal2
     SWI	XOS_Write0

     ; decode map setting
     MOVS	R6,R6,LSR #1		; shift lowest bit into carry.
     MOVCC	R0, #ASC("-")		; Use OS_WriteC instead of 2 OS_WriteI to remove "caution" notice of conditional code following SWI call.
     MOVCS	R0, #ASC("+")
     SWI	XOS_WriteC              ; Write out + or - to indicate the mode is set or not.
     SWI	XOS_WriteI + 32		; Write out a space.

     ; finish the loops
     ADD	R4,R4,#1		; increment modenumber
     TEQ	R4,#128			; all modes printed ?
     SWIEQ	XOS_NewLine
     TEQ	R4,#128			; check again, SWI may corrupt the flags...
     LDMEQFD	R13!,{R0-R6,PC}		; we've got to the end... so we can return.

     TEQ	R4,#32			; check for boundaries and
     TEQNE	R4,#64
     TEQNE	R4,#96
     BNE	_stloop2
     BEQ	_stloop1			; get next mapentry.

 ; --------------------------------------------------------------------------
 ; AutoVIDCXXset <Modenumber><+|-> [...] changes the setting for one or
 ; more screenmodes to '+'=ON or '-'=OFF.

 ; R0 - SWI var & pointer to string -> R1
 ; R1 - SWI var & number of parameters -> R4
 ; R2 - max value
 ; R3 - value of current MODE bit
 ; R4 - Number of parameters left to process.
 ; R5 - Next part of the Mode List
 ; R6 - Mode List

.SetIgnore
     STMFD	R13!,{R0-R6,R14}
     MOV	R6,#ignoreModes
     B		Set

.SetOC
     STMFD	R13!,{R0-R6,R14}
     MOV	R6,#ModeListOC
     B		Set

.Set36
     STMFD	R13!,{R0-R6,R14}
     MOV	R6,#ModeList36
     B		Set

.Set25
     STMFD	R13!,{R0-R6,R14}
     LDRB	R6,internal_flags
     TST	R6,#RISCOS3
     MOVNE	R6,#ModeList25RO2
     MOVEQ	R6,#ModeList25

.Set
     LDR	R12,[R12,#0]		;R12->VARS
     ADD	R6,R6,R12

     MOV	R4,R1			; number of parameters
     MOV	R1,R0			; pointer to string

._setloop
     TEQ	R4,#0			; any parameters left ?
     BEQ	_reinitNewMap

     SUB	R4,R4,#1		; decrement parameters.

     ; Scan for modenumber
     MOV	R0,#ReadUnsignedFlags	; base; R1 is still pointing to next argument.
     MOV	R2,#127			; maximum value

     SWI	XOS_ReadUnsigned
     BVS	_returnSetModeError

     CMP	R2,#128			; is it a valid value ?
     ADDCS	R1,R1,#1
     BCS	_setloop			; No, then ignore

     ; Get the mode-bit ready
     MOV	R0,R6			; Get Tablebase.
     ADD	R0,R0,R2,LSR #3		; Tablebase + (Mode /32*4)
     BIC	R0,R0,#3		; Clear lowest 2 Bits.
     LDR	R5,[R0,#0]		; get this part of Table
     MOV	R3,#1			; This is our bit for that entry,
     AND	R2,R2,#31		; mask shift amount
     MOV	R3,R3,LSL R2		; shift our bit to correct position.

     ; Check the sign for '+' or '-'
     LDRB	R2,[R1,#0]		; load the signal-character
     TEQ	R2,#ASC("+")		; and decide....
     ORREQ	R5,R5,R3		; ...Set the bit to one.
     TEQ	R2,#ASC("-")		; or
     BICEQ	R5,R5,R3		; ...Reset the bit to zero.

     ; Store the mode-bit again
     STR	R5,[R0,#0]
     ADD	R1,R1,#1		; Increment string-pointer for next parameter.
     B		_setloop

._reinitNewMap
	BL	AutoVIDC_ReInitSWI	; do a new init, maybe we changed...
	LDMFD 	R13!,{R0-R6,PC}		; No parameters so return

._returnSetModeError
	LDMFD	R13!,{R0-R6,R14}

	ADR	R0,seterror		; Load up the error message.
	B       exitWithError

; ---------------------------------------------------------------------------
; Provide support for * commands for Enabling and Disabling of features

.disableVIDC
     STMFD	R13!,{R0,R14}
     MOV	R0,#0			; Set the VIDCEnable latch to 0
     B		enable_disableVIDC

.enableVIDC
     STMFD	R13!,{R0,R14}
     LDRB	R0,internal_flags
     TST	R0,#EnhancerNeeded	;is an enhancer needed?
     LDMNEFD	R13!,{R0,PC}		;NO
     MOV	R0,#1
.enable_disableVIDC
     LDR        R12,[R12,#0]		;R12->VARS
     STRB	R0,VIDCEnable		; set the VIDCEnable latch to 1
     BL		AutoVIDC_ReInitSWI	; re-initialise AutoVIDC
     LDMFD	R13!,{R0,PC}


.disableOC
     STMFD	R13!,{R0,R14}
     MOV	R0,#1
     B          enable_disableOC

.enableOC
     STMFD	R13!,{R0,R14}
     MOV	R0,#0
.enable_disableOC
     LDR        R12,[R12,#0]		;R12->VARS
     STRB	R0,OCdisable		; set the disableOC latch to 0
     BL		AutoVIDC_ReInitSWI	; re-initialise AutoVIDC
     LDMFD	R13!,{R0,PC}

; ---------------------------------------------------------------------------
; manually set the clock speed of the over clocking oscillator...

.setOCkHz
     STMFD	R13!,{R0-R2,R14}
     LDR        R12,[R12,#0]		;R12->VARS
     MOV	R1,R0			; pointer to string

     MOV	R0,#ReadUnsignedFlags	; base; R1 is still pointing to next argument.
     MOV	R2,#VIDCclkMAX		; maximum value 60MHz

     SWI	XOS_ReadUnsigned
     BVS	_clockSpeedTooHigh
     STR	R2,detectedClockSpeeds+12
     LDMFD	R13!,{R0-R2,PC}

._clockSpeedTooHigh
     MOV	R0,#1
     STRB	R0,OCdisable			; set the disableOC latch to 1
     LDMFD	R13!,{R0-R2,R14}		; if we're here, the clock speed is *way too high*
     ADR	R0,clockTooHigh			; Load up the error message.
     B		exitWithError

; ---------------------------------------------------------------------------
; Disable and Enable RISC OS control of mode selection on earlier Arc's

.disableROcontrol
     STMFD	R13!,{R0,R14}
     MOV	R14,#ROinControl
     B		enable_disable_ROcontrol

.enableROcontrol
     STMFD	R13!,{R0,R14}
.enable_disable_ROcontrol
     LDR        R12,[R12,#0]		;R12->VARS
     LDRB	R0,internal_flags
     TST	R0,#ROcanControl	;can RISC OS control the VIDC clock?
     LDMNEFD	R13!,{R0,PC}		;NO

     TEQ	R14,#ROinControl	;Are we enabling
     BICNE	R0,R0,#ROinControl	;YES
     ORREQ	R0,R0,#ROinControl	;NO
     STRB	R0,internal_flags
     BL		AutoVIDC_ReInitSWI	; re-initialise AutoVIDC
     LDMFD	R13!,{R0,PC}
; ---------------------------------------------------------------------------
; Toggle the long memory POST tests on RISC OS 3. Not convinced Acorn ever implemented this...

.toggleVIDCPost
     STMFD	R13!,{R0-R3,R14}

     MOV	R0,#161			; Read the CMOS RAM to see what the byte is set to
     MOV	R1,#188
     SWI	XOS_Byte		; returns the byte in R2

     MOV	R0,#162			; Prepare to write the value back.
     MOV	R3,#128			; We want to OR the value with 128
     EOR	R2,R2,R3
     SWI	XOS_Byte
     LDMFD	R13!,{R0-R3,PC}

 ; --------------------------------------------------------------------------
 ; Change the screen mode

.AutoVIDC_Mode
	STMFD	R13!,{R0-R3,R14}
        MOV	R1,R0

        MOV	R0,#ReadUnsignedFlags	; base; R1 is still pointing to next argument.
	MOV	R2,#127			; maximum value 127
	SWI	XOS_ReadUnsigned
	BVS	_noModeChange

      	SWI	XOS_WriteI+22		; VDU 22
      	MOV	R0,R2
      	SWI	XOS_WriteC
	LDMFD	R13!,{R0-R3,PC}

._noModeChange
	LDMFD	R13!,{R0-R3,R14}

	ADR	R0,setModeError			; Load up the error message.
.exitWithError
        CMPVC   R0,#1<<31		; Set V
;	CMNVC	R0,#1<<31		; unnecessary as R0 is always an error pointer that's <&80000000
	MOV	PC,R14



; ---------------------------------------------------------------------------
 ; Report back the relevant system details as AutoVIDC sees things...

DCB	1+LCDMonitor - MonitorTypes
DCB	1+SVGAMonitor- MonitorTypes
DCB	1+VGAMonitor - MonitorTypes
DCB	1+Mono       - MonitorTypes
DCB	1+Multiscan  - MonitorTypes
DCB	1+TVMonitor  - MonitorTypes
.MonitorTypes
	DCB "unknown",0
.TVMonitor
	DCB "50Hz TV",0
.Multiscan
	DCB "Multiscan",0
.SVGAMonitor
	DCB "S"
.VGAMonitor
	DCB "VGA",0
.Mono
	DCB "64Hz hi-res mono",0
.LCDMonitor
	DCB "LCD",0
ALIGN


.VIDCStatus
	STMFD	R13!,{R0-R5,R14}
        LDR     R12,[R12,#0]		;R12->VARS
; -------------------------------------------------------
; Output the detected VIDC Enhancer type and whether it was detected or is assumed.
; -------------------------------------------------------
	LDRB	R1,EnhancerType
	CMP	R1,#AuxIOType
	ADRLO	R0,strNativeEnhancer
	ADREQ	R0,strAuxIO
	ADRHI	R0,strWatford
	SWI	XOS_Write0
	SWI	XOS_WriteS
	DCB	"VIDC Enhancer", 0
	ALIGN
	LDRB	R1,internal_flags
	TST	R1,#EnhancerDetected
	ADREQ	R0,strAssumed
	ADRNE	R0,strDetected
	BL	writeStringNewLine

; -------------------------------------------------------
; Output the monitor type and whether mode mapping is enabled
; -------------------------------------------------------
	BL	getMonitorTypeAndMode
	MOV	R2,R1			;R2=monitor type
	MOV	R3,R0			;R3=mode
	SWI	XOS_WriteS
	DCB	"Monitor type: ",0
	ALIGN

	ADR	R0,MonitorTypes-1
	CMP	R2,#5			; lookup monitor type
	LDRLSB	R1,[R0,-R2]
	MOVHI	R0,#1			; unknown monitor
	ADD	R0,R0,R1
	BL	writeStringNewLine

; -------------------------------------------------------
; If we know the MonitorType, we can say if mode mapping is enabled.
; -------------------------------------------------------
	SWI	XOS_WriteS
	DCB	"MODE mapping: ",0
	ALIGN

	ADR	R0,_strDisabled
	TEQ	R2,#3
 	TEQNE	R2,#4
	ADREQ	R0,_strEnabled
	BL	writeStringNewLine

; -------------------------------------------------------
; Output the current screen MODE
; -------------------------------------------------------
	SWI	XOS_WriteS
	DCB	"Current MODE: ",0
	ALIGN

	MOV	R0,R3
	BL	convertCardinal2
	BL	writeStringNewLine

; -------------------------------------------------------
; Output the current detected clock speed.
; -------------------------------------------------------
 ; Lets ask what the clock speed is set to.
	SWI	XOS_WriteS
	DCB	"VIDC clock: ",0
	ALIGN
	MVN	R0,#0			; If we pass in a value other than 0 to 3...
	BL	AutoVIDC_SetClockSWI	; the SWI returns 0, 1, 2, or 3 depending on the clock speeds which are 24, 25.175, 36 and overclocked respectively.

	ADR	R4,detectedClockSpeeds
	LDR	R0,[R4,R0,LSL#2]
	BL	convertCardinal2
	SWI	XOS_Write0
	SWI	XOS_WriteS
	DCB	"kHz",10,13,"AutoVIDC: ",0
	ALIGN

; -------------------------------------------------------
; Output the state of AutoVIDC
; -------------------------------------------------------
	LDRB	R1,VIDCEnable
	TEQ	R1,#1
	ADREQ	R0,_strEnabled
	ADRNE	R0,_strDisabled
	BL	writeStringNewLine

; -------------------------------------------------------
; Output the status of the VIDC POST check in the CMOS.
; -------------------------------------------------------
	SWI	XOS_WriteS
	DCB	"VIDC POST check: ",0
	ALIGN

	MOV	R0,#161
	MOV	R1,#188
	SWI	XOS_Byte
	TST	R2,#128
	ADRNE	R0,_strDisabled
	ADREQ	R0,_strEnabled
	BL	writeStringNewLine

	SWI	XOS_WriteS
	DCB	"Detected clocks:",10,13,0
	ALIGN

;	LDRB	R1,EnhancerType
	MOV	R5,#0
._detected_clocks
	SWI	XOS_WriteI+ASC(" ")
	ADD	R0,R5,#ASC("0")
	SWI	XOS_WriteC
	SWI	XOS_WriteI+ASC(":")
;	TEQ	R1,#WatfordType			;is it a Watford VIDC Enhancer?
;	TEQEQ	R5,#1				;YES, is it clock 1?
;	BEQ	_skip_this_clock		;YES, skip as WE uses clocks 0,2,3
	LDR	R0,[R4],#4
	TEQ	R0,#0
._skip_this_clock
	SWIEQ	XOS_WriteI+ASC("-")
	BEQ	_no_clock
	BL	convertCardinal2
	SWI	XOS_Write0
	SWI	XOS_WriteS
	DCB	"kHz",0
	ALIGN
._no_clock
	SWI	XOS_NewLine
	ADD	R5,R5,#1
	TEQ	R5,#4
	BNE	_detected_clocks

	LDMFD	R13!,{R0-R5,PC}

._strEnabled
	DCB "Enabled",0
._strDisabled
	DCB "Disabled",0
ALIGN