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

📄 tmrcode.inc

📁 MMURTL(tm) Computer Operating System Ver x0.8, source code.
💻 INC
字号:
;   MMURTL Operating System Source Code
;   Copyright 1991,1992,1993, Richard A. Burgess
;   ALL RIGHTS RESERVED
;   Version x0.8

; This file contains the following internal and Public calls
; dealing with time:
;
; IntTimer - The Timer ISR
; Sleep()
; Alarm()
; KillAlarm()
; GetCMOSTime()
; GetCMOSDate()
; MicroDelay()
; GetTimerTick()
;
;=============================================================================
;
; The timer interrupt checks up to n timer blocks for values to decrement.
; Because interrupts are disabled during the entire process, I have checked
; the amount of timer for best and worse case run. Best case is when no
; timer blocks are used. Worst case is when all timer blocks are used and
; they all expire at the same time (this is almost impossible but you never
; know).
;
; Interrupt latency can be a problem for high speed non-DMA comms.
; A single channel operating at 19,200 bps will interrupt every 520 us.
; Two channels will do it every 260us (continuous comms).
; That means our worst case will cause a problem if it occurs while
; two channels are running 19.2Kbps continuously.  The odds of more than a
; couple of	tasks being delayed and firing at the same time
; are pretty darned slim.
;
IntTimer:
		PUSHAD	      				;
		INC TimerTick               ;Timer Tick INT 20
		CMP nTmrBlksUsed, 0
		JE IntTmrEnd

		PUSH 0
		CALL FAR PTR _MaskIRQ       ;Don't let timer go off
		PUSH 0
		CALL FAR PTR _EndOfIRQ      ;Let others interrupt
		STI
		LEA EAX,rgTmrBlks           ;EAX has addr of blocks
		MOV ECX,nTmrBlks            ;ECX has count of blocks
		CLD							;Move forward thru the blocks
IntTmr01:
		CLI
		CMP [EAX.fInUse],FALSE		;Timer Block found?
		JE IntTmr03					;No  - goto next block
		CMP [EAX.CountDown],0h      ;Yes - is count at zero?
		JNE IntTmr02                ;No  - goto decrement it
		PUSH EAX                    ;save ptr to rgTmpBlk
		PUSH ECX                    ;save current count
		PUSH [EAX.TmrRespExch]		;Yes - ISend Message
		MOV EAX, -1					;FFFFFFFFh
		PUSH EAX		            ;bogus msg
		PUSH EAX        		    ;bogus msg
		CALL FAR PTR _ISendMsg		;tell him his times up!
		POP ECX                     ;get count back
		POP EAX                     ;get ptr back
		MOV [EAX.fInUse],FALSE      ;Free up the timer block
		DEC nTmrBlksUsed			;Correct count of used blocks
		JMP IntTmr03                ;skip decrement - empty blk
IntTmr02:
		DEC [EAX.CountDown]         ;10ms more gone...
IntTmr03:
		STI
		ADD EAX,sTmrBlk             ;next block please!
		LOOP IntTmr01               ;unless were done

		CLI
		PUSH 0
		CALL FAR PTR _UnMaskIRQ     ;Let the timer go off
		POPAD                       ;
		IRETD                       ;

IntTmrEnd:
		PUSH 0
		CALL FAR PTR _EndOfIRQ      ;
		POPAD                       ;
		IRETD                       ;

;=============================================================================
;
; Sleep - A Public routine that delays the calling process by setting
;       up a timer block with CountDown value and an Exchange to
;       send a message to when the countdown reaches zero.
;       The timer interrupt sends the message and clears the block
;       when it reaches zero.
;       This requires an exchange. The exchange
;       used is the TSS_Exch in the TSS for the current task.
;
DelayCnt	EQU [EBP+0Ch]
;
;
_Sleep	PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		MOV EAX, DelayCnt
		CMP EAX, 0					;See if there's no delay
		JE Delay03
		LEA EAX,rgTmrBlks           ;EAX points to timer blocks
		MOV ECX,nTmrBlks            ;Count of timer blocks
		CLD                         ;clear direction flag
Delay01:
		CLI                         ;can't let others interfere
		CMP [EAX.fInUse],FALSE      ;Empty block?
		JNE Delay02                 ;No  - goto next block
		MOV EBX,DelayCnt			;Get delay count
		MOV [EAX.CountDown],EBX     ;
		MOV [EAX.fInUse],TRUE       ;Use the Timer Block
		INC nTmrBlksUsed			;Up the blocksInUse count
		MOV ECX,pRunTSS             ;Get TSS_Exch for our use
		MOV EBX,[ECX.TSS_Exch]      ;
		MOV [EAX.TmrRespExch],EBX   ;put it in timer block!
		STI
		PUSH EBX                    ;Pass exchange (for WaitMsg)
		ADD ECX,TSS_Msg             ;Offset of msg area
		PUSH ECX
		CALL FAR PTR _WaitMsg       ;and Wait for it to come back
		MOV EAX,ErcOk               ;all is well
		JMP Delay03
Delay02:
		STI
		ADD EAX,sTmrBlk
		LOOP Delay01                ;unless were done
		MOV EAX,ErcNoMoreTBs        ;Sorry, out of timer blocks
Delay03:
		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 4                      ;
_Sleep	ENDP

;=============================================================================
;
; Alarm - A Public routine that sends a message to the exchange that the
;       caller specifies after the number of ticks specified.
;       The message is NOT repeatable (must be set up each time).
;       The message will always be two DWords with 0FFFFFFFFh in each.
;
;		Alarm(nAlarmExch, AlarmCnt):dErc
;
AlarmExch	EQU [EBP+10h]
AlarmCnt	EQU [EBP+0Ch]
;
;
_Alarm	PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		MOV EAX, AlarmCnt
		CMP EAX, 0					;See if there's no delay
		JE Alarm03
		LEA EAX,rgTmrBlks           ;EAX points to timer blocks
		MOV ECX,nTmrBlks            ;Count of timer blocks
		CLD                         ;clear direction flag
Alarm01:
		CLI                         ;can't let others interfere
		CMP [EAX.fInUse],FALSE      ;Empty block?
		JNE Alarm02                 ;No  - goto next block
		MOV EBX,AlarmCnt			;Get delay count
		MOV [EAX.CountDown],EBX     ;
		MOV [EAX.fInUse],TRUE       ;Use the Timer Block
		INC nTmrBlksUsed			;Up the blocksInUse count
		MOV EBX, AlarmExch
		MOV [EAX.TmrRespExch],EBX   ;put it in timer block!
		STI                         ;It's OK to interrupt now
		MOV EAX,ErcOk               ;all is well
		JMP Alarm03
Alarm02:
		STI                         ;It's OK to interrupt now
		ADD EAX,sTmrBlk
		LOOP Alarm01                ;unless were done
		MOV EAX,ErcNoMoreTBs        ;Sorry, out of timer blocks
Alarm03:
		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 8                      ;
_Alarm	ENDP
;=============================================================================
;
; KillAlarm - A Public routine that kills an alarm message that is
;       set to be sent to an exchange.  ALL alarms set to fire off
;		to that exchange are killed. If the alarm is already queued
;		through the kernel, NOTHING will stop it...
;
;		KillAlarm(nAlarmExch):dErc
;
KAlarmExch	EQU [EBP+0Ch]
;
;
_KillAlarm	PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		CMP nTmrBlksUsed, 0			;No blocks in use
		JE KAlarm03					; so we get out!
		MOV EBX,KAlarmExch			;Get exchange for killing alarms to
		LEA EAX,rgTmrBlks           ;EAX points to timer blocks
		MOV ECX,nTmrBlks            ;Count of timer blocks
		CLD                         ;clear direction flag
KAlarm01:
		CLI                         ;can't let others interfere
		CMP [EAX.fInUse],TRUE		;Block in use?
		JNE KAlarm02                ;No - goto next block
		CMP [EAX.TmrRespExch],EBX   ;Does this match the Exchange?
		JNE KAlarm02
		MOV [EAX.fInUse],FALSE      ;Make Empty
		DEC nTmrBlksUsed			;Make blocksInUse correct
KAlarm02:
		STI                         ;It's OK to interrupt now
		ADD EAX,sTmrBlk
		LOOP KAlarm01               ;unless were done
KAlarm03:
		XOR EAX,EAX			        ;ALl done -- ErcOk
		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 4                      ;
_KillAlarm	ENDP
;=============================================================================
;   MicroDelay(dDelay):derror  Delay count is in 15 us increments
;
; The timing for this delay is based on the toggle of the refresh bit
; from the System Status port.  The toggle is approxiamtely 15us.  This
; means this call will not be very accurate for values less than
; 3 or 4 (45 to 60 microseconds).  BUT, it's still very much needed.
;
_MicroDelay PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		MOV ECX, [EBP+0Ch]			;Get delay count
		CMP ECX, 0
		JE MDL01					;get out if they came in with 0!
MDL00:
		IN AL, 61h					;Get system status port
		AND AL, 10h					;check refrest bit
		CMP AH, AL					;Check toggle of bit
		JE MDL00					;No toggle yet
		MOV AH, AL					;Toggle! Move to AH for next compare
		LOOP MDL00
MDL01:
		XOR EAX, EAX
		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 4                      ;
_MicroDelay ENDP

;=============================================================================
;   GetCMOSTime(pdTimeRet):derror
;
; The Time is returned from the CMOS clock as a DWord.
; Low order byte is the Seconds (BCD),
; Next byte is the Minutes (BCD),
; Next byte is the Hours (BCD),
; High order byte is 0.
;
pCMOSTimeRet EQU [EBP+12]

_GetCMOSTime PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		XOR EBX, EBX				;Clear time return

	    MOV EAX,04h					;Hours
		OUT 70h,AL
		IN AL,71h
		MOV BL, AL

		SHL EBX, 8					;Minutes
	    MOV EAX,02h
		OUT 70h,AL
		IN AL,71h
		MOV BL,AL

		SHL EBX, 8              	;Seconds
	    MOV EAX,00h
		OUT 70h,AL
		IN AL,71h
		MOV BL,AL

		MOV ESI, pCMOSTimeRet		;Give 'em the time
		MOV [ESI], EBX
		XOR EAX, EAX				; No Error

		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 4                      ;
_GetCMOSTime ENDP

;=============================================================================
;   GetCMOSDate(pdTimeRet):derror
;
; The Date is returned from the CMOS clock as a DWord.
; Low order byte is the Day of Week (BCD 0-6 0=Sunday),
; Next byte is the Day (BCD 1-31),
; Next byte is the Month (BCD 1-12),
; High order byte is year (BCD 0-99).
;
pCMOSDateRet EQU [EBP+12]

_GetCMOSDate PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		XOR EBX, EBX				;Clear date return

	    MOV EAX,09h					;Year
		OUT 70h,AL
		IN AL,71h
		MOV BL, AL
		SHL EBX, 8					;

	    MOV EAX,08h					;Month
		OUT 70h,AL
		IN AL,71h
		MOV BL, AL
		SHL EBX, 8

	    MOV EAX,07h					;Day of month
		OUT 70h,AL
		IN AL,71h
		MOV BL,AL
		SHL EBX, 8              	;

	    MOV EAX,06h					;Day of week
		OUT 70h,AL
		IN AL,71h
		MOV BL,AL

		MOV ESI, pCMOSDateRet		;Give 'em the time
		MOV [ESI], EBX
		XOR EAX, EAX				; No Error

		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 4                      ;
_GetCMOSDate ENDP

;=============================================================================
;   GetTimerTick(pdTickRet):derror
;
; The Current Timer Tick is returned (it's a DWord).
;
pTickRet EQU [EBP+12]

_GetTimerTick PROC FAR
		PUSH EBP                    ;
		MOV EBP,ESP                 ;
		MOV ESI, pTickRet
		MOV EAX, TimerTick
		MOV [ESI], EAX
		XOR EAX, EAX				;No Error
		MOV ESP,EBP                 ;
		POP EBP                     ;
		RETF 4                      ;
_GetTimerTick ENDP

;====================== Module End =================================

⌨️ 快捷键说明

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