|
DataMuseum.dkPresents historical artifacts from the history of: RC4000/8000/9000 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about RC4000/8000/9000 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 10752 (0x2a00) Types: TextFile Names: »ttimer«
└─⟦2c55ea56f⟧ Bits:30001844 SW-save af projekt 1000, Alarm-system └─⟦6b41451d2⟧ └─⟦this⟧ »ttimer«
job pm 2 600 time 11 0 perm mini 100 1 size 110000 platonenv = set bs bblenv ( ; o timerout head 1 cpu pascal80 codesize.12000 spacing.12000 , stack.200, codelist.no, ioenvir ; o c ; convert timerout btimer = set 1 mini btimer = move pass6code if ok.yes scope project btimer finis ) process timer (var timersem, dummysem: semaphore); label put_in_queue, insert, endloop, get_time, hangup, insert2; (* definitions for global time *) type daytype = array (1..12) of byte; const maxdays = daytype (31,28,31,30,31,30,30,31,30,31,30,31); var global_date : coded_date := coded_date (81, 6, 1); global_time : coded_time := coded_time (?, 11, 40); global_msec : integer := 0; (* unit is milli seconds *) one_minute : integer; (* definitions for timer interrupts *) const level = 2; clock_level_index = 0; timer_index1 = 4; timer_index2 = 3; timeperiod = 50; (* milli seconds, must be a multiple of 5 msec *) ticks_per_sec = 1000 div timeperiod; ticks_per_slice = 200 div timeperiod; monreg = 992; type activetype = array (minpriority..maxpriority) of addr; const delaysize = 5; (* words *) type mess_hdr = record chain : ^ mess_hdr; ? : integer; size : integer; start : ^ delaytype; ?,?,?,?: addr; ?,? : byte; u3u4 : integer; end; var msg, dev: reference; iotimerptr: ^ semaphore; timerhead : ^ mess_hdr; msgptr : ^ mess_hdr; prevmsg : ^ mess_hdr; curmsg : ^ mess_hdr; nill : ! ^ niltype; a : addr; longdelay : ^ mess_hdr; prevdelay : ^ mess_hdr; curdelay : ^ mess_hdr; delay : integer; power : integer; i : integer; dummy : integer; mask : integer; io_tick : integer; slice_tick: integer; pri : integer; priobits : integer; activequeue: ^ activetype; (* variables for iotimer *) delayhead : addr; (* points to first process in timer-chain, or nil *) proc, newproc: ^ ext_incarnation_descriptor; insertion, searching : boolean; procedure clearlevel; external; procedure writeram (value, index: integer); external; procedure setregister (value, index: integer); external; procedure requeue (var q: addr); external; procedure startschedule; external; procedure timestep (p: addr); external; function maxday (year, month: integer): integer; begin maxday := maxdays(month) + ord(((year mod 4)=0) and (month=2)); end; begin own.secret_pointer^(timerstack)^.chain := addr_of (own.chain); activequeue := ptraddr (own.secret_pointer^(activebase)^.chain); iotimerptr := own.secret_pointer^(iotimersem); delayhead.base.nill := 1; dummy := reservech (dev, level, 0); writeram (clock_level_index, level); io_tick := timeperiod div 5 * 2; (* interrupt unit is 2.5 msec *) writeram (timer_index1, io_tick div 256); writeram (timer_index2, io_tick mod 256); one_minute := umul (60, 1000); slice_tick := 0; pri := -1; priobits := 0; repeat io_tick := 0; channel dev do repeat clearlevel; (* wait interrupt *) (* get timer messages *) while open (timersem) do begin wait (msg, timersem); delay := msg^.u3; power := msg^.u4; asgnaddrref (a, msg); msgptr := ptraddr (a); asgnrefaddr (msg, addrptr (nill)); if delay <> 0 then begin (* delay is: delay * 2**power *) while power <> 0 do begin delay := uadd (delay, delay); if delay < 0 then power := 0 else power := power - 1; end; put_in_queue: prevmsg := nill; curmsg := timerhead; while not nil (curmsg) do begin if ult (delay, curmsg^.u3u4) then begin with curmsg^ do u3u4 := usub(u3u4,delay); goto insert end; delay := usub (delay, curmsg^.u3u4); prevmsg := curmsg; curmsg := curmsg^.chain; end; insert:; msgptr^.u3u4 := delay; msgptr^.chain:= curmsg; if nil(prevmsg) then timerhead := msgptr else prevmsg^.chain := msgptr; end (* simple delay *) else if ult(msgptr^.size, delaysize) or nil(msgptr^.start) then begin delay := 0; goto put_in_queue; end else with msgptr^.start^ do begin (* databuffer has delay_format *) if power = 0 then begin (* absolute delay *) (* add increment to previous time *) i := prev_secs.msec + inc.msecs; prev_secs.msec := i mod 1000; i := prev_secs.sec + inc.secs + i div 1000; prev_secs.sec := i mod 60; i := prev_time.minute+inc.mins + i div 60; prev_time.minute:= i mod 60; i := prev_time.hour + inc.hours + i div 60; prev_time.hour := i mod 24; i := inc.days + i div 24; if i > 0 then begin i := prev_date.day + i; while i > maxday(prev_date.year_after_1900, prev_date.month) do begin i := i - maxday(prev_date.year_after_1900, prev_date.month); if prev_date.month < 11 then prev_date.month := succ (prev_date.month) else begin prev_date.month := 1; prev_date.year_after_1900 := (prev_date.year_after_1900 + 1) mod 128; end; end; (* while *) prev_date.day := i; end; (* insert in simple chain if prev(year..min) = global_time(year..min) *) if prev_date.year_after_1900 = global_date.year_after_1900 then begin if prev_date.month = global_date.month then begin if prev_date.day = global_date.day then begin if prev_time.hour = global_time.hour then begin if prev_time.minute = global_time.minute then begin (* insert in simple queue *) delay := uadd (umul(prev_secs.sec, 1000), prev_secs.msec); if ult (global_msec, delay) then begin delay := usub (delay, global_msec); goto put_in_queue; end; end else if prev_time.minute > global_time.minute then goto hangup; end else if prev_time.hour > global_time.hour then goto hangup; end else if prev_date.day > global_date.day then goto hangup; end else if prev_date.month > global_date.month then goto hangup; end else if prev_date.year_after_1900 > global_date.year_after_1900 then goto hangup; (* prev <= global_time, return message as soon as possible *) get_time: begin prev_date := global_date; prev_time := global_time; prev_secs.sec := udiv (global_msec, 1000); prev_secs.msec := umod (global_msec, 1000); end; delay := 0; goto put_in_queue; (* prev > global_time(year..min), insert in delaylist *) hangup: msgptr^.chain := longdelay; longdelay := msgptr; end (* power = 0 *) else begin if power = 1 then begin global_date := prev_date; global_time := prev_time; global_msec := uadd (umul (prev_secs.sec, 1000), prev_secs.msec); end; goto get_time; end; end; end; (* while open (timersem) *) (* define-timer messages *) while open (iotimerptr^) do begin wait (msg, iotimerptr^); insertion := msg^.u2 = ord(true); proc := ptraddr (delayhead); (* proc points at first process *) if delayhead = msg^.start then begin (* process was in front of chain *) if not insertion then delayhead := proc^.delaychain; end else begin (* process was not in front of chain, try to find it *) searching := true; while not nil(proc) and searching do begin newproc := ptraddr(proc^.delaychain); if proc^.delaychain = msg^.start then begin (* process was found in chain *) if not insertion then proc^.delaychain := newproc^.delaychain; searching := false; end else proc := newproc; end; if searching and insertion then begin (* insert, if not found already *) proc := ptraddr (msg^.start); proc^.delaychain := delayhead; delayhead := msg^.start; end; end; return (msg); end; (* while open (iotimerptr) *) (* time slicing *) slice_tick := slice_tick + 1; if slice_tick >= ticks_per_slice then begin slice_tick := 0; requeue (activequeue^(pri)); pri := -1; mask := 1; (* find rightmost zero-bit *) while (priobits and mask) <> 0 do begin pri := pri - 1; mask := uadd (mask, mask); end; if pri = minpriority then priobits := 0 else priobits := uadd (priobits, 1); setregister (pri, monreg+4); startschedule; end; (* update global time *) begin global_msec := uadd (global_msec, timeperiod); if not ult (global_msec, one_minute) then begin global_msec := usub (global_msec, one_minute); with global_date, global_time do if minute < 59 then minute := succ (minute) else begin minute := 0; if hour < 23 then hour := succ (hour) else begin hour := 0; if day < maxday(year_after_1900, month) then day := succ (day) else begin day := 1; if month < 11 then month := succ (month) else begin month := 1; year_after_1900 := (year_after_1900 + 1) mod 128; end; end; end; end; (* minute has changed, scan delaylist and transfer to simple delay list *) prevdelay := nill; curdelay := longdelay; while not nil(curdelay) do with curdelay^.start^ do begin if (prev_date.year_after_1900 <= global_date.year_after_1900) and (prev_date.month <= global_date.month ) and (prev_date.day <= global_date.day ) and (prev_time.hour <= global_time.hour ) and (prev_time.minute <= global_time.minute ) then begin msgptr := curdelay; curdelay := curdelay^.chain; if nil(prevdelay) then longdelay := curdelay else prevdelay^.chain := curdelay; delay := uadd (umul (prev_secs.sec, 1000), prev_secs.msec); if ult (global_msec, delay) then delay := usub (delay, global_msec) else delay := 0; (* put in simple delay list *) prevmsg := nill; curmsg := timerhead; while not nil(curmsg) do begin if ult (delay, curmsg^.u3u4) then goto insert2; delay := usub (delay, curmsg^.u3u4); prevmsg := curmsg; curmsg := curmsg^.chain; end; insert2:; msgptr^.u3u4 := delay; msgptr^.chain:= curmsg; if nil(prevmsg) then timerhead := msgptr else prevmsg^.chain := msgptr; end else begin prevdelay := curdelay; curdelay := curdelay^.chain; end; end; end; end; (* return messages *) if nil(timerhead) then goto endloop; while not ult (timeperiod, timerhead^.u3u4) do begin delay := timerhead^.u3u4; timerhead^.u3u4 := 0; asgnrefaddr (msg, addrptr (timerhead)); timerhead := timerhead^.chain; return (msg); if nil(timerhead) then goto endloop; timerhead^.u3u4 := uadd (timerhead^.u3u4, delay); end; timerhead^.u3u4 := usub (timerhead^.u3u4, timeperiod); endloop:; io_tick := io_tick + 1; until io_tick = ticks_per_sec; (* handle iotimer counting at level 0 *) timestep (delayhead); until false; end (* timer *); . ▶EOF◀