home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1987
/
12
/
holub
/
schedule.asm
< prev
next >
Wrap
Assembly Source File
|
1987-12-21
|
33KB
|
345 lines
PAGE 56,132
TITLE SPEEDUP.ASM: System-clock-modification routines
;------------------------------------------------------------
DEBUG equ 1 ; Set to 1 to make internal symbols public for
; debugging.
DOSPEED equ 1 ; Set to 0 to disable everything except
; global-variable initialization in speedup.
;------------------------------------------------------------
; Public Subroutines are:
;
; t_cli()
; Disable Interrupts
; t_sti()
; Enable Interrupts
;
;------------------------------------------------------------
; _t_speedup( factor )
; int factor;
;
; Speed up the system clock by the indicated factor
; (1, 2, 3, 4, etc.). Call the scheduler
; on every timer interrupt and call the default clock
; routine as well every "factor" ticks. For example,
; speedup( 2 ) speeds up the system clock by
; a factor of two; the normal interrupt-service
; routine that's used by DOS will be called every-
; other tick. A speedup factor of 1 or 0 doesn't modify
; the clock rate.
;
; _t_slowdown()
;
; Restore the clock to the normal speed and disconnect
; the routine installed with a previous speedup() call
; (if one is installed).
;------------------------------------------------------------
;
; t_block()
; t_release()
;
; Disable the scheduler but not the normal clock interrupt.
; The default system interrupt-service routine is processed
; in the normal way, on every Nth clock tick. Use these
; routines carefully. If they're used in a tight loop, it's
; possible that ALL timer interrupts will be ignored, even
; if the processor is released for a while inside the loop.
; In this situation sti() and cli() are better.
;
;------------------------------------------------------------
; long numint(); Number of unblocked interrupts.
; long numblk(); Number of blocked interrupts.
;
_TEXT SEGMENT BYTE PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT WORD PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
DGROUP GROUP CONST, _BSS, _DATA
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP
EXTRN __chkstk:NEAR
EXTRN __t_reschedule:NEAR
EXTRN _T_active:WORD
;------------------------------------------------------------
TIMR_CTRL = 43H ; address of timer control port
TIMR_0_DATA = 40H ; address of counter 0 data port
TIMR_0_LOAD = 36H ; control word for timer
STKSIZE = 256 ; Number of bytes on interrupt-
; service-routine stack
;------------------------------------------------------------
_TEXT SEGMENT
;------------------------------------------------------------
; Misc. variables. Note that I'm putting all these in the
; code (_TEXT) segment so that I can find them when an
; interrupt comes along. The PUBLIC statements are just for
; debugging.
old_int equ $
old_off dw ? ; Offset of old timer interrupt routine.
old_seg dw ? ; Segment address of same.
tick_reset dw ?
numticks dw ? ; Initialized to tick_reset, decre-
; mented on each timer interrupt,
; reset to the speedup factor (and the
; old service routine is called) when
; it reaches zero.
stack db STKSIZE dup (0) ; Local stack for service routine
; 30 bytes are used by real service
; routine, the rest is available
; for the user service routine.
stack_end dw ?
old_ds dw ?
old_sp dw ?
old_ss dw ?
old_ax dw ?
old_ip dw ?
old_cs dw ?
old_fl dw ?
numint dd 0 ; total number of interrupts
numblk dd 0 ; number of times user routine blocked
blocked db 0 ; don't execute user routine if true
IF DEBUG
PUBLIC old_int, old_off, old_seg, old_ds,
PUBLIC tick_reset, numticks, stack, stack_end, old_sp,
PUBLIC old_ss, old_ax, old_ip, old_cs, old_fl
PUBLIC blocked, serv, numint, numblk
ENDIF
;------------------------------------------------------------
; statistics stuff.
;
PUBLIC _t_numint, _t_numblk
_t_numint PROC NEAR
mov ax,WORD PTR cs:numint
mov dx,WORD PTR cs:numint+2
ret
_t_numint ENDP
_t_numblk PROC NEAR
mov ax,WORD PTR cs:numblk
mov dx,WORD PTR cs:numblk+2
ret
_t_numblk ENDP
;------------------------------------------------------------
; t_cli(); t_sti(); Disable and enable interrupts.
;
PUBLIC _t_cli, _t_sti
_t_cli PROC NEAR
cli
ret
_t_cli ENDP
_t_sti PROC NEAR
sti
ret
_t_sti ENDP
;------------------------------------------------------------
; t_block(); Disable and enable user interrupt service
; t_release(); routine but not the real interrupt service
; routine (or the interrupt itself).
PUBLIC _t_block, _t_release
_t_block PROC NEAR
mov byte ptr cs:blocked,1
ret
_t_block ENDP
_t_release PROC NEAR
mov byte ptr cs:blocked,0
ret
_t_release ENDP
;------------------------------------------------------------
; _t_speedup( factor )
; int factor;
; factor = [bp+4]
; routine = [bp+6]
PUBLIC __t_speedup
__t_speedup PROC NEAR
push bp
mov bp,sp
xor ax,ax
call __chkstk
mov _TEXT:old_ds,ds ; remember current DS.
mov ax,[bp+4] ; AX = factor
mov _TEXT:tick_reset,ax ; tick_reset = factor;
mov _TEXT:numticks,ax ; numticks = factor;
if DOSPEED
mov ax,[bp+4] ; if( factor && factor != 1)
cmp ax,01H ; {
je noload ;
cmp ax,00H ;
je noload ;
;
mov al,TIMR_0_LOAD ; Set up timer for load
out TIMR_CTRL,al ;
mov ax,00000H ; Number of ticks
mov dx,00001H ; = 65536/factor
mov bx,[bp+4] ; BX = factor.
div bx ; AX = number of ticks
cli ;
out TIMR_0_DATA,al ; Send new count to timer
mov al,ah ;
out TIMR_0_DATA,al ;
sti ; }
noload:
; Get the old vector
mov ah,35H ;
mov al,08H ;
int 21H ;
mov _TEXT:old_off,bx ;
mov _TEXT:old_seg,es ;
; set up the new vector
mov ah,25H ;
mov al,08H ;
mov dx,OFFSET _TEXT: serv ;
push ds ;
push cs ;
pop ds ;
int 21H ;
pop ds ;
endif
mov sp,bp
pop bp
ret
__t_speedup ENDP
;------------------------------------------------------------
PUBLIC __t_slowdown
__t_slowdown PROC NEAR
push bp
mov bp,sp
xor ax,ax
call __chkstk
mov ax,_TEXT:old_off ; See if the interrupts have
or ax,ax ; changed.
jz no_int ; No, don't fix them then
; restore old timer interrupt
push ds ;
mov ah,25H ;
mov al,08H ;
mov ds,_TEXT:old_seg ;
mov dx,_TEXT:old_off ;
int 21H ;
pop ds ;
no_int:
mov al,TIMR_0_LOAD ; Restore default system
out TIMR_CTRL,al ; clock tick rate
mov al,0
out TIMR_0_DATA,al
out TIMR_0_DATA,al
mov sp,bp
pop bp
ret
__t_slowdown ENDP
;------------------------------------------------------------
; Actual interrupt service routine.
; Note that the flags, cs, and ip are pushed on entry (because
; if the interrupt)
;
serv PROC NEAR
push ax
mov al, byte ptr cs:blocked ; If( servicing blocked)
or al,al ; {
jz serv1 ;
;
add WORD PTR cs:numblk,1 ; ++numblk;
adc WORD PTR cs:numblk+2,0 ;
jmp servexit ; }
serv1: ; else
add WORD PTR cs:numint,1 ; {
adc WORD PTR cs:numint+2,0 ; +numint;
push bx ;
push cx ; Save rest of
push dx ; current context
push si
push di
push bp
push ds
push es
mov ds,_TEXT:old_ds ; Restore Data segment
mov bx,_T_active ; BX = T_active
mov [bx],sp ; T_active->sp = SP
mov [bx+2],ss ; T_active->ss = SS
push cs ; Set up local stack
pop ss ;
mov sp,offset _TEXT: stack_end ;
call __t_reschedule ; in task.c
mov bx,_T_active ; BX = new T_active,
mov ss,[bx+2] ; will be the same as
mov sp,[bx] ; the old T_active if
pop es ; no change is reqd.
pop ds ;
pop bp ;
pop di ;
pop si ;
pop dx ;
pop cx ;
pop bx ;
;
servexit: ; }
dec _TEXT:numticks ; if(--numticks > 0)
jle serv3 ; {
mov al,20h ; send EOI
out 20h,al ;
pop ax
iret ; }
; else
serv3: ; {
mov ax,_TEXT:tick_reset ; numticks = tick_reset;
mov _TEXT:numticks,ax ;
pop ax ;
jmp dword ptr _TEXT:old_int ; jmp to old vector
; }
serv ENDP
_TEXT ENDS
END