|
|
DataMuseum.dkPresents historical artifacts from the history of: RC3500 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about RC3500 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 49920 (0xc300)
Types: TextFileVerbose
Names: »tpascrun«
└─⟦2c55ea56f⟧ Bits:30001844 SW-save af projekt 1000, Alarm-system
└─⟦6b41451d2⟧
└─⟦this⟧ »tpascrun«
(pascrun = slang
pascrun)
; pascal runtime system
; version 16
; date 81.05.05▶05◀
b. g3 w.
d.
p. <:fpnames:>
l.
k = h55
s. c10, d50, e30, f25, p20, r155 w.
; the first part of the variables are used
; by various library procedures
d0: 0, r.5 ; +0: (not used)
0, r.5 ;+10: (not used)
0, r.5 ;+20: (not used)
0, r.5 ;+30: stack chain for output
; the following variables describe the core-layout and some
; paging-dependant variables
; description of partitioning of core:
;
;
; low addresses
;
; ! !
; ! runtime !
; ! system !
; ! !
; !-----------!
; d1 --> ! ! first of stack
; ! !
; ! !
; !-----------!
; d2 --> ! ! stacktop
; ! !
; ! !
; !-----------!
; d6 --> ! ! first of proc nearest to stack
; ! !
; ! !
; !-----------!
; d8 --> ! ! first of last loaded proc (=top of next to load)
; ! !
; ! !
; !-----------!
; d9 --> ! ! last killed by heap-reservation
; ! !
; ! !
; !-----------!
; d10--> ! ! last used of heap
; ! !
; ! !
; !-----------!
; d11--> ! ! first of resident code
; ! !
; ! !
; !-----------!
; d12--> ! ! first of procedure table
; ! !
; ! !
; !-----------!
; d13--> ! ! first of library table
; ! !
; ! !
; !-----------!
; d14--> ! ! top of procedure table
; ! !
; ! fpstack !
; ! !
; ! !
;
; high addresses
d1: 0-0-0 ; first of stack
d2: 0-0-0 ; top of stack
d3: 512 ; (minimum room between (d2) and (d6))
d6: 0-0-0 ; first of proc nearest to stack
d7: 512 + 00 + 00 ; (minimum room between (d2) and (d10))
d8: 0-0-0 ; first of last loaded procedure
d9: 0-0-0 ; last killed by heap-reserve
d10: 0-0-0 ; last used of heap
d11: 0-0-0 ; first of resident procedures
d12: 0-0-0 ; first of procedure table
d13: 0-0-0 ; first of library table
d14: 0-0-0 ; top of proc table
d15: 000 ; maximum page size (to be reserved above (d10)
; the next variables are used for page-transfers
d4: <:pascallib:>,0,0 ; name of library
d5: 0, r.5 ; name of program file
d20: 0 ; zero ; dummy name (also used as illegal instruction by io-error)
d21: 3 < 12 ; input message
0 ;+2: first address
0 ;+4: last address (may also be top address)
0 ;+6: segment number
d22: 0 ; spare message buffer
d23: 0, r.8 ; answer
; format of procedure table:
p0 = 0 ; segment number in program/library file
p2 = 2 ; if not in core: negative size of procedure
; if in core : top address of procedure
p4 = 4 ; if pascal procedure: size of stack-space
; if library procedure: address of runtime error
p6 = 6 ; if in core : first address of procedure
; if not in core: zero, if never used
; else old first address
p8 = 8 ; if pascal procedure: virtual address of first error line
; if library procedure: saved stackref
p12 = 12 ; accumulated time (double word)
p14 = 14 ; number of calls
p10 =16 ; (size of entry)
; transfer
;
; call: w0 = segment number
; w2 = return
;
; exit: return+0: transfer not ok: w0 = logical status
; return+2: transfer ok : w0 = 2
b. a10, b10 w.
b0: 0 ; return
am d4-d5 ;f0-2: w3 := library name;
f0: al. w3 d5. ;f0+0: w3 := program name;
rs. w0 d21.+6 ; save segment number in message;
rs. w2 b0. ; save(return);
al. w1 d23. ; w1 := answer area;
al w2 0 ;
rx. w2 d22. ; spare mess buf := 0;
se w2 0 ; if spare mess buf was <> 0 then
jd 1<11+18; wait answer(spare mess buf);
; (it will only be zero just after startup,
; and in case of a break in this very procedure)
rl. w1 d44. ;
al w1 x1+1 ; increase(blocksread);
rs. w1 d44. ;
a0: ; rep:
al. w1 d21. ; w1 := message;
jd 1<11+16; send message(w1, w3);
al. w1 d23. ; w1 := answer;
jd 1<11+18; w0 := wait answer(w1, w2);
al w2 1 ; w2 := logical status :=
ls w2 (0) ; 1 shift result
sn w2 1<1 ;
lo w2 x1 ; + maybe status(answer);
sn w2 1<1 ; if status = 2 and
sh w2 (x1+2) ; bytes transferred < 2 then
jl. a1. ;
jl. a0. ; goto rep;
a1: ;
sz w2 1<1 ; if result <> ok then
jl. a2. ; begin
jd 1<11+52; create area process (name);
rs w0 x3+8 ; name table addr := undef;
sn w0 0 ; if ok then
jl. a0. ; goto rep;
al w1 x3 ; (prepare w1=name, for fp-exit)
sn. w1 d5. ; if name = library name then
jl. h7. ; goto fp-end-program(name,status);
a2: ; end;
al w0 x2 ; w0 := logical status;
al. w3 d20. ; w3 := dummy name;
jd 1<11+16; spare mess buf := send dummy message;
rs. w2 d22. ;
rl. w2 b0. ;
sn w0 1<1 ; if transfer ok then
jl x2+2 ; normal return
jl x2 ; else error return;
e. ;
; kill
;
; call: w0 = first addr to kill
; w1 = top addr to kill
; w3 = return
;
; exit: w0 = unchanged
; w1 = last addr to kill
; w2 = unchanged
; w3 = undef
b. a10, b10 w.
b0: 0 ; first addr to kill
b1: 0 ; last addr to kill
b2: 0 ; return
f1: ;
al w1 x1-2 ; w1 := last addr to kill;
ds. w1 b1. ; save (first addr, last addr);
rs. w3 b2. ; save (return);
rl. w3 d14. ; entry := top of proc table;
a0: ; next:
sn. w3 (d12.) ; if entry = first of proc table then
jl. (b2.) ; return;
al w3 x3-p10 ; decrease(entry);
sl w1 (x3+p6) ; if last to kill < first (entry) or
sl w0 (x3+p2) ; first to kill >= top (entry) then
jl. a0. ; goto next;
; if 'returnaddr' is killed then
; convert abs addr to: abs proc table entry, rel addr
rl. w0 d40. ; w0 := return addr;
sl w0 (x3+p6) ; if returnaddr inside proc (entry) then
sl w0 (x3+p2) ; <* note: can't be equal to top(proc) *>
jl. a5. ; begin
ws w0 x3+p6 ; rel return addr := returnaddr - first (entry);
ds. w0 d42. ; returnproc := entry;
al. w0 f2. ; returnaddr :=
rs. w0 d40. ; restore and return;
c. -1
m.*** begin testversion
rs. w3 b9.
al. w0 b10.
rl. w3 b2.
sh. w3 r8. ; if not called from 'new' then
jl. w3 h31.-2 ; outtext (warning)
rl. w3 b9.
jl. a5.
b9: 0
b10: <:<10>***pascal warning: calling procedure killed<10><0>:>
m.*** end testversion
z.
a5: ; end;
rl w0 x3+p6 ; w0 := first (entry);
; optimize stack-reservation
rl. w1 d6. ; if proc was nearest to stack then
sl w1 (x3+p6) ;
sl w1 (x3+p2) ;
jl. a6. ; begin
rl w1 x3+p2 ;
rs. w1 d6. ; closest to stack := top(entry);
a6: ; end;
ws w0 x3+p2 ; last (entry) :=
rs w0 x3+p2 ; negative size of procedure;
dl. w1 b1. ; restore (first,last to kill);
jl. a0. ; goto next;
e. ;
; restore and return
;
; (called because returnaddr was kill'ed)
;
; call: d41, d42 = return point
;
; exit: w2 = unchanged
f2: ;
jl. w1 f4. ; restore returnproc;
jl (0) ; return;
; get procedure and enter
;
; (called because procedure was not in core)
;
; call: w3 = rel (or abs) proc table entry
;
; exit: w1 = unchanged
; w2 = unchanged
; (w3 = abs proc table entry)
f3: ;
al w0 x1 ; (save w1);
jl. w1 f5. ; get procedure;
rl w1 0 ; (restore w1);
jl (x3+p6) ; goto procedure;
; restore returnproc
;
; call: w1 = return
; d41, d42 = return point
;
; exit: w0 = abs return addr
; w2 = unchanged
b. b10 w.
b0: 0 ;
f4: ;
rs. w1 b0. ; (save return);
dl. w0 d42. ; w0 := rel; w3 := proc table entry;
jl. w1 f5. ; get procedure;
wa w0 x3+p6 ; w0 := abs return := rel + first (entry);
rs. w0 d40. ; returnaddr := abs return;
jl. (b0.) ; return;
e. ;
; get procedure
;
; call: w1 = return
; w3 = abs proc table entry
;
; exit: w0 = unchanged
; w1 = undef
; w2 = unchanged
; w3 = abs proc table entry
b. a10, b10 w.
b0: 0 ; saved w0
b1: 0 ; return
b2: 0 ; saved w2
b3: 0 ; abs proc table entry
b4: 0 ; expected top
b5: 0 ; calling proc
f5: ;
ds. w1 b1. ;
ds. w3 b3. ;
rl w0 x3+p2 ; if top (entry) > 0 then
sl w0 0 ; <* proc is in core *>
jl. a10. ; goto return;
rl. w1 d43. ; calling proc :=
rs. w1 b5. ; current pascal proc;
; w0 = negative size of procedure
; step 1: try to fit just above last loaded procedure
wa. w0 d8. ; w0 := expected first addr;
a0: ; test against stack:
al w1 -1<9 ; ps stacktop :=
la w1 x3+p2 ; (rounded size of procedure
ac w1 x1 ;
wa w1 x3+p2 ; + negative size of procedure
wa. w1 d2. ; + stacktop
wa. w1 d3. ; + min room between stack and code;
sl w0 x1 ; if expected first >= ps stacktop then
jl. a2. ; goto found;
; step 2: try to fit just above heap
rl w0 x3+p2 ; w0 := expected first addr;
wa. w0 d10. ;
sh w0 x1-2 ; if expected first < ps stacktop then
jl. e1. ; alarm (process too small);
; <* should never occur, if 'd7' is properly set *>
a2: ; found:
; step 3: set (first,last) in procedure table
rs w0 x3+p6 ; first (entry) := expected first;
ws w0 x3+p2 ; expected top := expected first
rs. w0 b4. ; - negative size of procedure;
; step 4: compute first addr of transfer
; (it has already been tested that it will
; not interfere with the stack)
al w0 -1<9 ; w0 := negative size
la w0 x3+p2 ; rounded to integral number of used segments
wa. w0 b4. ; + top of procedure;
rl. w1 b4. ; w1 := top of procedure;
al w1 x1-2 ; w1 := last of procedure;
ds. w1 d21.+4 ; save (first,last) in message;
; step 4a: the procedure may not cross the maxpage boundary
; just above the heap
rl. w3 d10. ; boundary := last used of heap
ws. w3 d15. ; - maximum page size;
sl w1 x3 ; if last of transfer >= boundary and
sl w0 x3 ; first of transfer < boundary then
jl. a3. ; begin
al w0 x3 ; first := boundary;
jl. a5. ; goto set expected first;
a3: ; end;
; step 5: avoid killing of calling procedure
; (used by: call library procedure (optimization)
; call pascal procedure (because of string params)
al w3 0 ; calling proc := 0;
rx. w3 b5. ; w3 := old calling proc;
sn w3 0 ; if calling proc <> 0 then
jl. a6. ; begin
sl w1 (x3+p6) ; if last of transfer >= first (proc) and
sl w0 (x3+p2) ; first of transfer < top (proc) then
jl. a6. ; begin
; the calling proc was about to get kill'ed.
; try to fit the call'ed procedure just above it.
; repeat from step 1a.
rl w0 x3+p6 ; w0 := first (calling proc);
a5: ; set expected first:
rl. w3 b3. ; (restore called proc entry);
wa w0 x3+p2 ; w0 := expected first addr :=
; first(calling) + negative size(called);
jl. a0. ; goto test against stack;
a6: ; end;
; end;
; step 6: kill all procedures touched by the transfer
;
; w0 = first of transfer
; w1 = last of transfer
al w1 x1+2 ; w1 := top of transfer;
jl. w3 f1. ; kill;
rl. w3 b3. ; (restore proc entry);
al w1 x1+2 ;
; step 7: compute top addr for next procedure to be loaded
rl w0 x3+p6 ; w0 := first of procedure;
rs. w0 d8. ; first of last loaded := first of procedure;
; step 8: optimize stack-reserve and heap-reserve
sh. w0 (d6.) ; if top of next loaded <= closest to stack then
rs. w0 d6. ; closest to stack := top of next loaded;
sl. w1 (d9.) ; if top (entry) >= last killed by heap then
rs. w1 d9. ; last killed by heap := top (entry);
; step 9: load the procedure from program- or library file
rl w0 x3+p0 ; w0 := segm number (entry);
sl. w3 (d13.) ; if entry >= first of library table then
am -2 ; transfer from library file
jl. w2 f0. ; else transfer from program file;
jl. e3. ;+2: io-error
dl. w3 b3. ; restore(w2, proc table entry);
rl. w0 b4. ;
rs w0 x3+p2 ; top(entry) := expected top;
; step 10: exit
a10: ; return:
dl. w1 b1. ;
jl x1 ; return;
e. ;
; break routine
b. a10 w.
c0: ; interrupt address:
jd 1<11+0 ; set interrupt address;
rs. w1 d2. ; top of stack := w1;
al w0 0 ; w0 := procedure number of main program;
jl w3 (x2-2047) ; call pascal procedure
0 ;+2: occupied in stack = 0
r. (:c0.+h76:)>1+1; (fill up to size of dumped regs)
c1: ; top of regdump
dl. w3 c0.+12 ; w3 := cause; w2 := ic;
se w3 0 ; if cause = 0 and
jl. a2. ;
bl w0 x2-2 ; (w0 := break'ed instruction)
h. se w0, ks w. ; instruction = 'ks' then
jl. a2. ; begin
a0: ; enter fp-break:
al. w1 h10. ; move registers to fp;
a1: ;
rl w0 x1+c0-h10 ;
rs w0 x1 ;
al w1 x1+2 ;
se. w1 h10.+h76;
jl. a1. ;
jl x1 ; goto fp-break routine;
a2: ; end;
m.*** temporary: prevent calling break recursively
al w0 2
hs. w0 a0.-1
; if break occured inside runtime system then don't destroy returnaddr
sl. w2 (d2.) ; if ic >= stacktop then
rs. w2 d40. ; returnaddr := ic;
rl. w0 c0.+14 ; w0 := effective address;
se w0 -2047 ; if w0=nilvalue (e.g. after indirect)
bs w0 x2-1 ; or w0 - instr.disp = nilvalue
sn w0 -2047 ; (e.g. before indirect) then
am 24-5 ; errorcode := illegal pointer value
; else
am 5-3 ; errorcode := break;
e3: am 3-1 ; ioerror:
e1: am 1-25 ; process too small:
e25: al w1 25 ; dispose outside heap:
; call alarm-segment and transfer the returnpoint
c2: ; call and enter alarm:
; call: w0 = additional error inf
; w1 = text number
; d39 = stackref
; d40 = returnaddr (i.e. addr where error occured)
; (d41,d42 = returnpoint, if returnaddr just kill'ed)
rs. w0 d46. ; save (additional error inf);
rs. w1 d38. ; save (text number);
rl. w0 d40. ; w0 := returnaddr;
rl. w3 d14. ; w3 := top of library table
a3: ; next:
sn. w3 (d12.) ; if entry = first of proc table then
jl. a4. ; goto returnpoint set;
al w3 x3-p10 ; decrease (entry);
sh w0 (x3+p2) ; if returnaddr > top (entry) or
sh w0 (x3+p6) ; returnaddr <= first (entry) then
jl. a3. ; goto next;
; <* returnaddr can never be the first instruction
; in a procedure, but may well be the last *>
ws w0 x3+p6 ; w0 := rel addr := returnaddr - first(entry);
ds. w0 d42. ; save in return point;
a4: ; return point set:
; call alarm:
rl. w3 d13. ;
jl. w1 f5. ; get procedure ( alarm segment);
rl w0 x3+p6 ;
rl w1 x3+p6 ;
al w1 x1+512 ;
jl. w3 f1. ; kill first segment of procedure;
ds. w1 d21.+4 ; first,last in message := first of procedure;
rl. w0 d12. ; w0 := first of procedure table;
al. w1 c0. ; w1 := addr of interrupt routine;
rl. w2 d13. ; w2 := first of library table;
jl w3 (x2+p6) ; enter alarm procedure;
d38: 0 ;+0: error number
d39: 0 ;+2: stackref when error occured
d40: 0 ;+4: abs returnaddr where error occured
d41: 0 ;+6: return point: abs proc table entry
d42: 0 ;+8: rel return addr
d43: 0 ;+10: current pascal procedure
jl. a0. ;+12: goto enter fp-break
jl. f0. ;+14: goto transfer from program file
d44: 0 ;+16: blocksread
d45: 0 ;+18: abs return addr of last library call
d46: 0 ;+20: additional error inf
0
d47: 0 ; +22, +24: time stamp
e. ;
; runtime error
;
; call: w0 = additional error inf
; w1 = error number (0==program end)
; w2 = stackref
; w3 = address where error occured
r1: ;
ds. w3 d40. ;
jl. c2. ; goto call and enter alarm
; call library procedure
;
; call: w0w1 = parameters
; w2 = stackref
; w3 = return inf
; x3+0: library pageno < 12 + rel entry addr
; x3+2: maybe further parameters to library procedure
b. b10 w.
b0: 0 ; saved w0
b1: 0 ; saved w1
b10: p10 ; const: size of entry in proc tables
r3: ;
ds. w3 d40. ; save (stackref, return);
ds. w1 b1. ; save params;
bl w1 x3 ;
wm. w1 b10. ; w0 := 0; w1 := rel library entry;
wa. w1 d13. ;
al w3 x1 ; w3 := abs library proctable entry;
rs w2 x3+p8 ; save stackref in library proctable entry;
sl w0 (x3+p2) ; if library proc not in core then
jl. w1 f5. ; get procedure;
al w2 x3 ; w2 := library proc entry;
; since the library procedure may need to access parameters on
; the calling procedure page, it will be checked that the calling
; procedure is in core (but maybe at a new place)
rl. w0 d40. ;
sn. w0 f2. ; if calling proc just kill'ed then
jl. w1 f4. ; restore returnproc;
; begin test version
rl w1 x2+p2 ; if library proc not in core anymore then
sh w1 -1 ;
jl. e1. ; alarm...
; end test version
rl. w3 d40. ; w3 := abs return addr;
rs. w3 d45. ; (remember return addr, in case of errors)
bz w0 x3+1 ; w0 := rel entry addr
wa w0 x2+p6 ; + first (library proc);
rx. w0 b0. ;
rl. w1 b1. ; restore (params);
jl. (b0.) ; goto library proc;
; at entry to library proc:
; w0w1 = params
; w2 = abs addr of library proc table entry
; x2+p8 = saved stackref
; w3 = abs return addr
e. ;
; call pascal procedure
;
; call: w0 = procedure number
; w1 = abs addr of old display
; w2 = current stackref
; w3 = addr of call descriptor
; x3+0: stack space used by calling procedure
b. a10, b10 w.
b0: 0 ; calling proctable entry
b1: 0 ; old display
r4: ;
ds. w3 d40. ; save (stackref, return);
rs. w1 b1. ; save (old display);
al w1 x2 ; w1 := old stackref;
wa w2 x3+0 ; new stackref := old stackref + used space;
rs w1 x2-2037 ; activation record.dynamic list := old sref;
al w1 p10 ; w1 := entry size * procedure number
wm w1 0 ;
wa. w1 d12. ; + first of procedure table;
al w0 x3+2 ; w0 := abs return address; (* i.e. skip param *)
al w3 x1 ; w3 := abs addr of called proc table entry;
rl. w1 d43. ; w1 := current pascal procedure;
ws w0 x1+p6 ; w0 := rel return;
ds w1 x2-2041 ; activation record.return point :=
; (rel return, proc table entry);
al w1 x2 ; w1 := abs stacktop :=
wa w1 x3+p4 ; new sref + reserve (called proc);
; test that the new stackspace can be reserved
; step 1: first test that it is possible to reserve that much stack
rl. w0 d10. ; limit := last used of heap
ws. w0 d7. ; - room between stack and heap;
sh w0 x1-2 ; if abs stacktop > limit then
jl. e1. ; alarm(process too small);
; step 2: second, if new stacktop does not kill any pages then ok
; (remember to leave some room between stack and program)
rl. w0 d6. ; limit := first of proc nearest to stack
ws. w0 d3. ; - room between stack and program;
sl w0 x1 ; if abs stacktop <= limit then
jl. a5. ; goto stack reserved;
rs. w3 b0. ; save (entry);
rl. w0 d2. ; w0 := first to kill := old stacktop;
rs. w1 d2. ; stacktop := new stacktop;
wa. w1 d3. ; w1 := top to kill := new stacktop + spare room;
sl. w1 (d6.) ; if top to kill >= first of proc nearest to stack then
rs. w1 d6. ; first of proc nearest to stack := top to kill;
jl. w3 f1. ; kill;
rl. w3 b0. ; restore (entry);
rl. w1 d2. ; restore (new stacktop);
a5: ; stack reserved:
rs. w1 d2. ; stacktop := new stacktop;
sl w1 (x3+p2) ; if called proc not in core then
jl. w1 f5. ; get procedure;
rs. w3 d43. ; current pascal procedure := called proc;
; prepare alarm-inf, in case the procedure is breaked
; before it makes any runtime-system calls
rl w3 x3+p6 ;
ds. w3 d40. ; save (stackref, returnaddr);
rl. w1 b1. ; w1 := old display;
jl x3 ; goto procedure start;
; at entry to pascal procedure:
; w1 = abs addr of old display
; w2 = new stackref
e. ;
; return from pascal procedure
;
; call: w2 = current stackref
b. a10, b10 w.
b10: p10 ; size of procedure table entry
r6: ;
ds. w3 d40. ; save (stackref, return);
dl w1 x2-2041 ; w0 := rel return; w1 := return proc entry;
sh. w1 0 ; if after 'goto' to surrounding block then
jl. w3 a10. ; convert procedure number to abs proc table entry;
al w3 x1 ; w3 := abs proc table entry;
rl w2 x2-2037 ; w2 := dynamic link;
al w1 x2 ; stacktop :=
wa w1 x3+p4 ; stackref + reserve (return proc);
rs. w1 d2. ;
; prepare nice printout, in case of break before procedure is loaded
ds. w0 d42. ; returnpoint := (abs proc entry, rel return);
al. w1 f2. ; simulate just kill'ed;
rs. w1 d40. ;
rs. w2 d39. ; save stackref;
rs. w3 d43. ; current pascal proc := return proc;
sl w1 (x3+p2) ; if proc not in core then
jl. w1 f5. ; get procedure;
wa w0 x3+p6 ; abs return := rel return + first (entry);
jl (0) ; goto procedure;
a10: ; convert procedure number to abs proc table entry:
wm. w1 b10. ; w1 := proc entry := procedure number * entry size;
wa. w1 d12. ; w1 := abs procedure table entry;
rl w0 x2-2043 ; (restore w0)
jl x3 ; return;
e. ;
; value initialization
;
; call: w0 := abs address in stack
; w1 = no of segms to read
; w2 = stackref
; w3 = return addr
; x3+0: segment number in program file
; exit: w0 = undef
; w1 = undef
; w2 = stackref
; w3 = undef
b. b10 w.
b0: 0
b1: 0
r7: ;
ds. w3 d40. ; save (stackref, returnaddr);
ls w1 9 ; top of transfer := segments * 512
wa w1 0 ; + first of transfer;
ds. w1 d21.+4 ; save (first, top) in message;
rl w0 x3 ; w0 := segment number;
al w3 x3+2 ; (prepare eventual kill of program-page)
rs. w3 d40. ; return := after param;
jl. w2 f0. ; transfer;
jl. e3. ;+2: ioerror;
; the previous transfer did'nt test for overwriting of any
; program-pages
dl. w1 d21.+4 ; w0w1 := first,last to kill;
jl. w3 f1. ; kill;
dl. w3 d40. ; restore (stackref, returnaddr);
jl x3 ; return; (notice: automatic page-recovery)
e.
; new
;
; call: w0 = number of halfwords to reserve
; w1 = address of pointer variable
; w2 = stackref
; w3 = return
;
; exit: w0 = undef
; w1 = undef
; w2 = stackref
; w3 = undef
b. a10, b10 w.
b0: 0 ; number of halfwords
b1: 0 ; addr of pointer variable
r8: ;
ds. w3 d40. ; save (stackref, returnaddress);
ds. w1 b1. ; save (number of halfwords, addr of pointer);
; test that it is possible to allocate the wanted number of halfwords
; without having to kill any program pages
rl. w0 d10. ; new last of heap := last of heap
ws. w0 b0. ; - wanted space;
sl. w0 (d9.) ; if new last of heap >= last killed by heap then
jl. a5. ; goto heap reserved;
; it was nescessary to kill some pages.
; start by checking the amount to reserve
rl. w1 d2. ; limit := stacktop
wa. w1 d7. ; + room between stack and heap;
sh w0 x1-2 ; if new last of heap < limit then
jl. e1. ; alarm(process too small);
rs. w0 d9. ; last killed by heap := new last of heap;
sh. w0 (d8.) ; if first to kill <= first of last loaded then
rs. w0 d8. ; first of last loaded := first to kill;
rl. w1 d10. ; top to kill := last of heap;
jl. w3 f1. ; kill;
a5: ; heap reserved:
rs. w0 (b1.) ; pointer variable := last of head;
a7: ; kill at maxpage boundary:
; w0 = new last used of heap
rs. w0 d10. ; last used of heap := new last of heap;
ws. w0 d15. ; boundary := last used of heap- maxpage size;
rl w1 0 ; first,top to kill := boundary;
jl. w3 f1. ; kill;
jl. (d40.) ; return;
; dispose
;
; call: w0 = number of halfwords to release
; w1 = addr of pointer variable, pointing to the heap
; w2 = stackref
; w3 = return
;
; exit:
; w0 = undef
; w1 = undef
; w2 = stackref
; w3 = undef
r9: ;
ds. w3 d40. ; save (stackref, returnaddress);
wa w0 x1 ; w0 := new last of heap := top of record;
; test that the record really was within the heap
rl w3 x1 ; w3 := first of record;
bs. w0 1 ; w0 := last of record;
sl. w3 (d10.) ; if first of record < last of heap or
sl. w0 (d11.) ; last of record >= first of resident code then
jl. e25. ; alarm(try to release not used area);
ba. w0 1 ; w0 := new last used of heap := top of record;
al w3 -2047 ;
rs w3 x1 ; pointer variable := nil;
jl. a7. ; goto kill at maxpage boundary;
e. ;
r15: ; top of resident code, if not mode listing:
; alternative call and return from procedure
; accumulate time spent in procedure, and count number of activations
b. a10, b10 w.
b0: 0 ; saved w0
b1: 0 ; saved w1
r41:
ds. w3 d40. ; save (stackref, return )
ds. w1 b1. ; save ( old display )
dl w1 110 ; time of day
dl. w3 d47. ; old time
ds. w1 d47. ; update old time
ss w1 6 ; w0 1 := time delta
rl. w3 d43. ; address ( proc table )
aa w1 x3+p12 ; add time delta
ds w1 x3+p12 ; restore new acc. time
dl. w3 d40. ; goto normal call procedure
dl. w1 b1.
jl. r4.+2
e.
b. w.
r61:
ds. w3 d40. ; alternative return
dl w1 110 ; time of day
dl. w3 d47. ; old time
ds. w1 d47. ; updated old time
ss w1 6 ; w0 1 := time delta
rl. w3 d43. ; addrss ( proc table )
aa w1 x3+p12 ; add time spent
ds w1 x3+p12 ;
rl w1 x3+p14 ; increment( number of calls )
al w1 x1+1
rs w1 x3+p14
dl. w3 d40. ; goto normal return from procedure
jl. r6.+2
e.
r151: ; top of resident code if mode listing:
\f
; initialization code.
; at entry the situation is as follows :
; w0 - abs add of process start + h55
; w1 - abs add of process start
; w2 - abs add of first item in fp-stack
; w3 - abs add of item containing program name
;
; the init code takes care of the following points :
; 1) test for correct program call
; 2) set interrupt address
; 3) set abs add of some runtime entries in bottom of stack
; 4) create area process to object file and pascallib
; 5) read procedure table into core from object file
; 6) initialize procedure table entries (incl. entries concerning pascallib)
; 6a) input resident procedures
; 7) input main program and jump to entry of main
; 8) global variables are initialized when the values
; become available
;
\f
; the object file contains the following :
; - code for each procedure
; - value blocks to value initialization
; - procedure table
; - information segment (heapsize,noofproc * 10 etc)
; - line error table
;
; each of these types of items occupies an integral
; number of bs-segments. this means that a new item always
; starts on a bs-segment boundary.
; the segment number of the information segment is found in
; the catalog tail for the object file.
; the catalog entry tail contains in +17 cont key<12 + segmno of inf
;
; the information segment contains :
; +0 heapsize
; +2 no of procedures
; +4 segment no of procedure table
; +6 segment no of line error table
; +8 proc number of first resident procedure
; +10 - - - second - -
; .
; .
; +n -1 (end of resident procedures)
b. a40, b20 w.
b0 = 8 ; size of proc table entry in inf segment
b1: 4<12 + 10 ; spacename
b3: 0, r.10 ; tail for lookup entry
b4: 0 ; first of process
b5: 0, r.256 ; buffer for init-segment
b7: ; list of library procedure sizes
1536 ; page 0
512 ; page 1
512 ; page 2
512 ; page 3
1024 ; page 4
1024 ; page 5
1024 ; page 6
512 ; page 7
b8: (: k - b7 :) / 2 * p10 ; size of library proc table
b9: 0 ; proc table entry
b10: 0 ; size of proc
b11: 0 ; pointer variable
g3: ; start of initialization:
rs. w1 b4. ; save (first of process);
rs. w2 d14. ; top of proc table := first of command;
rl. w0 d5. ; if program file name already set then
se w0 0 ;
jl. a2. ; goto program file name found;
rs. w3 d14. ; save (addr of program name item, i.e. 'pascrun')
a0: ; get program file name:
ba w3 x3+1 ; w3 := first parameter;
rl w0 x3 ; if separator <> spacename then
se. w0 (b1.) ;
jl. a20. ; init error (error in call);
dl w1 x3+4 ; w0w1 := first part of program file name;
se w0 0 ; if first part = 0 then
jl. a1. ; begin <* after replace *>
am. (b4.) ;
rs w1 h51 ; fp-modebits := second word;
jl. a0. ; goto get program file name;
a1: ; end;
ds. w1 d5.+2 ;
dl w1 x3+8 ; move param to program file name;
ds. w1 d5.+6 ;
; remove the 'pascrun'-name from the command stack
; (this will make it easier for 'system'...)
rl. w2 d14. ; w2 := addr of program name item;
bl w0 x2+0 ; w0 := preceding separator;
se w0 6 ; if separator = 'equal' then
jl. a3. ; begin
dl w1 x2-0 ; move lefthand side up in
ds w1 x3-0 ; front of file name;
dl w1 x2-4 ;
ds w1 x3-4 ;
dl w1 x2-8 ; (don't forget the '=' item...)
ds w1 x3-8 ;
al w3 x3-10 ; first of command := addr of lefthand item;
a3: ; end;
rs. w3 d14. ; top of proc table := first of command;
rl. w2 b4. ;
rs w3 x2+h8 ; current command := first of command;
a2: ; program file name found:
al. w1 b3. ;
al. w3 d5. ;
jd 1<11+42; lookup entry (file name);
se w0 0 ; if not ok then
jl. a21. ; init error (object file not ok);
sh w0 (x1) ; if size < 0 then
jl. a4. ; begin
dl. w1 b3.+4 ; move docname( entry ) to filename
ds w1 x3+2 ;
dl. w1 b3.+8 ;
ds w1 x3+6 ;
al. w1 b3. ;
jd 1<11+42 ; lookup entry (file name)
se w0 0 ; if not ok then
jl. a21. ; init error (object file not ok);
a4: ; end;
jd 1<11+52; create area process (file name);
se w0 0 ; if not ok then
jl. a22. ; init error (area process not created);
al. w3 d4. ;
jd 1<11+52; create area process(library file);
se w0 0 ; if not ok then
jl. a22. ; init error (area process not created);
; prepare initialization of primary input/output
rl. w1 b4. ;
al. w0 d20. ;
rs w0 x1+h20+h2+2; primary input.giveup action := 'dummy name';
rs w0 x1+h21+h2+2; primary output.giveup action:= 'dummy name';
al w0 0 ;
al w2 1 ;
al w3 10 ;
; initialize primary input
hs w0 x1+h20+h4+0; primary input.eof := false;
hs w2 x1+h20+h4+1; primary input.eoln := true;
rs w3 x1+h20+h4+4; primary input.filebuf := newline char;
hs w2 x1+h20+h2+6; primary input.zonestate := after read char;
hs w2 x1+h20+h2+7; primary input.kind := textfile;
; initialize primary output
hs w2 x1+h21+h4+0; primary output.eof := true;
hs w2 x1+h21+h2+7; primary output.kind := textfile;
al w2 3 ;
hs w2 x1+h21+h2+6; primary output.zonestate := after write char;
; step 2: get inf segment
al. w3 b5. ;
al w0 x3+510 ;
ds. w0 d21.+4 ; save (first,last) in message;
rl. w2 b3.+0 ; w2 := entry size;
al w0 x2-1 ; w0 := segment number := size - 1;
jl. w2 f0. ; transfer from program file;
jl. a23. ;+2: io-error
; step 3: initialize pointers
rl. w3 d14. ; w3 := top := top of procedure table;
ws. w3 b8. ; top := top - size of library table;
rs. w3 d13. ; first of library table := top;
al w1 p10 ; size of procedure table :=
wm. w1 b5.+2 ; entry size * number of procedures;
ws w3 2 ; top := top - size of procedure table;
rs. w3 d12. ; first of procedure table := top;
rs. w3 d11. ; first of resident := top;
rs. w3 d10. ; last used of heap := top;
rs. w3 d9. ; last killed by heap := top;
rs. w3 d8. ; first of last loaded := top;
rs. w3 d6. ; first of proc nearest to stack := top;
; step 4: read procedure table into core
al w3 b0 ; w3 := size of entry in inf segment
wm. w3 b5.+2 ; * number of procedures
al w3 x3+511 ;
ls w3 -9 ;
ls w3 9 ; rounded up to size of used segments;
al. w3 x3+b6. ; w3 := last of transfer;
al w3 x3-2 ;
sl. w3 (d12.) ; if last of transfer >= first of procedure table then
jl. a24. ; init error(process too small);
al. w2 b6. ; w2 := first of transfer;
ds. w3 d21.+4 ;
rl. w0 b5.+4 ; w0 := segment number of procedure table;
jl. w2 f0. ; transfer from program file;
jl. a23. ;+2: ioerror
; step 5: initialize procedure table
al. w2 b6. ; w2 := first of procedure table buffer;
rl. w3 d12. ; w3 := first of procedure table;
rs. w3 d43.
dl w1 110
ds. w1 d47.
a10: ; next:
rl w0 x2+0 ; move segment number;
rs w0 x3+p0 ;
ac w0 (x2+2) ; move negative size of procedure;
rs w0 x3+p2 ;
rl w0 x2+4 ; move number of halfwords on stack;
rs w0 x3+p4 ;
al w0 0
rs w0 x3+p12-2 ; accumulated time := 0
rs w0 x3+p12
rs w0 x3+p14 ; number of calls := 0
rs w3 x3+p6 ; first addr := 'greater than runtime syst'
rl. w1 b5.+6 ; move (abs) virtual address of first line error entry;
ls w1 9 ;
wa w1 x2+6 ;
wa w1 x2+6 ; (it was a word number)
rs w1 x3+p8 ;
al w2 x2+b0 ; increase pointers;
al w3 x3+p10 ;
se. w3 (d13.) ; if not all procedures initialized then
jl. a10. ; goto next;
; step 6: initialize library procedure table
al. w2 b7. ; w2 := first of library procedure sizes;
al w0 0 ; w0 := current segment := 0;
a15: ; next:
rs w0 x3+p0 ; segm := current segment;
ac w1 (x2+0) ; move negative size of procedure;
rs w1 x3+p2 ;
as w1 -9 ; current segment := current segment
ws w0 2 ; + segments used by this procedure;
al. w1 r1. ; initialize addr of runtime error;
rs w1 x3+p4 ;
al w1 0 ; first addr := 0;
rs w1 x3+p6 ;
al w2 x2+2 ; increase pointers;
al w3 x3+p10 ;
se. w3 (d14.) ; if not all library procedures initialized then
jl. a15. ; goto next;
rl. w3 d13. ; first proc := first of library proc table;
jl. w2 f20. ; set maxsize;
; step 7: get resident procedures to core
al. w3 b6. ; safety limit := top of init code;
rs. w3 d1. ; first of stack := safety limit;
rs. w3 d2. ; stacktop := safety limit;
jl. w3 f21. ; test room;
al. w2 b5.+8 ; w2 := first of resident list;
a18: ; next resident:
al w1 p10 ; proc entry := proc table entry size
wm w1 x2 ; * procedure number (entry);
sh w1 -1 ; if procedure number >= 0 then
jl. a25. ; begin
al w3 x1 ; w3 := abs proc table entry;
wa. w3 d12. ;
ac w0 (x3+p2) ; w0 := positive size of procedure;
ds. w0 b10. ; save (proc table entry, proc size);
; check room for resident procedure, by means of calls of: 'new' and 'dispose'
al. w1 b11. ; w1 := address of working cell;
jl. w3 r8. ; allocate on heap;
rl. w0 b10. ; w0 := size of procedure;
al. w1 b11. ; w1 := working cell;
jl. w3 r9. ; release heap;
; there was room enough, therefore load it
rl. w3 b9. ; w3 := proc entry;
rl. w1 d10. ;
rs. w1 d8. ; first of last loaded := last used of heap;
jl. w1 f5. ; get procedure;
rl w1 x3+p6 ;
rs. w1 d11. ; first of resident := first(proc);
rs. w1 d10. ; last used of heap := first(proc);
rs. w1 d9. ; last killed by heap reserve := first(proc);
al w2 x2+2 ; increase(entry);
jl. a18. ; goto next resident;
a25: ; end;
; step 8: compute max size of nonresident procedures
rl. w3 d12. ; first proc := first of procedure table;
jl. w2 f20. ; set maxsize;
; step 9: pre-reserve the heap (but don't check yet)
rl. w1 d10. ; limit := last used of heap
ws. w1 b5. ; - std heap size;
rs. w1 d9. ; last killed by heap := limit;
rs. w1 d8. ; first of last loaded procedure := limit;
rs. w1 d6. ; first of proc nearest to stack := limit;
; step 11: set correct first of stack, and check heapsize
al. w1 r15. ;
am. (b4.) ; get fp-mode bits
rl w3 h51
sz w3 1<8 ; if mode listing
al. w1 r151. ; then top of rs := r151
rs. w1 d1. ; first of stack := top of runtime system;
jl. w3 f21. ; test room;
; step 12: initialize stackref and entry-addresses to runtime system
am. (b4.) ; get mode bits
rl w3 h51
al w2 x1+2047 ; w2 := stackref;
al w2 x2+1 ;
sz w3 1<8
am r41-r4 ; alternative call procedure
al. w0 r4. ; init: call pascal procedure
rs w0 x2-2047 ;
sz w3 1<8
am r61-r6 ; alternative return from procedure
al. w0 r6. ; return from pascal procedure
rs w0 x2-2045 ;
al. w0 r3. ; call library procedure
rs w0 x2-2035 ;
al. w0 r1. ; runtime error
rs w0 x2-2033 ;
al. w0 r7. ; value initialization
rs w0 x2-2031 ;
al. w0 r8. ; new
rs w0 x2-2029 ;
al. w0 r9. ; dispose
rs w0 x2-2027 ;
al w0 -15 ; (old versions: start of proctable)
rs w0 x2-2025 ;
al w0 -2 ; (old versions: get procedure)
rs w0 x2-2023 ;
; step 13: prepare call of set interrupt, and start main program
al w0 0 ; interrupt mask := 0;
al. w3 c0. ; interrupt address := break-routine;
; w0 = interrupt mask
; w1 = stacktop
; w2 = stackref
; w3 = interrupt address
jl. c0. ; goto init-code;
; set maxsize
;
; call: w2 = return
; w3 = first proc
b. a10 w.
f20: ;
al w0 0 ; w0 := maxsize := 0; <*notice: negative values *>
a0: ; rep:
sn. w3 (d14.) ; if entry = top of procedure table then
jl. a1. ; goto set max;
sl w0 (x3+p2) ; if maxsize >= size of procedure then
rl w0 x3+p2 ; maxsize := negative size of procedure;
al w3 x3+p10 ; increase(entry);
jl. a0. ; goto rep;
a1: ; set max:
; w0 = largest (negative) procedure size
ls w0 -9 ;
ls w0 9 ;
ac w0 (0) ; max := - maxsize rounded up;
rs. w0 d15. ; maximum page size above 'd10' := max;
ls w0 1 ;
wa. w0 d3. ; minimum room between stack and heap :=
rs. w0 d7. ; 2 * max + min room between stack and code;
jl x2 ; return;
e. ;
; test room
;
; call: w3 = return
f21: ;
rl. w0 d10. ; room := last used of heap
ws. w0 d7. ; - room between stack and heap
ws. w0 d1. ; - first of stack;
sh w0 -1 ; if room < 0 then
jl. a24. ; init error (process too small);
jl x3 ; return;
\f
; errorreturn :
b. c10, e2 w.
e1: 0 ;
0 ;
c0: <:<10><10> *** pascal init trouble <10> w0=:>;
c1: <: error in program call<0> :>;
c2: <: cannot create area process<0> :>;
c3: <: wrong answer<0> :>;
c4: <: process too small<0> :>;
c5: <: cannot transfer procedure table<0> :>;
a20: am c1.-c2.; error in program call
a22: am c2.-c3.; cannot create area process
a23: ; ioerror:
a21: am c3.-c4.; object file not ok
a24: am c4.-c5.; program too big
a5: al. w1 c5. ; transfer proc table
ds. w1 e1.+2 ;
rl. w2 b4. ;
al. w0 c0. ;
jl w3 x2+h31-2 ; outtext(init trouble)
rl. w0 e1. ;
jl w3 x2+h32-2 ; outinteger(w0)
1<23 + 32<12 + 3 ;
rl. w0 e1.+2 ;
jl w3 x2+h31-2 ; outtext(cause)
rl. w1 b4. ;
al w2 10 ;
jl w3 x1+h26-2 ; outchar(nl)
al w2 1 ; terminate program(not ok)
rl. w1 b4. ;
jl x1+h7 ; goto fp-end program
e.
\f
; dump procedure
; call :
; w1 - lower bound
; w2 - upper bound
; w3 - return
b. a3 w.
a1: 0,r.4
f22: ds. w1 a1.+2
ds. w3 a1.+6
a3: rl. w2 b4.
rl. w0 a1.+2 ;
jl w3 x2+h32-2 ; outinteger(addr);
32<12 + 6 ;
rl. w1 b4. ;
al w2 58 ;
jl w3 x1+h26-2 ; outchar(colon);
rl. w2 b4. ;
rl. w0 (a1.+2)
jl w3 x2+h32-2
1<23+32<12+9
al w2 10
rl. w1 b4.
jl w3 x1+h26-2
rl. w1 a1.+2
al w1 x1+2
rs. w1 a1.+2
sh. w1 (a1.+4)
jl. a3.
dl. w1 a1.+2
dl. w3 a1.+6
jl x3
e.
b6: ; top of init code:
e. ; end initialization block;
e. ; end segment
g2=k-h55
; the runtime system is generated by a job like
; the following :
; job bbj 3 1 time 30 size 25000 perm disc1 40 1
; clear user pascrun
; pascrun=set 40 disc1
; (pascrun=slang tpascrun entry.no proc.fpnames proc.insertproc
; pascrun)
; scope user pascrun
; finis
;
; the job looks like this because the catalog entry
; is set by insertproc, which requires the name of the
; entry to appear right after the translation. the
; parenthesis is present to ensure that the name is
; read at the same time as the call of the slang-
; assembler.
g0:
g1: (:g2+511:)>9 ; segments
0,r.4 ; document
s2 ; short clock
0 ; file
0 ; block
2<12+g3-h55 ; contents key <12 + entry point
g2 ; load length
d.
p.<:insertproc:>
«eof»