Files
Digital-Research-Source-Code/MPM OPERATING SYSTEMS/MPM I/MPM I SOURCE/03/dsptch.asm
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1049 lines
16 KiB
NASM
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

$title('MP/M 1.1 Dispatcher')
name dsptch
;dsptch:
;do;
;/*
; Copyright (C) 1979,1980
; Digital Research
; P.O. Box 579
; Pacific Grove, CA 93950
;
; Revised:
; 18 Jan 80 by Thomas Rolander
;*/
;/*
; Common Literals
;*/
; declare true literally '0FFFFH';
; declare false literally '0';
; declare forever literally 'while true';
; declare boolean literally 'byte';
; declare enter$region literally
; 'disable';
;/*
; Proces Literals
;*/
; declare process$header literally
; 'structure (pl address,
; status byte,
; priority byte,
; stkptr address';
; declare bdos$save literally
; 'disk$set$dma address,
; disk$slct byte,
; dcnt byte,
; searchl byte,
; searcha address,
; thread address,
; scratch (14) byte)';
; declare process$descriptor literally
; 'process$header,
; name (8) byte,
; console byte,
; memseg byte,
; b address,
; bdos$save';
; declare rtr$status literally '0',
; dq$status literally '1',
; nq$status literally '2',
; poll$status literally '3',
; FlgWt$status literally '4',
; Delay$status literally '5',
; Swap$status literally '6',
; Terminate$status literally '7',
; Set$Prior$status literally '8',
; Dispatch$status literally '9',
; Attach$status literally '10',
; Detach$status literally '11',
; Set$cns$status literally '12';
;/*
; Memmgr Literals
;*/
; declare memory$descriptor literally
; 'structure (base byte,
; size byte,
; attrib byte)';
;/*
; Th Literals
;*/
; declare nmb$consoles literally '2';
extrn maxcns
;/*
; Bdosi Externals
;*/
; xios$pl:
extrn xiospl
; procedure (device) byte external;
; declare device byte;
; end xios$pl;
; xios$ms:
extrn xiosms
; procedure (memsegadr) external;
; declare memsegadr address;
; end xios$ms;
; str$clk:
extrn strclk
; procedure external;
; end str$clk;
;/*
; Flag Externals
;*/
; declare sys$flag (1) address external;
extrn sysflag
;/*
; Memmgr Externals
;*/
; declare memsegtbl (1) memory$descriptor external;
extrn memsegtbl
; user$process:
extrn userprocess
; procedure (pdadr) byte external;
; declare pdadr$address;
; end user$process;
; mem$fr:
extrn memfr
; procedure (mdadr) external;
; declare mdadr address;
; end mem$fr;
;/*
; Th Externals
;*/
; attach:
extrn attach
; procedure (pdadr) external;
; declare pdadr address;
; end attach;
; detach:
extrn detach
; procedure (pdadr) external;
; declare pdadr address;
; end detach;
dseg
; declare rlr address external;
extrn rlr
; declare rlrpd based rlr process$descriptor;
; declare thread$root address external;
extrn thrdrt
; declare drl address external;
extrn drl
; declare drlpd based drl process$descriptor;
; declare plr address external;
extrn plr
; declare dlr address external;
extrn dlr
; declare slr address external;
extrn slr
; declare indisp byte public initial (0);
public indisp
indisp: db 0
; declare dsptch$param address public;
public dparam
dparam:
dsptchparam:
dw 0
; declare pdadr address;
pdadr:
dw 0
; declare pd based pdadr process$descriptor;
; declare pollpointer address;
pollpointer:
dw 0
; declare oldpollptr address;
oldpollptr:
nextthreadptr:
dw 0
; declare oldpoll based oldpollptr address;
; declare next$thread$ptr address at (.oldpollptr);
; declare next$thread based next$thread$ptr address;
; declare pdladr address;
pdladr:
dw 0
; declare pdl based pdladr process$descriptor;
; declare first$time boolean;
;/*
; delay$list$insert:
; The purpose of the delay list insert procedure is to
; place a process descriptor on the delay list. The delay
; list is maintained in such a manner that the tick counts
; in the process descriptor represent the value required to
; produce the specified delay, by adding together all the
; tick counts of the preceding processes on the delay list.
; Entry Conditions:
; Dispatch$param = ticks
; Exit Conditions:
; Note
; *** NOTE *** this procedure assumes that
; a critical region has been entered.
;*/
cseg
; delay$list$insert:
delaylistinsert:
; procedure;
dseg
; declare accum address;
accum:
dw 0
; declare nxtpdladr address;
nxtpdladr:
dw 0
; declare nxtpdl based nxtpdladr address;
;
cseg
; dsptch$param = dsptch$param+1;
lxi h,DSPTCHPARAM
inr m
; if dlr = 0 then call strclk;
LHLD DLR
MOV A,H
ORA L
CZ STRCLK
; accum = 0;
LXI H,0H
SHLD ACCUM
; nxtpdladr = .dlr;
LXI H,DLR
SHLD NXTPDLADR
; do forever;
;
@25:
; pdladr = nxtpdl;
MOV E,M
INX H
MOV D,M
XCHG
SHLD PDLADR
; if (nxtpdl = 0) or
XCHG
DCX H
MOV A,M
INX H
ORA M
JZ @25A
LXI H,10H
DAD D
XCHG
LHLD ACCUM
CALL PADD
LXI D,DSPTCHPARAM
CALL PSUB
JNC @3
; ((accum + pdl.b) > dsptch$param) then
; do;
@25A:
; pd.pl = nxtpdl;
LHLD NXTPDLADR
MOV C,M
INX H
MOV B,M
DCX H
XCHG
LHLD PDADR
MOV M,C
INX H
MOV M,B
; nxtpdl = pdadr;
DCX H
XCHG
MOV M,E
INX H
MOV M,D
; accum = dsptch$param - accum;
LHLD ACCUM
LXI D,DSPTCHPARAM
CALL PADD
SHLD ACCUM
; pd.b = accum;
XCHG
LXI B,10H
LHLD PDADR
DAD B
PUSH H
MOV M,E
INX H
MOV M,D
; if pd.pl <> 0 then pdl.b = pdl.b - accum;
LHLD PDADR
MOV A,M
INX H
ORA M
POP D
RZ
LHLD ACCUM
CALL PSUB
XCHG
DCX H
MOV M,E
INX H
MOV M,D
; return;
RET
; end;
@3:
; accum = accum + pdl.b;
LXI B,10H
LHLD PDLADR
DAD B
XCHG
LHLD ACCUM
CALL PADD
SHLD ACCUM
; nxtpdladr = nxtpdl;
LHLD NXTPDLADR
MOV E,M
INX H
MOV D,M
XCHG
SHLD NXTPDLADR
; end;
JMP @25
; end;
; end delay$list$insert;
PADD:
; HL = [DE] + HL
LDAX D
ADD L
MOV L,A
INX D
LDAX D
ADC H
MOV H,A
RET
PSUB:
; HL = [DE] - HL
LDAX D
SUB L
MOV L,A
INX D
LDAX D
SBB H
MOV H,A
RET
;/*
; insert$process:
; The purpose of the insert process procedure is to
; place a process desciptor into a list pointed to by a
; passed parameter in priority order. The algorithm
; searches for a process in the list with a lower priority
; (lower priorities have high priority numbers) to make
; the insertion. This ensures that processes of the same
; priority are round-robin scheduled.
; Entry Conditions:
; BC = list root
; DE = process descriptor
; *** NOTE *** this procedure assumes that
; a critical region has been entered.
; Exit Conditions:
; None
;*/
cseg
@5:
MOV B,H
MOV C,L
; insert$process:
inspr:
insertprocess:
; procedure (nxtpdladr,pdadr) public;
public inspr
; declare (nxtpdladr,pdadr) address;
; declare nxtpdl based nxtpdladr address;
; declare pd based pdadr process$descriptor;
; do forever;
; pdladr = nxtpdl;
; BC = NXTPDLADR, DE = PDADR
@27:
LDAX B
MOV L,A
INX B
LDAX B
MOV H,A
; if (nxtpdl = 0) or
ORA L
INX D
INX D
INX D
LDAX D
DCX D
DCX D
DCX D
JZ @27A
; HL = PDLADR
INX H
INX H
INX H
SUB M
DCX H
DCX H
DCX H
JNC @5
; (pd.priority < pdl.priority) then
; do;
; pd.pl = nxtpdl;
@27A:
MOV A,L
STAX D
INX D
MOV A,H
STAX D
DCX D
; nxtpdl = pdadr;
MOV A,D
STAX B
DCX B
MOV A,E
STAX B
; return;
RET
; end;
; nxtpdladr = nxtpdl;
; end;
; end insert$process;
;/*
; dispatch:
; The purpose of the dispatch procedure is to perform the
; action required by the status of the current running
; process, to determine the highest priority ready process,
; and then to give it the processor resource. The procedure
; takes all the processes linked to the dispatcher
; ready list and inserts them into the ready list before
; executing the highest priority ready process.
; Entry Conditions:
; None
; Exit Conditions:
; None
;*/
dseg
svhl: ds 2 ; saved HL
svde: ds 2 ; saved DE
svret: ds 2 ; saved return
svsp: ds 2 ; saved SP
dspstk:
dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h
dw 0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h,0c7c7h
cseg
; dispatch:
pdisp:
public pdisp
; Note: This entry point should only be used from an
; interrupt handler, i.e. interrupts disabled.
; rlrpd.status = dispatch
di
shld svhl
lhld rlr
inx h
inx h
mvi m,9
lhld svhl
dispatch:
; procedure public;
public dispatch
; enter$region;
DI
;
; save registers in the Process Desciptor
;
shld svhl
pop h
shld svret
push psw
lxi h,0
dad sp
shld svsp
xchg
shld svde
lhld rlr
lxi d,50
dad d
xchg
pop psw
lhld svret
push h
xchg
sphl
lhld svde
xchg
lhld svhl
PUSH PSW
PUSH B
PUSH D
PUSH H
; call svz80;
public dspsvz80
dspsvz80:
jmp noz80save
db 0ddh,0e5h ;Push IX
db 0fdh,0e5h ;Push IY
db 008h ;Ex AF,AF'
db 0d9h ;Exx
push psw
push b
push d
push h
noz80save:
mvi a,0ffh
sta indisp ;set in dipatcher flag
; pdadr = stackptr;
lhld svsp
XCHG
; rlrpd.stkptr = pdadr;
LHLD RLR
; pdadr = rlr;
SHLD PDADR
MOV B,H
MOV C,L
inx h
inx h
inx h
inx h
MOV M,E
INX H
MOV M,D
;
LXI SP,DSPSTK+24
; if rlrpd.status <> rtr$status then rlr = rlrpd.pl;
dcx h
dcx h
dcx h
MOV A,M
ORA A
JZ @7
DCX H
DCX H
MOV E,M
INX H
MOV D,M
XCHG
SHLD RLR
; do case pd.status;
MOV E,A
MVI D,0
LXI H,@29
DAD D
DAD D
MOV E,M
INX H
MOV D,M
LHLD DSPTCHPARAM
XCHG
PCHL
; /* status = 0, Ready to Run */
; do;
; end;
; /* status = 1, DQ */
; do;
@9:
; call insert$process (dsptch$param,pdadr);
; end;
; /* status = 2, NQ */
; do;
@10:
; call insert$process (dsptch$param,pdadr);
MOV H,B
MOV L,C
MOV B,D
MOV C,E
XCHG
; end;
JMP @6
; /* status = 3, Poll */
; do;
@11:
; pd.b = dsptch$param;
LXI H,10H
DAD B
MOV M,E
INX H
MOV M,D
; pd.pl = plr;
LHLD PLR
XCHG
LHLD PDADR
MOV M,E
INX H
MOV M,D
; plr = pdadr;
DCX H
SHLD PLR
; end;
JMP @7
; /* status = 4, Flag Wait */
; do;
@12:
; sys$flag(dsptch$param) = pdadr;
LXI H,SYSFLAG
DAD D
DAD D
MOV M,C
INX H
MOV M,B
; pd.pl = 0;
XRA A
STAX B
INX B
STAX B
; end;
JMP @7
; /* status = 5, Delay */
; do;
@13:
; call delay$list$insert;
CALL DELAYLISTINSERT
; end;
JMP @7
; /* status = 6, Swap */
; do;
@14:
; call insert$process (.slr,pdadr);
MOV D,B
MOV E,C
LXI B,SLR
; end;
JMP @6
; /* status = 7, Terminate */
; do;
@15:
; if dsptch$param = 0ffh or /* sys pr. term */
; user$process (pdadr) then
PUSH D
CALL USERPROCESS
POP D
RAR
JC @15A
INR E
JZ @15C
JMP @16
; do;
@15A:
; call mem$fr (.memsegtbl(pd.memseg));
; free memory segment only if BDOS system reset call
LHLD DSPTCHPARAM
INR H
JZ @15C
LXI B,0FH
LHLD PDADR
DAD B
MOV A,M
LXI H,MEMSEGTBL
ADD A
ADD A
MOV E,A
MVI D,0
DAD D
MOV B,H
MOV C,L
CALL MEMFR
@15c:
; call rlsmx (pdadr);
lhld pdadr
mov b,h
mov c,l
extrn rlsmx
call rlsmx ; release all owned MX queues
; call detach (pdadr);
LHLD PDADR
MOV B,H
MOV C,L
CALL DETACH
; next$thread$ptr = .thread$root;
LHLD PDADR
MOV B,H
MOV C,L
LXI H,thrdrt
@30:
; BC = PDADR, HL = NEXTTHREADPTR
; do while (pdladr := next$thread) <> pdadr;
MOV E,M
INX H
MOV D,M
; DE = PDLADR, NEXTTHREAD
MOV A,E
CMP C
JNZ @30A
MOV A,D
CMP B
JZ @31
@30A:
; next$thread$ptr = .pdl.thread;
LXI H,12H
DAD D
; end;
JMP @30
@31:
; next$thread = pdl.thread;
DCX H
XCHG
LXI B,12H
DAD B
MOV A,M
STAX D
INX D
INX H
MOV A,M
STAX D
; end;
JMP @7
@16:
; else
; do;
; pd.status = rtr$status;
LHLD PDADR
INX H
INX H
MVI M,0H
; pd.pl = drl;
; drl = pdadr;
; end;
; end;
JMP @19
; /* status = 8, Set Priority */
; do;
@18:
; pd.priority = dsptch$param;
INX B
INX B
INX B
MOV A,L
STAX B
; pd.pl = drl;
; drl = pdadr;
; end;
; JMP @19
; /* status = 9, Dispatch */
; do;
@19:
; pd.pl = drl;
LHLD DRL
XCHG
LHLD PDADR
MOV M,E
INX H
MOV M,D
; drl = pdadr;
DCX H
SHLD DRL
; end;
JMP @7
; /* status = 10, Attach */
; do;
;@20: (see end of set console)
; call attach (pdadr);
; end;
; /* status = 11, Detach */
; do;
@21:
; call detach (pdadr);
CALL DETACH
; pd.pl = drl;
; drl = pdadr;
; end;
JMP @19
; /* status = 12, Set Console */
; do;
@22:
; call detach (pdadr);
CALL DETACH
; if dsptch$param < nmb$consoles then
CALL MAXCNS
MOV B,A
LDA DSPTCHPARAM
CMP B
JNC @7
; do;
; pd.console = dsptch$param;
LXI B,0EH
LHLD PDADR
DAD B
MOV M,A
; call attach (pdadr);
@20:
LHLD PDADR
MOV B,H
MOV C,L
CALL ATTACH
; end;
; end;
JMP @7
; end; /* case */
@29:
DW @7
DW @9
DW @10
DW @11
DW @12
DW @13
DW @14
DW @15
DW @18
DW @19
DW @20
DW @21
DW @22
@6:
CALL INSERTPROCESS
@7:
; /* Put ready processes on ready list and poll
; devices required -> at least once then until
; there is a process ready to run */
; do while first$time or (rlr = 0);
@32:
; /* insert all processes on ready list from
; the dispatcher ready list */
; do while drl <> 0;
@34:
LHLD DRL
@34A:
MOV A,H
ORA L
JZ @35
; pdadr = drlpd.pl;
MOV E,M
INX H
MOV D,M
PUSH D
; drlpd.status = rtr$status;
INX H
MVI M,0H
; call insert$process (.rlr,drl);
DCX H
DCX H
XCHG
LXI B,RLR
CALL INSERTPROCESS
; drl = pdadr;
POP H
SHLD DRL
; end;
JMP @34A
@35:
; /* poll all required devices and place any
; readied processes on the ready list */
; pdadr = .plr;
LXI D,PLR
; pollpointer = plr;
LHLD PLR
; do while pollpointer <> 0;
@36: ; BC = oldpollptr, DE = pdadr, HL = pollpointer
MOV A,H
ORA L
JZ @37
; oldpollptr = pdadr;
MOV B,D
MOV C,E
; pdadr = pollpointer;
MOV D,H
MOV E,L
; pollpointer = pd.pl;
MOV A,M
INX H
MOV H,M
MOV L,A
; if xios$pl (pd.b) then
PUSH B
PUSH D
PUSH H
LXI H,10H
DAD D
MOV C,M
CALL XIOSPL
POP H
POP D
POP B
RAR
JNC @36
; do;
; oldpoll = pollpointer;
MOV A,L
STAX B
INX B
MOV A,H
STAX B
DCX B
PUSH B
PUSH H
; pd.status = rtr$status;
MOV H,D
MOV L,E
INX H
INX H
MVI M,0
; call insert$process (.rlr,pdadr);
LXI B,RLR
CALL INSERTPROCESS
POP H
POP B
; pdadr = oldpollptr;
MOV D,B
MOV E,C
; end;
; end;
JMP @36
@37:
; first$time = false;
; end;
; call xios$ms (.memsegtbl(rlrpd.memseg));
lhld rlr
LXI B,0FH
DAD B
MOV A,M
add a
jm @38 ;system process, no xiosms
add a
LXI H,MEMSEGTBL
mov e,a
mvi d,0
dad d
MOV B,H
MOV C,L
CALL XIOSMS
; stackptr = rlrpd.stkptr;
@38:
LHLD RLR
LXI B,4H
DAD B
MOV E,M
INX H
MOV D,M
XCHG
shld svsp
xra a
sta indisp ;clear in dispatcher flag
lhld rlr
lxi d,50-8
dad d
sphl
public dsprsz80
dsprsz80:
jmp noz80restore
lxi d,-12
dad d
sphl
pop h
pop d
pop b
pop psw
db 0d9h ;Exx
db 008h ;Ex AF,AF'
db 0fdh,0e1h ;Pop IY
db 0ddh,0e1h ;Pop IX
noz80restore:
POP H
POP D
POP B
POP PSW
; exit$region;
shld svhl
lhld svsp
sphl
lhld svhl
EI
RET
; end dispatch;
;end dsptch;
end