⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 power.asm

📁 DOS 源码 系列之 BIOS ,上传与大家分享
💻 ASM
📖 第 1 页 / 共 5 页
字号:

	; if activity has been detected DO_IDLE will be avoided
	; for a period measured in timer interrupts

	cmp     [SPDUP],0               ; is system speed up?
	je      did1ot

	mov     ax,[SPDUP_DLY]          ; check if enough time
did3ot: cmp     [SPDUP_CNT],ax          ; has passed to return
	jae     did2ot                  ; to normal idle

didxxx: pop     ax
	jmp     short didex1

did2ot: mov     [SPDUP],0
	mov     [SPDUP_DLY],0

did1ot: in      al,21h                  ; get interrupt mask
	test    al,3h                   ; make sure timer and
	jnz     didxxx                  ; keyboard aren't masked 

	add     word ptr [INFO].IDLE_TOT,1
	adc     word ptr [INFO].IDLE_TOT+2,0


IFDEF DEBUG

	test    [CONTROL].IDLE_FLG,SOUND_ACTIVE
	jz      did0ot

	call    START_SOUND

ENDIF                                   ; IFDEF DEBUG

did0ot: test    [CONTROL].IDLE_FLG,MEASURE_ACTIVE
	jz      didhlt
	mov     [IDLTIC],1              ; set IDLE flag ; M004

didhlt:

IFDEF INCL_APM
	cmp     fAPM_STATE,0            ; is APM present and enabled ?
	je      didNoAPM
	call    Do_APM_Idle
	jmp     short didResume
didNoAPM:
ENDIF   ; for IFDEF INCL_APM

IFDEF OEM_EXTENSION
	call    OEM_IDLE
ELSE
	call    CheckV86                ; M004 AVOID HLT IN V86
	jnz     didNoHlt
	sti                             ; interrupts must be enabled
	hlt                             ; or system will halt ...
didNoHlt:
ENDIF

didResume:

didot2: 
IFDEF DEBUG        
	test    [CONTROL].IDLE_FLG,SOUND_ACTIVE
	jz      didex0

	call    END_SOUND
ENDIF                                    ; IFDEF DEBUG

didex0: pop     ax
	stc                             ; CY.set halt executed
	ret
DO_IDLE endp

;********************* APM functions ***********************************

IFDEF INCL_APM

;********************* APM IDLE routine ********************************
; Called by Do_Idle procedure when APM BIOS is present
; 
; Psuedocode:
;       call APM_IDLE API
;       if (clock changes for CPU_IDLE API) {
;               call CPU_BUSY API
;       }
;
; Entry: nothing
; exit: nothing
;
;***********************************************************************
; Do_APM_CPUBUSY        Entry Point             (M002 addition)
;       Calls APM CPUBUSY API to return CPU to full speed after a resume
;               or a CPU_IDLE
; Entry: none
; Exit: none
;***********************************************************************
 
Do_APM_Idle     Proc    near

	push    bx
	mov     ax,APM_CPUIDLE_FUNC
	int     15h             ; make CPU_IDLE API call
	pop     bx
;
Do_APM_CPUBUSY  label   near            ; M002; added this entry point
;
; Check if we need to make a CPU_BUSY call 
	test    APM_FLAGS,APM_SLOW_CLOCK        ; does CPU_IDLE slows clock ?
	jz      dai_End

; need to make CPU_BUSY call
	push    bx
	mov     ax,APM_CPUBUSY_FUNC
	int     15h             ; make CPU_BUSY call to speedup CPU
	pop     bx
dai_End:
	ret

Do_APM_Idle     endp

;********************* Do_APM_Connect **********************************
; Purpose: to connect to APM BIOS as the coop.process (real mode only)
; Entry: none
; exit: CY      - connect failed
;               ax = error code
;       NC      - connection succeeded
;***********************************************************************

Do_APM_Connect  proc    near            ;M005

	test    fAPM_PRESENT,1          ; Do this only if APM is present
	jz      DAC_End
	mov     ax,APM_CONNECT_FUNC
	mov     bx,APM_SYSTEM_BIOS
	int     15h
	jc      DAC_End
	mov     fAPM_CONNECT,1
DAC_End:
	ret
Do_APM_Connect  endp

;********************* Do_APM_Disconnect **********************************
; Purpose: to disconnect from APM BIOS 
; Entry: none
; exit: CY      - Disconnect failed (can this ever happen ?)
;               ax = error code
;       NC      - disconnect succeeded
;***********************************************************************

Do_APM_Disconnect       proc    near

	test    fAPM_CONNECT,1          ; disconnect only if WE are 
	jz      DAD_End                 ; connected     
	mov     ax,APM_DISCONNECT_FUNC
	mov     bx,APM_SYSTEM_BIOS
	int     15h
	jc      DAD_End
	mov     fAPM_CONNECT,0
DAD_End:
	ret
Do_APM_Disconnect       endp
;********************* Do_APM_Enable_Disable **********************************
; Purpose: to enable/disable all power management 
;
; Entry: CX = APM_DO_DISABLE -> disable all power management
;           = APM_DO_ENABLE  -> enable all power management
;
; exit: CY      - function unsuccessful
;               ax = error code
;       NC      - function succeeded
;***********************************************************************


Do_APM_Enable_Disable   proc    near    ;M005

	mov     ax,APM_ENABLE_DISABLE_FUNC
	mov     bx,APM_ALL_DEVICES
	int     15h
	jnc     DAED_Ret
	mov     ax,ERROR_PM_NOT_CONNECTED
DAED_Ret:
	ret

Do_APM_Enable_Disable   endp


ENDIF           ; for IFDEF INCL_APM 

;********************* General Idle Check Routine **********************
; purpose: called by INT 28 and 16 interrupt handlers
;       This is the common routine which checks elapsed time between
;       interrupts in order to adjust idle signaling.
;
;       Entry : SI = base address of PERIOD_INFO structure for this interrupt
;               DI = address of total delay accumulator for this interrupt
;               BX = address of time accumulator for this interrupt
;               DS = our data segment
;       Exit  : nothing
;       must preserve all registers


public Chk_Delay
Chk_Delay       proc
	assume  ds:Bios_Data, es:nothing
	xor	cx,cx

; entry point for i16 idle checking
; for i16: cx = 1

Chk_i16idle	label	near
;
	push    ax
	cmp     word ptr [bx]+2,1      ; waited too long?
	jb	cd_readtime
	jmp	cd_ClrTmr              ; yes, do a recount

cd_readtime:
	call    READ_TMR0               ; read return time
	neg     ax
	cmp     word ptr [bx]+2,1
	jb      cd_0

	add     ax,0ffffh               ; OVERFLOW=-AX + 65535
	add     [bx],ax                 ; TICS=TICS + OVERFLOW
	jnc	cd_1
	jmp     cd_ClrTmr        	; Go recount on overflow

cd_0:
	add     [bx],ax                 ; TICS=TICS + -ax

cd_1: 	mov     ax,[si].BASE            ; is TIC >= BASE+THRESHOLD?
	add     ax,[CONTROL].THRESHOLD
	jnc     cd_2
	mov     ax,0FFFFh

cd_2:
	cmp     [bx],ax
	jae     cd_go_recount           ; yes, ignore reading   

	cmp     word ptr [si].ADAPT,0   ; are we in adapt cycle ?
	jne     cd_3			; yes go do avg.

; we are in idle cycle. check to see if we are within allowed limites for
; idle
	mov     ax,[si].BASE            ; is TIC <= BASE+NOISE?
	add     ax,[si].NOISE
	cmp     [bx],ax
	jbe     cd_doidle                 ; yes, stay in halt state

; we are above the allowed idle limits; go for adapt cycles

cd_adapt:
	mov     word ptr [si].ADAPT,1   ; start measuring increase
	mov     word ptr [si].DELAY,0

cd_go_recount:
	jmp     short cd_transf_period

; adapt cycle processing
; try calculating avg.
; [bx] = current period
; [si].PERIOD = avg so far
; if the current period is not within 50% of prev. avg we check to see if
; we can ignore this period for avg and go for next one. If we have seen 
; a no of such high(or low) values in the cycle so far, then start adapt
; cycle all over again

cd_3:
	mov     ax,[CONTROL].ADAPT_DLY
	cmp     [si].DELAY,ax           ; is delay over?
	jae	cd_end_adapt		; yes, go cmp our avg with baselineref
	mov	ax,[si].PERIOD
	shr	ax,1			; ax = 1/2 of avg
	shr	ax,1			; ax = .25 of avg
	push	ax

	push	bx
	mov	bx,ax
	add	ax,ax
	add	ax,bx			; ax = 0.75 of avg
	pop	bx

	add	ax,[si].PERIOD		; ax = 1.75 times avg
	cmp	ax,[bx]			; is current period more than 50% 
        pop	ax			; above our prev. period/avg
	jb	cd_throw_sample
	cmp	ax,[bx]			; ax = 1/2 of avg	
	ja	cd_throw_sample		; if below 0.5 (avg) then ignore this
;

	mov	ax,[bx]			; get current period
	add	ax,[si].PERIOD		; add previous period

; BUGBUG - nagara This should never happen ; we should rather ignore 
; this CY so that we get a low avg. this should help us not go idle when
; the period bet. ints are 32k apart
IFDEF DEBUG
	jnc	cd_4
	dbg_printchar 'o'
ENDIF
;	shr	ax,1
;	add	ax,8000h
;	jmp	short cd_5
; END BUGBUG

cd_4: 	shr	ax,1
cd_5:	mov	[bx],ax
	jmp	short cd_transf_period        ; go for next int

cd_end_adapt:
	mov	[ErrSampleCount],0
	mov     word ptr [si].ADAPT,0
	mov     ax,[si].PERIOD             ; for next compare ...
	jcxz	cd_setbase		; for i28 and i2f, no baseline ref.
	cmp	ax,[BaseLineRef]	; for i16, have a max limit for period
	jbe	cd_setbase		; 
	mov	ax,[BaseLineRef]
	mov	[si].BASE,ax		; go up to the max.allowed base
	shr	ax,1			; 50% of base
	mov	[si].NOISE,ax
	shr	ax,1			; 25% of base
	add	[si].NOISE,ax		; noise = 75% of base
	jmp	short cd_transf_period

cd_setbase:
	mov     [si].BASE,ax
	shr	ax,1			; 50% of base
	mov	[si].NOISE,ax
	shr	ax,1			; 25% of base
	add	[si].NOISE,ax		; noise = 75% of base
	
cd_doidle:
	call    DO_IDLE
	adc     word ptr [di],0         ; accumulate idle time
	adc     word ptr [di]+2,0
	mov     word ptr [bx]+2,0       ; avoid speed up error

cd_transf_period:
	mov	ax,[bx]
	mov     [si].PERIOD,ax
cd_ClrTmr:
	call    ClearTimer              ; do speedup if needed, clear 
					; timer accumulator
	pop     ax
	ret

cd_throw_sample:
	inc	[ErrSampleCount]	
	mov	ax,[ErrSampleCount]
	cmp	ax,[CONTROL].MAXERRSAMPLE
	jbe	cd_ClrTmr		; go try adapting again
	mov	[ErrSampleCount],0
	jmp	cd_adapt

Chk_Delay       endp




;*************** Timer clear and app speedup adjustment
;       Helper routine for Chk_Delay.  Called independently
;       by I16_IDLE when it detects a key waiting.  Calls APP_SPDUP
;       if required, and clears out timer overflow
;
;       Entry : BX = address of timer accumulator for this interrupt
;       Exit  : nothing
;       Uses AX -- caller must preserve

public  ClearTimer
ClearTimer         proc
	assume  ds:Bios_Data
	cmp     word ptr [bx]+2,3
	jb      ct_0
	call    APP_SPDUP               ; speedup proportional
					; to delay...
ct_0:
	mov     word ptr [bx]+2,0       ; clear key timer
	call    READ_TMR0
	mov     [bx],ax
	cmp     word ptr [bx]+2,0
	jne     ct_0

	ret

ClearTimer         endp


;********************* APPLICATION IDLE CHECK *******************
; purpose: check application idle (INT 2F Function 1680H)
;          if interrupt is detected than DO_IDLE should be called
;          the interrupt should be absorbed.

PUBLIC I2f_idle
I2f_idle proc   far
	assume  ds:nothing, es:nothing

	push    ds
	mov     ds, Bios_Data_Word
	assume  ds:Bios_Data

	cmp     ax,1680h                ; Any app idles?
	jne     i2F_chk_ours            ; check for a service call to us

; JAH Set the idle support byte in the current apps PSP
	push	ds
	mov	ds,PSPsegment		; DS:BX --> Current PSP in Dosdata
	mov	ds,WORD PTR ds:[CUR_PSP_OFFSET] ; DS -> current app's PSP
	assume	ds:Pdb_Data
	mov	PDB_Idle,IDLE_SUPPORT_BYTE ; Set this app's idle support byte
	pop	ds
	assume	ds:Bios_Data
; JAH end 

; load up registers and call do_idle
	push    di
	lea     di,[INFO].APP_TOT

; JAH	call    DO_IDLE			
	call	I2fIdleEntry		; JAH Use new idle entry point

	adc     word ptr [di],0         ; accumulate idle time
	adc     word ptr [di]+2,0

I2FIdleCleanup:				; JAH New label
	pop	di
	pop	ds
	iret

i2Fnxt: 
	jmp     dword ptr pwr_i2f_next

i2f_chk_ours:
	cmp     ah, MultPWR_API         ; is this a call for one of our ; M077
	jne     i2fnxt                  ; services ?
	pop     ds                      ; restore original vector
	call    Pwr_Services            ; one of our services
	iret                            ; no propagation

I2f_idle endp

;************************ I28_IDLE *********************

PUBLIC I28_idle
I28_idle proc
	assume  ds:nothing, es:nothing

	push    ds
	mov     ds,Bios_Data_Word
	assume  ds:Bios_Data

	inc     [I28].PCOUNT

	test    [CONTROL].IDLE_FLG,DOS_ACTIVE
	jz      i28ret

		; load up registers and call general delay checker
	push	cx
	push    bx
	push    si
	push    di
	lea     bx,I28_TMR0
	lea     si,I28
	lea     di,[INFO].DOS_TOT
	call    Chk_Delay
	pop     di
	pop     si
	pop     bx
	pop	cx

i28ret:

IFDEF   POWERALONE                      ; chain to next
	jmp     dword ptr pwr_i28_next
ELSE
	pop     ds
	assume  ds:nothing

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -