📄 tmrcode.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 + -