"BEGIN INCLUDE FILE simone_operators_.incl.alm " HISTORY COMMENTS: " 1) change(86-09-11,JPFauche), approve(86-09-11,MCR7521), " audit(86-09-15,Martinson), install(86-11-12,MR12.0-1208): " Release 8.03 for MR12. " END HISTORY COMMENTS " " SIM-ONE OPERATORS - Designed and written : Alain Kermarrec, CICB - France " " " " " " " * * * * * * * * * * * * * * " * * " * SIMONE ENTRY OPERATORS * " * * " * * * * * * * * * * * * * * " " " " entry operators for MAIN SIMONE " -------------------------------------------------- " " assumed that: (Multics convention) " PR0 -> parameter list " PR6 -> stack frame of the calling procedure " PR7 -> stack header " " calling sequence: " epp5 0,ic entry point addr " epp2 7|stack_header.trans_op_tv_ptr MUST BE SECOND WORD (for TRACE) " epp2 2|8,* to get ptr to pascal operators " ldq [PASCAL execution flags],dl " eax7 [stack_frame size in words (n * 16)] " eax4 [max size than can be reached by the stak of this processus] " eax3 [addr of return point when EXIT] " tsp3 2|{op number} " " Performs the standard push sequence. " " returns: " PR0 -> pascal operators transfer vector " PR4 -> link section of the procedure " PR6 -> stack_frame of the procedure " (indicators are reset) SIMONE_MAIN_entry: " PUSH stack inhibit on epp1 7|stack_header.stack_end_ptr,* spri6 1|stack_frame.prev_sp spri1 6|stack_frame.next_sp epp6 1|0 epp1 6|0,x4 get full space for this process spri1 6|stack_frame.next_sp spri1 7|stack_header.stack_end_ptr inhibit off " FILL stack spri0 6|stack_frame.arg_ptr "arg_ptr" in new stack frame epp0 2|0 op ptr must be pr0 spri5 6|stack_frame.entry_ptr "entry_ptr" of new stack frame spri0 6|stack_frame.operator_ptr "operator_ptr" in new stack frame adq my_id,du stq 6|stack_frame.translator_id epp2 6|0,7 ptr to next stack_frame of this processus spri2 6|next_simone_frame_ptr epp1 2|-sim_locs_size spri1 6|locals_ptr " initialize now locals " - - - - - - - - - - - - - stx4 1|max_size stx7 6|left_size sbx4 6|left_size stx4 6|left_size spri6 1|main_base_ptr spri6 6|base_process_ptr epbp2 3|0 PR2 --> Executed segment epp2 2|0,x3 PR2 --> EXIT point spri2 1|exit_ptr Store PR2 epp2 null_ptr,* spri2 6|next_free_block_ptr Free list spri2 1|first_active_process_ptr spri2 1|next_threaded_process_ptr spri2 1|previous_threaded_process_ptr spri2 1|bill_book_ptr spri2 6|dlinkw spri2 6|execution_mo_ptr stz 1|hour stz 1|father_type stz 1|number_of_active_sons stz 1|waiting_var_sons aos 1|number_of_active_sons epaq 3|0 lprp4 7|stack_header.lot_ptr,*au spri4 6|linkage_ptr "linkage_ptr" in new stack frame epbp1 3|0 spri1 6|stack_frame.return_ptr ldi 0,dl reset indicators tra 3|2 return to procedure " " " " " entry operator for exportable pure SIMONE procedure " ----------------------------------------------------- " " assumed that: (Multics convention) " PR0 -> parameter list " PR6 -> stack frame of the calling procedure " PR7 -> stack header " " calling sequence: " epp5 0,ic entry point addr " epp2 7|stack_header.trans_op_tv_ptr MUST BE SECOND WORD (for TRACE) " epp2 2|8,* to get ptr to pascal operators " ldq [PASCAL execution flags],dl " eax7 [stack_frame size in words (n * 16)] " eax4 [max size than can be reached by the stak of this processus] " tsp3 2|{op number} " " Performs the standard push sequence. " Sets locals to blank if check mode " " returns: " PR0 -> pascal operators transfer vector " PR4 -> link section of the procedure " PR6 -> stack_frame of the procedure " (indicators are reset) " " sim_ext_entry: " PUSH stack inhibit on epp1 7|stack_header.stack_end_ptr,* spri6 1|stack_frame.prev_sp spri1 6|stack_frame.next_sp epp6 1|0 epp1 6|0,x7 get space for this proc spri1 6|stack_frame.next_sp spri1 7|stack_header.stack_end_ptr inhibit off " FILL stack spri0 6|stack_frame.arg_ptr "arg_ptr" in new stack frame epp0 2|0 spri0 6|stack_frame.operator_ptr spri5 6|stack_frame.entry_ptr "entry_ptr" of new stack frame adq my_id,du stq 6|stack_frame.translator_id anq check_bit,dl tze sim_ext_skip_init eaa -sim_first_local_place,x7 als 2 mlr (pr),(pr,rl),fill(040) desc9a 6|sim_first_local_place,0 desc9a 6|sim_first_local_place,au sim_ext_skip_init: epaq 3|0 lprp4 7|stack_header.lot_ptr,*au spri4 6|linkage_ptr "linkage_ptr" in new stack frame epp1 null_ptr,* spri1 6|dlinkw spri1 6|base_process_ptr epbp1 3|0 spri1 6|stack_frame.return_ptr ldi 0,dl reset indicators tra 3|2 return to procedure " " " " " entry operator for Simone pure internal procedures " -------------------------------------------------- " " assumed that: (PASCAL internal convention) " PR0 -> pascal operators " PR1 -> dynamic link " PR2 -> argument list " PR4 -> linkage section " PR6 -> stack frame of the calling procedure " PR7 -> stack header " " calling sequence: " epp5 0,ic get ptr to the entry point " eax7 [stack_frame size in words (n * 16)] " tsp3 0|91 " " returns: " PR0 , PR6 not changed " PR6 -> stack frame of the procedure " pure_int_entry: " PUSH stack inhibit on eaa 7|stack_header.stack_end_ptr,* [A] <- stack_end spri6 7|stack_frame.prev_sp,au spri1 7|dlinkw,au spri2 7|stack_frame.arg_ptr,au epp1 6|0 PR1 -> caller stack epp6 7|0,au PR6 -> current new stack epp2 6|0,x7 PR2 -> next stack (stack_end) spri6 1|stack_frame.next_sp spri2 6|stack_frame.next_sp spri2 7|stack_header.stack_end_ptr inhibit off " FILL stack spri4 6|linkage_ptr spri0 6|stack_frame.operator_ptr spri5 6|stack_frame.entry_ptr epp5 1|base_process_ptr,* spri5 6|base_process_ptr ldq 1|stack_frame.translator_id anq non_MAIN_mask stq 6|stack_frame.translator_id anq check_bit,dl tze skip_p_inter_init eaa -sim_first_local_place,x7 als 2 mlr (pr),(pr,rl),fill(040) desc9a pr6|sim_first_local_place,0 desc9a pr6|sim_first_local_place,au skip_p_inter_init: ldi 0,dl epbp1 3|0 spri1 6|stack_frame.return_ptr tra 3|2 " " " " " entry operator for Simone non pure internal procedures " ------------------------------------------------------ " " assumed that: (PASCAL internal convention) " PR0 -> pascal operators " PR1 -> dynamic link " PR2 -> argument list " PR4 -> linkage section " PR6 -> stack frame of the calling procedure " PR7 -> stack header " x2 = " " calling sequence: " epp5 0,ic get ptr to the entry point " eax7 [stack_frame size in words (n * 16)] " tsp3 0|91 " " returns: " PR0 , PR6 not changed " PR6 -> stack frame of the procedure " sim_int_entry: " Check if enough room in process stack stx7 6|op_work ldx4 6|left_size sbx4 6|op_work tmi check_overflow " PUSH stack inhibit on eaa 6|next_simone_frame_ptr,* spri6 7|stack_frame.prev_sp,au spri1 7|dlinkw,au spri2 7|stack_frame.arg_ptr,au epp1 6|0 PR1 -> caller stack epp6 7|0,au PR6 -> current new stack epp2 1|stack_frame.next_sp,* PR2 -> next stack_frame spri6 1|stack_frame.next_sp spri2 6|stack_frame.next_sp epp2 6|0,x7 spri2 6|next_simone_frame_ptr inhibit off " FILL stack spri4 6|linkage_ptr spri5 7|stack_frame.entry_ptr,au " adx6 -1,du test x6 " tmi no_propagation " epp4 6|stack_frame.prev_sp,* " epp4 4|base_process_ptr,* PR4 -> PROCESS STACK " epp4 4|execution_mo_ptr,* PR4 -> MONITOR WHERE CALL IS MADE " spri4 6|monormod_ptr " epp4 6|linkage_ptr,* Restore PR4 " no_propagation: adx2 -1,du tmi ordinary_proc ldq 6|stack_frame.arg_ptr,* qrl 1 mpy 2,dl eaa 1|next_simone_frame_ptr,* epp5 6|stack_frame.arg_ptr,*qu epp5 5|0,* spri5 6|monormod_ptr epp2 1|base_process_ptr,* spri5 2|execution_mo_ptr ordinary_proc: ldq 1|stack_frame.translator_id anq non_MAIN_mask stq 6|stack_frame.translator_id anq check_bit,dl tze skip_inter_init eaa -sim_first_local_place,x7 als 2 mlr (pr),(pr,rl),fill(040) desc9a 6|sim_first_local_place,0 desc9a 6|sim_first_local_place,au skip_inter_init: epp2 1|base_process_ptr,* spri2 6|base_process_ptr epbp1 3|0 spri1 6|stack_frame.return_ptr stx4 6|left_size ldi 0,dl tra 3|2 check_overflow: epp1 |[recursivity_error] tra common_op_call " " " " Entry operator for a process " ---------------------------- " " " This Operator : " -Installs the stack of the process to be started " - Put the process including the calling procedure " in the active_process_queue by calling the " appropriate operator. " " assumed that: (PASCAL internal convention) " PR0 -> pascal operators " PR1 -> dynamic link " PR2 -> argument list " PR4 -> linkage section " PR6 -> stack frame of the calling procedure " PR7 -> stack header " " calling sequence: " epp5 0,ic get ptr to the entry point " eax7 [stack_frame size in words (n * 16)] " eax4 [max size the process can reach] " eax3 [addr of EXIT point] " eax6 [type of the father (proc : 0 or monormod :1)] " tsp3 0| " " " process_entry: " " first save registers " eax1 save_ptr_regs eax2 save_regs spri 6|base_process_ptr,*x1 sreg 6|base_process_ptr,*x2 " epp1 6|base_process_ptr,* PR1 <- STARTER epp2 1|locals_ptr,* PR2 <- locals of STARTER epp5 2|main_base_ptr,* PR5 <- Main " " Look for a free block to install process frame " continue_to_search: epp2 5|0 PR2 <- [PR5] ldaq null_ptr ) eraq 5|next_free_block_ptr ) Test if next free block exists ana ring_number_mask ) tze set_on_stack_end epp5 5|next_free_block_ptr,* PR5 <- next free block cmpx4 5|free_block_size compare new process and free block sizes tnz continue_to_search This block is not suitable eaa 5|0 A <- addr of new process frame epp5 5|next_free_block_ptr,* PR5 <- next free block (becomming [PR2]'s next free block) spri5 2|next_free_block_ptr Update free list epp5 7|stack_header.stack_end_ptr,* stack end does not change tra install_stack Not to modify A register set_on_stack_end: epp5 7|stack_header.stack_end_ptr,*x4 new stack end eaa 7|stack_header.stack_end_ptr,* A <- addr of new process frame install_stack: stz 6|work_for_sim sxl6 6|work_for_sim Store process father type ldq 6|work_for_sim Q <- Store process father type anq check_mo_father_type_bit Check father type tze load_dlk_type epp2 1|save_ptr_regs+2,* PR6 -> Dyn_link new_link_again: ldq 2|mo_father_type anq check_mo_father_type_bit Check father type epp2 2|mo_dynlk,* New dyn_link tze install_stack_now tra new_link_again load_dlk_type: epp2 1|save_ptr_regs+2,* install_stack_now: " " " At this point: " " PR5 -> (new) stack end " PR2 -> Father (dlink) " A = offset of new process stack frame " " " PUSH stack inhibit on spri5 7|stack_header.stack_end_ptr spri5 7|stack_frame.next_sp,au spri2 7|stack_frame.prev_sp,au " epp2 4|0 epp6 7|0,au spri6 2|stack_frame.next_sp inhibit off " FILL stack " " At this point: " " PR0 -> pascal_operators " PR1 -> starter process frame (where registers are saved) " PR2 -> stack frame of father (or dlink) " PR3 -> return point in code of current starting process " PR4 -> linkage section " PR6 -> current new stack frame " PR7 -> stack base " epp5 1|save_ptr_regs+10,* restor PR5 (entry point) spri5 6|stack_frame.entry_ptr epbp5 3|0 spri5 6|stack_frame.return_ptr spri0 6|stack_frame.operator_ptr spri4 6|linkage_ptr epp5 1|save_ptr_regs+4,* restor PR2 (arg ptr) spri5 6|stack_frame.arg_ptr epp2 1|save_ptr_regs+2,* dlink or father spri2 6|dlinkw " epp2 1|0 epp1 6|-sim_locs_size,x7 " " At this point: " " PR1 -> sim locals for this new proc " PR2 -> starter process frame " " " spri1 6|locals_ptr " " Update set frame list " ldq 2|stack_frame.translator_id ) anq non_MAIN_mask ) Update sf translator_id stq 6|stack_frame.translator_id ) anq check_bit,dl ) tze skip_internal_init ) eaa -sim_first_local_place-sim_locs_size,x7 ) als 2 ) Fill variable with blanck char mlr (pr),(pr,rl),fill(040) ) desc9a pr6|sim_first_local_place,0 ) desc9a pr6|sim_first_local_place,au ) skip_internal_init: epp5 2|locals_ptr,* epp5 5|main_base_ptr,* spri5 1|main_base_ptr epp5 6|0,x7 PR5 <- next simone frame spri5 6|next_simone_frame_ptr spri6 6|base_process_ptr [[PR6] -> base_process] <- [PR6] stz 1|waiting_var_sons stz 1|father_type ) sxl6 1|father_type ) store type of the father stx4 1|max_size stx7 6|left_size sbx4 6|left_size stx4 6|left_size stz 1|priority stz 1|activation_time stz 1|number_of_active_sons aos 1|number_of_active_sons Process is its own son epbp5 3|0 PR5 --> Executed module epp5 5|0,x3 PR5 --> Exit point spri5 1|exit_ptr Store PR5 epp5 null_ptr,* spri5 1|next_threaded_process_ptr spri5 1|previous_threaded_process_ptr spri5 6|execution_mo_ptr epp5 6|father_ptr,* PR5 --> father ldq 1|father_type check father type --> Q anq check_mo_father_type_bit compare with father of this process tze proc_father transfer for proc father monormod_father: aos 5|mo_active_sons active_sons +:= 1 tra end_update_active_sons proc_father: epp5 5|locals_ptr,* PR5 __> locals aos 5|number_of_active_sons active_sons +:= 1 end_update_active_sons: " " Put caller process in queue " epp5 2|0 PR5 --> process to queue epp1 6|0 PR1 -> process to be started tsp2 active_process_queuing active_process_queueing " ldi 0,dl tra 3|2 ..finally, return to starting process " " " " *************************** " * * " * SAVE_ARG_LIST OPERATOR * " * * " *************************** " " " This Operator updates pointers on the parameters " which have just been copied in the new stack. " " " Calling sequence : " " ldq [number of parameters for this process] " tsp3 0|operator's number " " save_arg_list: tze save_arg_end If no parameters epp2 6|stack_frame.arg_ptr,* PR2 --> arg list eaa 2|2 sta 6|decal eaa 6|sim_first_local_place ssa 6|decal lda 6|decal epp2 6|sim_first_local_place update_pointer: asa 2|1 sbq 1,dl tze save_arg_end epp2 2|2 tra update_pointer save_arg_end: tra 3|0 " " " " *************************************************** " * * " * OPERATORS DEALING WITH QUEUES * " * * " *************************************************** " " " " " Operator setting a process in the active process queue " ------------------------------------------------------ " " " The process to be put in this queue is inserted at the " head of the queue. " " " ASSUME THAT : " PR1 --> FRAME of the process to be started " PR5 --> FRAME of the process to be queued " PR6 --> FRAME of the calling procedure " " MUST NOT MODIFIE PR1 PR2 PR3 PR6 " " PR0 PR4, PR7 ARE USED BUT RESTORED " " " Calling sequence : " tsp2 0|-5 " " active_process_queuing: epp7 5|locals_ptr,* epp7 7|main_base_ptr,* PR7 --> main ldaq null_ptr epp4 7|locals_ptr,* eraq 4|first_active_process_ptr Checking emptyness of the queue ana ring_number_mask tze first_in_queue " " There is already at least one process in the queue " -------------------------------------------------- " epp0 4|first_active_process_ptr,* epp7 0|locals_ptr,* spri5 7|previous_threaded_process_ptr spri5 4|first_active_process_ptr epp7 5|locals_ptr,* spri0 7|next_threaded_process_ptr epp0 null_ptr,* spri0 7|previous_threaded_process_ptr epp7 4|main_base_ptr,* tra restor_ptr " " The queue was empty " ------------------- " first_in_queue: epp4 7|locals_ptr,* spri5 4|first_active_process_ptr epp4 5|locals_ptr,* ldaq null_ptr staq 4|previous_threaded_process_ptr staq 4|next_threaded_process_ptr " " restor now PR0, PR4, PR7 " ------------------------ " restor_ptr: epp0 7|stack_frame.operator_ptr,* epbp7 7|0 epp4 6|linkage_ptr,* tra 2|0 " " " Choose process operator " ----------------------- " " Asuume that PR6 --> Main_process " " " May modifie active_process_queue or bill_book_queue " " Calling sequence : " tra choose_process " " choose_process: epp5 6|locals_ptr,* ldaq null_ptr eraq 5|first_active_process_ptr ana ring_number_mask tnz take_in_active_queue " " Choose in bill_book_queue " ------------------------- ldaq null_ptr eraq 5|bill_book_ptr ana ring_number_mask tnz bill_book_ok epp7 6|base_process_ptr,* lpri 7|save_ptr_regs epbp7 6|0 epp1 7|stack_header.stack_end_ptr,* spri1 6|stack_frame.next_sp epp1 |[dead_lock_error] No process available tra common_op_call bill_book_ok: epp4 5|bill_book_ptr,* PR4 --> Choosen process frame epp2 4|locals_ptr,* PR2 --> Choosen process locals lda 2|activation_time sta 5|hour ldaq null_ptr eraq 2|next_threaded_process_ptr ana ring_number_mask tnz bill_book_not_empty ldaq null_ptr staq 5|bill_book_ptr tra skip_bill_book_update bill_book_not_empty: epp1 2|next_threaded_process_ptr,* epp7 1|locals_ptr,* ldaq null_ptr staq 7|previous_threaded_process_ptr spri1 5|bill_book_ptr skip_bill_book_update: staq 2|next_threaded_process_ptr epp6 4|0 tra activate_process take_in_active_queue: " " Choose in active_queue " ---------------------- " epp4 5|first_active_process_ptr,* PR4 --> Choosen process frame epp2 4|locals_ptr,* PR2 --> Choosen process locals ldaq null_ptr eraq 2|next_threaded_process_ptr ana ring_number_mask tnz active_queue_not_empty ldaq null_ptr staq 5|first_active_process_ptr tra skip_active_queue_update active_queue_not_empty: epp1 2|next_threaded_process_ptr,* epp7 1|locals_ptr,* ldaq null_ptr staq 7|previous_threaded_process_ptr spri1 5|first_active_process_ptr skip_active_queue_update: staq 2|next_threaded_process_ptr epp6 4|0 tra activate_process " " activate_process operator " ------------------------- " " Assume that : PR6 --> Base of the process to be activated " " " Restor : PR0, PR1, PR4, PR6, PR7 " " set PPR to the convenient address " " " Calling sequence : " tra activate_process " " activate_process: epp2 6|0 stack_links_loop: epp3 2|locals_ptr,* PR3 -> [PR2] locals ldq 3|father_type anq check_mo_father_type_bit tze no_skip epp2 2|dlinkw,* PR2 -> Dynamic link (MONITOR) skip_monitor: ldq 2|mo_father_type anq check_mo_father_type_bit epp2 2|mo_dynlk,* dynamic_link is a monitor tnz skip_monitor no_skip: ldaq null_ptr eraq 2|dlinkw ana ring_number_mask tze stack_links_ok epp3 2|dlinkw,* epp3 3|base_process_ptr,* epp1 3|save_ptr_regs+12,* spri2 1|stack_frame.next_sp spri1 2|stack_frame.prev_sp epp2 3|0 tra stack_links_loop stack_links_ok: epp2 6|locals_ptr,* PR2 <- [PR6] locals ldaq null_ptr staq 2|next_threaded_process_ptr store NIL in [PR6] NTP staq 2|previous_threaded_process_ptr store NIL in [PR6] PTP lreg 6|save_regs restor regs lpri 6|save_ptr_regs restor ptr_regs epbp3 6|0 epp3 3|stack_header.stack_end_ptr,* spri3 6|stack_frame.next_sp epp3 6|stack_frame.return_ptr,* PR3 <- return point tra 3|0 " " " *********************************** " * * " * WAITSONS * " * * " *********************************** " " " " These operators delay the end of process or monitor or " module until they have no more active sons. " " MO_WAITSONS " ----------- " " This operator deals with monitors and modules " " Calling sequence: " " epp2
" tsp3 0| " " mo_waitsons: ldq 2|mo_father_type anq check_mo_father_type_bit tze mo_return spri1 6|work_for_sim save PR1 epp1 2|mo_dynlk,* ldq 1|mo_active_sons sbq 1,dl stq 1|mo_active_sons epp1 6|work_for_sim,* mo_return: ldq 2|mo_active_sons Load Q reg with number of active sons tnz wait_later tra 3|0 wait_later: eax1 save_ptr_regs eax2 save_regs epp5 6|base_process_ptr,* epp5 5|locals_ptr,* PR5 -> process locals aos 5|waiting_var_sons Process waiting for its variables sons spri 6|base_process_ptr,*x1 registers must be saved sreg 6|base_process_ptr,*x2 tra wait " " " WAITSONS " -------- " " This operator deals with processes " " " Calling sequence ; " tsp3 0|[operator number] " waitsons: epp5 6|locals_ptr,* lda 5|number_of_active_sons sba 1,dl sta 5|number_of_active_sons tnz wait tra 3|0 " " must wait " --------- " wait: spri3 6|stack_frame.return_ptr lda -1,dl sta 5|priority epp6 5|main_base_ptr,* tra choose_process " return from simone internal procedures " -------------------------------------- " " MUST NOT MODIFY E,A,Q AND ZERO AND NEGATIVE INDICATORS " " calling sequence: " tra 0|92 " " Returns to the calling procedure (in the same segment) " PR0 , PR4 no to modify - PR6 to reset " sim_int_return: epbp7 6|0 PR7 -> stack header epp2 6|stack_frame.next_sp,* epp6 6|stack_frame.prev_sp,* rPR6 -> stack frame of calling spri2 6|stack_frame.next_sp rtcd 6|stack_frame.return_ptr return to calling proc " " " return from process (after the active sons have been waited) " ------------------------------------------------------------ " " Calling sequence : " tra 0|operator_number " " Return to the next process to be reactived " " process_return: epp5 6|locals_ptr,* PR5 <- locals of the process to be terminated epp1 6|father_ptr,* PR1 <- father process ldq 5|father_type anq check_mo_father_type_bit tze proc_waiting tra if father in a process ldq 1|mo_active_sons load Q with number of active sons sbq 1,dl substract one stq 1|mo_active_sons store new number of active sons tnz return_end father must not be waken link_to_find: ldq 1|mo_father_type anq check_mo_father_type_bit tze link_found first process bound epp1 1|mo_dynlk,* PR1 -> next monitor tra link_to_find link_found: epp5 1|mo_dynlk,* to wake father if necessary epp1 5|locals_ptr,* PR1 -> locals ldq 1|waiting_var_sons tze return_end Process is not waiting tsp2 active_process_queuing tranfer to active_process_queueing tra return_end proc_waiting: epp2 1|locals_ptr,* PR2 <- father's locals lda 2|number_of_active_sons ) sba 1,dl ) Update father's number of active sons sta 2|number_of_active_sons ) tnz return_end " " This was the last active son " ---------------------------- " epp5 6|father_ptr,* PR5 <- father (that must be activated to finish) tsp2 0|-5 Active process queueing " return_end: " " block becomes free " ------------------- " epp5 6|locals_ptr,* PR5 -> locals of current terminating process epp7 5|main_base_ptr,* PR7 <- Main epp2 7|next_free_block_ptr,* PR2 <- first free block spri2 6|next_free_block_ptr Insert liberated frame in free list spri6 7|next_free_block_ptr ldq 5|max_size stq 6|free_block_size epp6 7|0 epbp7 6|0 tra choose_process " " " *********************** " * * " * HOLD OPERATOR * " * * " *********************** " " " This operator sets in the bill_book queue the process to be hold. " " " Calling sequence : " ldx3 [time to wait] " tsp3 0|operator_number " " hold: " " first save registers " -------------------- " spri7 6|save_regs epp7 6|base_process_ptr,* spri3 6|stack_frame.return_ptr spri 7|save_ptr_regs epp5 6|base_process_ptr,* PR5 : Process to be queued epp7 6|save_regs,* spri7 5|save_ptr_regs+14 epp4 5|locals_ptr,* sreg 5|save_regs " " Now begin queuing " ----------------- " epp0 4|main_base_ptr,* PR0 : main epp0 0|locals_ptr,* PR0 : Main's locals adq 0|hour stq 4|activation_time " " cheking emptyness of the queue " ------------------------------ " ldaq null_ptr eraq 0|bill_book_ptr ana ring_number_mask tze bill_book_was_empty " " the queue wasn't empty " ---------------------- " epp1 0|bill_book_ptr,* PR1 : first in the queue epp2 1|locals_ptr,* ldq 4|activation_time cmpq 2|activation_time tpnz chain_later " " Must be queued before C [PR1] " ----------------------------- " ldaq null_ptr eraq 2|previous_threaded_process_ptr ana ring_number_mask tze insert_at_the_first_place " " Queuing now the process " ----------------------- " bill_book_queuing: epp3 2|previous_threaded_process_ptr,* PR3 : previuos spri3 4|previous_threaded_process_ptr epp7 3|locals_ptr,* spri5 7|next_threaded_process_ptr spri1 4|next_threaded_process_ptr spri5 2|previous_threaded_process_ptr tra bill_book_end " chain_later: " " Was it the last in the queue ? " ------------------------------ " ldaq null_ptr eraq 2|next_threaded_process_ptr ana ring_number_mask tze set_at_the_last_place " " No " -- " epp1 2|next_threaded_process_ptr,* epp2 1|locals_ptr,* ldq 4|activation_time cmpq 2|activation_time tpnz chain_later tra bill_book_queuing " " bill_book was empty " ------------------- " bill_book_was_empty: epp3 null_ptr,* spri3 4|next_threaded_process_ptr set_at_the_first_place: spri5 0|bill_book_ptr tra bill_book_end " " The process must be inserted at the beginning of the queue " ----------------------------------------------------------- " insert_at_the_first_place: spri1 4|next_threaded_process_ptr spri5 2|previous_threaded_process_ptr tra set_at_the_first_place " " The process must be set at the end of the queue " ----------------------------------------------- " set_at_the_last_place: spri5 2|next_threaded_process_ptr spri1 4|previous_threaded_process_ptr epp3 null_ptr,* spri3 4|next_threaded_process_ptr " " End " --- " bill_book_end: epp6 5|locals_ptr,* epp6 6|main_base_ptr,* tra choose_process " " " " " ************************************************** " * * " * SIMONE 'S OPERATORS FOR MONITORS AND MODULES * " * * " ************************************************** " " " monitor entry " ------------- " This operator initializes the pseudo_stack of a monitor " " Calling sequence : " epp1 [dynlk] " epp2 [addr of the monitor] " eax1 [addr of the arg_list] " tsp3 0|operator number " " monitor_entry: stz 2|monitor_busy aos 2|monitor_busy epp5 7|0,x1 get pr on arg_list spri5 2|mo_arg_list_ptr and store it epp5 6|base_process_ptr,* PR5 -> PROCESS epp5 5|execution_mo_ptr,* PR5 -> previous execution_mo ptr if any spri5 2|prev_exec_mo_ptr epp5 6|base_process_ptr,* PR5 -> PROCESS spri2 5|execution_mo_ptr spri2 6|execution_mo_ptr epp5 2|mo_arg_list_ptr,* Restore PR5 spri6 2|mo_father_ptr spri1 2|mo_dynlk stz 2|mo_active_sons stz 2|mo_father_type 0 if father is a process sxl6 2|mo_father_type 1 if it is a monitor ldq 2|mo_father_type [Q] = father_type anq check_mo_father_type_bit tze nothing_with_act_sons aos 1|mo_active_sons add one when father monormod nothing_with_act_sons: ldaq null_ptr staq 2|mon_fifo_queue_ptr staq 2|mon_fifo_queue_end_ptr staq 2|mon_signalers_queue_ptr stz 2|monitor_busy tra 3|0 module_entry: epp5 7|0,x1 get pr on arg_list spri5 2|mo_arg_list_ptr and store it spri6 2|mo_father_ptr epp5 6|base_process_ptr,* PR5 -> PROCESS epp5 5|execution_mo_ptr,* PR5 -> previous execution_mo ptr if any spri5 2|prev_exec_mo_ptr epp5 6|base_process_ptr,* PR5 -> PROCESS spri2 5|execution_mo_ptr spri2 6|execution_mo_ptr spri1 2|mo_dynlk stz 2|mo_father_type 0 if father is a process sxl6 2|mo_father_type 1 if it is a monitor stz 2|mo_active_sons ldq 2|mo_father_type [Q] = father_type anq check_mo_father_type_bit tze end_init_mo aos 1|mo_active_sons add one when father monormod end_init_mo: tra 3|0 " " " " " RESTOR_PREV_EXEC_MO " -------------------- " " " This operator restors in execution_mo_ptr word (in process stack) " the address of the requested monitor or module that has possibly " be altered by another monitor or module initialisation. " " Calling sequence : " tsp3 0|operator_numbrer " " Assumes that PR2 -> just initialized monitor " " restor_prev_mo: spri1 6|work_for_sim save pr1 epp1 6|base_process_ptr,* PR1 -> base of the process epp2 2|prev_exec_mo_ptr,* PR2 -> requested monitor or module spri2 1|execution_mo_ptr store it epp1 6|work_for_sim,* restor PR1 tra 3|0 " " " " INIT_COND OPERATOR " ------------------- " " This operator initializes conditions " " assumed that pr2 -> condition to br init " calling sequence : " tsp3 pr0|operator_number " init_cond: epp1 null_ptr,* spri1 pr2|cond_queue_ptr spri1 pr2|cond_queue_end_ptr stz pr2|cond_counter tra pr3|0 " " " OPERATOR ASK_FOR_EXCLUSION " -------------------------- " " This operator is called when a process need the exclusion of a " monitor (i.e when it calls an entry_point of this monitor) " If the monitor is busy the process can enter it, otherwise it " is set in the queue. " " assume that pr2 --> monitor required " " calling sequence: " tsp3 0|operator number " " ask_for_exclusion: ldq 2|monitor_busy is monitor busy ? tze take_exclusion " " process must be queued " first save registers " spri7 6|save_regs save PR7 epp7 6|base_process_ptr,* PR7 <- Process body stack spri3 6|stack_frame.return_ptr save stack_frame return point spri 7|save_ptr_regs save ptr regs epp5 6|base_process_ptr,* PR5 <- Process to be queued epp7 6|save_regs,* restor PR7 spri7 5|save_ptr_regs+14 save real PR7 value epp4 5|locals_ptr,* PR4 <- [PR5] locals sreg 5|save_regs save regs " " now queue the process " ldaq null_ptr ) eraq 2|mon_fifo_queue_ptr ) is the queue empty ? ana ring_number_mask ) tze set_in_fifo_queue epp1 2|mon_fifo_queue_end_ptr,* PR1 <- last in the queue epp4 1|locals_ptr,* PR4 <- [PR1] locals spri5 4|next_threaded_process_ptr store [PR5] as [PR1] NTP epp4 5|locals_ptr,* PR4 <- [PR5] locals spri1 4|previous_threaded_process_ptr store [PR1] as [PR5] PTP tra add_in_fifo_queue set_in_fifo_queue: spri5 2|mon_fifo_queue_ptr store [PR5] as the 1st FIFO queued Process add_in_fifo_queue: spri5 2|mon_fifo_queue_end_ptr store [PR5] as the last FIFO queued process ldaq null_ptr staq 4|next_threaded_process_ptr store NIL as [PR5] NTP " " now select process to activate " Monitor is busy so select only in active_process_queue " or in bill_book " " epp6 4|main_base_ptr,* PR6 <- Main process stack tra choose_process take_exclusion: aos 2|monitor_busy spri5 6|work_for_sim save PR5 epp5 6|base_process_ptr,* PR5 <- process stack spri2 5|execution_mo_ptr store PR2 as [PR5] exec monit spri5 2|mon_tenant_process_ptr store PR5 as [PR2] holding process epp5 6|work_for_sim,* restor PR5 tra 3|0 " " OPERATOR FREE_EXCLUSION " " " This operator is called when a process leaves a monitor. " assume that pr2 --> monitor to be freed " " calling sequence: " tsp3 0|operator_number " free_exclusion: spri5 6|work_for_sim save PR5 epp5 6|base_process_ptr,* PR5 --> proces' base ldaq null_ptr staq 5|execution_mo_ptr normal execution epp5 6|work_for_sim,* restor PR5 eraq 2|mon_signalers_queue_ptr ana ring_number_mask tnz select_act_proc ldaq null_ptr eraq 2|mon_fifo_queue_ptr ana ring_number_mask tnz select_fifo_proc " " if no other process selected just free monitor " stz 2|monitor_busy tra 3|0 select_act_proc: " " process must be queued " first save registers " spri7 6|save_regs save PR7 epp7 2|mon_tenant_process_ptr,* PR7 <- holding process spri3 6|stack_frame.return_ptr save return point spri 7|save_ptr_regs save ptr_regs epp5 2|mon_tenant_process_ptr,* PR5 : Process to be queued epp7 6|save_regs,* restor PR7 spri7 5|save_ptr_regs+14 save PR7 real value epp4 5|locals_ptr,* PR4 <- holding process locals sreg 5|save_regs save regs epp1 2|mon_signalers_queue_ptr,* PR1 <- first signaller epp4 1|locals_ptr,* PR4 <- locals epp4 4|next_threaded_process_ptr,* PR4 <- New first sgnaller spri4 2|mon_signalers_queue_ptr Store it tra select_end select_fifo_proc: " " process must be queued " first save registers " spri7 6|save_regs epp7 2|mon_tenant_process_ptr,* spri3 6|stack_frame.return_ptr spri 7|save_ptr_regs epp5 2|mon_tenant_process_ptr,* PR5 : Process to be queued epp7 6|save_regs,* spri7 5|save_ptr_regs+14 epp4 5|locals_ptr,* sreg 5|save_regs epp1 2|mon_fifo_queue_ptr,* epp4 1|locals_ptr,* epp4 4|next_threaded_process_ptr,* spri4 2|mon_fifo_queue_ptr select_end: spri2 5|work_for_sim tsp2 0|-5 epp2 5|work_for_sim,* " " [PR1] MUST BE ACTVATED " ---------------------- " spri2 1|execution_mo_ptr spri1 2|mon_tenant_process_ptr epp6 1|0 tra activate_process " " " " " EXIT OPERATOR " -------------- " " " This operator is called when a process executes an EXIT instruction " anywhwere but during its body execution. " In such a case the process is executing a non pure procedure and " therefor the execution occurs inside the process pseudo stack. " This procedure may be a monitor's one. Then the concerned one is " to be freed. " At least the stack is to be cleared as in the case of a ordinary " procedure termination. Then the process ends waiting its active " sons and closing its variables. " " " " Calling sequence : " " tra 0|operator_number " exit: epp5 6|base_process_ptr,* PR5 --> Process' base ldaq null_ptr eraq 5|execution_mo_ptr Monitor or module proc ? ana ring_number_mask tze just_update_ptrs epp2 5|execution_mo_ptr,* PR2 --> concerned object ldq 2|mo_type Monitor ? tze just_update_ptrs tsp3 free_exclusion Monitor to free just_update_ptrs: inhibit on epp1 6|stack_frame.next_sp,* spri1 5|stack_frame.next_sp Update stack_frame epp6 5|0 inhibit off epp3 6|locals_ptr,* PR3 --> locals epp3 3|exit_ptr,* Process end tra 3|0 " " " " *************************************** " * * " * OPERATORS DEALING WITH CONDITIONS * " * * " *************************************** " " " SIGNAL_OPERATOR " --------------- " " assume that pr2 --> condition affected " " calling sequence: " tsp3 0|operator number " signal: ldq 2|cond_counter tze nothing " " save context " spri7 6|save_regs epp7 6|base_process_ptr,* spri 7|save_ptr_regs epp5 6|base_process_ptr,* PR5 : Process to be queued spri3 6|stack_frame.return_ptr epp4 5|locals_ptr,* epp7 6|save_regs,* spri7 5|save_ptr_regs+14 sreg 5|save_regs " " now set proc in signaller's queue " epp5 6|base_process_ptr,* epp1 5|execution_mo_ptr,* ldaq null_ptr eraq 1|mon_signalers_queue_ptr ana ring_number_mask tze no_signaler epp7 1|mon_signalers_queue_ptr,* PR7 -> first waiting process in monitor epp4 7|locals_ptr,* spri5 4|previous_threaded_process_ptr store NTP epp4 5|locals_ptr,* PR4 -> [PR5]'s locals spri7 4|next_threaded_process_ptr tra skip_no_signaler no_signaler: ldaq null_ptr staq 4|next_threaded_process_ptr skip_no_signaler: ldaq null_ptr staq 4|previous_threaded_process_ptr spri5 1|mon_signalers_queue_ptr " " UPDATE NOW COND_QUEUE " epp5 2|cond_queue_ptr,* ldq 2|cond_counter sbq 1,dl stq 2|cond_counter tze cond_queue_empty epp4 5|locals_ptr,* ldaq null_ptr staq 4|previous_threaded_process_ptr epp4 4|next_threaded_process_ptr,* spri4 2|cond_queue_ptr cond_queue_empty: " " AND ACTIVATE PROCESS " spri5 1|mon_tenant_process_ptr spri1 5|execution_mo_ptr epp6 5|0 tra activate_process nothing: tra 3|0 " " " WAIT OPERATOR " ------------- " " This operator is called when a process needs to wait on " a condition. It queues the process in the condition queue and acti- " vate another one " " assumed that pr2 --> condition " " calling sequence: " tsp3 0|operator number " cwait: " " SAVE CONTEXT " spri7 6|save_regs epp7 6|base_process_ptr,* spri3 6|stack_frame.return_ptr spri 7|save_ptr_regs epp5 6|base_process_ptr,* PR5 : Process to be queued epp4 5|locals_ptr,* PR4 --> Locals epp7 6|save_regs,* spri7 5|save_ptr_regs+14 sreg 5|save_regs sta 4|priority store priority " " NOW QUEUE PROCESS " ldq 2|cond_counter tze init_cond_queue epp1 2|cond_queue_end_ptr,* PR1 -> last process in the queue epp7 1|locals_ptr,* PR7 -> locals cmpa 7|priority compare with new_process' prioriry tmi not_at_end if new process priority < last " " AT THE END OF THE QUEUE " spri1 4|previous_threaded_process_ptr spri5 7|next_threaded_process_ptr tra end_init_cond " " THE QUEUE WAS EMPTY " init_cond_queue: ldaq null_ptr staq 4|previous_threaded_process_ptr spri5 2|cond_queue_ptr end_init_cond: spri5 2|cond_queue_end_ptr ldaq null_ptr staq 4|next_threaded_process_ptr tra select_process " " " PROCESS IS NOT TO BE END QUEUED " not_at_end: epp1 2|cond_queue_ptr,* PR1 --> 1st in queue epp7 1|locals_ptr,* PR7 --> locals cmpa 7|priority compare priorities tpl insert_inside " " " PROCESS QUEUED AT THE BEGINNING " " spri5 7|previous_threaded_process_ptr update queue spri1 4|next_threaded_process_ptr ldaq null_ptr staq 4|previous_threaded_process_ptr spri5 2|cond_queue_ptr update cond : Beginning of the queue tra select_process " " " PROCESS TO BE QUEUED INSIDE THE QUEUE " " insert_inside: ldq 4|priority proc tb queue's priority in Q insert_later: epp1 7|next_threaded_process_ptr,* PR1 --> Next in queue epp7 1|locals_ptr,* PR7 --> PR1's locals cmpq 7|priority tpl insert_later " " " PROCESS TO BE QUEUED BEFORE PR1 " " spri1 4|next_threaded_process_ptr epp0 7|previous_threaded_process_ptr,* spri0 4|previous_threaded_process_ptr spri5 7|previous_threaded_process_ptr epp1 0|locals_ptr,* spri5 1|next_threaded_process_ptr " " NOW SELECT PROCESS TO BE RESTARTED " select_process: aos 2|cond_counter update cond : counter +:= 1 epp1 5|execution_mo_ptr,* ldaq null_ptr eraq 1|mon_signalers_queue_ptr ana ring_number_mask tze fifoq " " SELECTED IN SIGNALERS' QUEUE " epp2 1|mon_signalers_queue_ptr,* epp7 2|locals_ptr,* epp4 7|next_threaded_process_ptr,* spri4 1|mon_signalers_queue_ptr tra activproc " fifoq: ldaq null_ptr eraq 1|mon_fifo_queue_ptr ana ring_number_mask tze algonorm " " SELECTED IN FIFO QUEUE " epp2 1|mon_fifo_queue_ptr,* epp7 2|locals_ptr,* epp4 7|next_threaded_process_ptr,* spri4 1|mon_fifo_queue_ptr tra activproc " " SELECT IN MAIN'S QUEUES " algonorm: epp2 5|execution_mo_ptr,* stz 2|monitor_busy epp1 5|locals_ptr,* epp6 1|main_base_ptr,* tra choose_process " " ACTIVPROC " activproc: spri2 1|mon_tenant_process_ptr spri1 2|execution_mo_ptr epp6 2|0 tra activate_process " " " " PRIORITY " -------- " " This operator returns the priority of the ieme process blocked on " a specified condition. If no process matches with this criteria " then returns -1 ; " " " Calling sequence : " " epp2 [condition] " ldq [i] " tsp3 [operator_number] " " priority_op: cmpq 2|cond_counter Is i too large? tmoz cont lda moinsun i is too large tra 3|0 return cont: stz 6|op_work +1 at each step aos 6|op_work epp5 2|cond_queue_ptr,* PR5 --> 1st waiting process epp1 5|locals_ptr,* PR1 --> locals cmpq 6|op_work right process ? tze priority_end priority_deb: aos 6|op_work epp5 1|next_threaded_process_ptr,* PR5 --> next epp1 5|locals_ptr,* PR1 --> locals cmpq 6|op_work right process ? tpnz priority_deb priority_end: lda 1|priority tra 3|0 " " " EMPTY " ----- " " This operator verifies wether a condition 's queue is empty or not " " " Calling sequence: " " epp2 " tsp3 0|operator number " " empty: lda 2|cond_counter tze empty_cond lda 1,dl tra empty_end empty_cond: lda 0,dl empty_end: tra 3|0 " " " " LENGTH " ------ " " length: lda 2|cond_counter tra 3|0 " " " " ********* " * * " * VTIME * " * * " ********* " " " RETURN VIRTAL TIME " " Calling sequence : " tra 3|operator number " " vtime: spri1 6|save_regs epp1 6|base_process_ptr,* epp1 1|locals_ptr,* epp1 1|main_base_ptr,* epp1 1|locals_ptr,* lda 1|hour epp1 6|save_regs,* tra 3|0 " " " " TERMINATE OPERATOR " ------------------ " " " Set pr6 on main and then call return " " " Calling sequence : " " tsp3 0|[operator number] " " terminate: epp6 6|base_process_ptr,* epp6 6|locals_ptr,* epp6 6|main_base_ptr,* tra 3|0 " " " " " " ******************* " * RANDOM FUNCIONS * " * OPERATORS * " ******************* " " " NORMAL " ------ " " Generates a random number greater than -6.0 and less than " 6.0 with a normal distribution by call to the random_$normal " subroutine. " The seed is passed as the first argument in the argument " list and the results is stored as the second one. The result is on " one word and has to be extended as a double word. " " " Assumed that arg list is built as follow : " " " " --------------------- 0 " | arg list header | " --------------------- 2 " | ptr on seed | " --------------------- 4 " | ptr on result | " --------------------- 6 " " Calling sequence: " " epp2 " tsp3 0| " " normal: ora 4,dl spri 6|op_work save pointers registers sreg 6|save_regs save other registers epaq 0,ic lprp4 7|stack_header.lot_ptr,*au ldaq 6|save_regs+4 staq 2|0 update arg list epp0 2|0 PR0 --> arg list epp1 6|base_process_ptr,* epp1 1|locals_ptr,* epp1 1|main_base_ptr,* epp1 1|stack_frame.operator_ptr,* spri1 6|stack_frame.operator_ptr epp2 3,ic PR2 --> return spri2 6|stack_frame.return_ptr store return tsp3 |[normal] call normal tra norm_unif_end for result expansion " " " " UNIFORM " -------- " " " Generates a random number with a value between 0.0 and " 1.0 with a unifrom distribution by call to the random_$uniform " subroutine. " The seed is passed as the first argument in the argument " list and the results is stored as the second one. The result is on " one word and has to be extended as a double word. " " " " Assumed that arg list is built as follow: " " " --------------------- 0 " | arg list header | " --------------------- 2 " | ptr on seed | " --------------------- 4 " | ptr on result | " --------------------- 6 " " Calling sequence: " " epp2 " tsp3 0| " " uniform: ora 4,dl spri 6|op_work save pointers registers sreg 6|save_regs save other registers epaq 0,ic lprp4 7|stack_header.lot_ptr,*au ldaq 6|save_regs+4 staq 2|0 update arg list epp0 2|0 PR0 --> arg list epp1 6|base_process_ptr,* epp1 1|locals_ptr,* epp1 1|main_base_ptr,* epp1 1|stack_frame.operator_ptr,* spri1 6|stack_frame.operator_ptr epp2 3,ic PR2 --> return spri2 6|stack_frame.return_ptr store return tsp3 |[uniform] call uniform norm_unif_end: epp2 6|op_work+4,* restor pr2 epp2 2|4,* pr2 --> result stz 2|1 expand result tra common_random_return negexp: " " " " " " RANDINT " ------- " " " Generates a random number with a value between two " bounds given by the programmer and an uniform distribution inside " this bounds. " First call random_$uniform and updates result just like " uniform operator does. " Then computes : " result * (high_bound - low_bound + 1) * low_bound " At least call trunc operator to get an integer as the " result. " " Assumed that arg list is built as follw ; " " --------------------- 0 " | arg list header | " --------------------- 2 " | ptr on seed | " --------------------- 4 " | ptr on result | " --------------------- 6 " | ptr on low bound | " --------------------- 8 " | ptr on high bound | " --------------------- " " " Calling sequence: " epp2 " tsp3 0| " " randint: ora 4,dl spri 6|op_work save pointers registers sreg 6|save_regs save other registers epaq 0,ic lprp4 7|stack_header.lot_ptr,*au ldaq 6|save_regs+4 staq 2|0 update arg list epp0 2|0 PR0 --> arg list epp1 6|base_process_ptr,* epp1 1|locals_ptr,* epp1 1|main_base_ptr,* epp1 1|stack_frame.operator_ptr,* spri1 6|stack_frame.operator_ptr necessary to return from random epp2 3,ic PR2 --> return spri2 6|stack_frame.return_ptr store return tsp3 |[uniform] call uniform epp2 6|op_work+4,* restor pr2 epp2 2|4,* pr2 --> result stz 2|1 expand result epp1 6|op_work+4,* PR1 --> arg list epp3 1|8,* PR3 --> high_bound lda 3|0 load A with high_bound epp5 1|6,* PR5 --> low_bound sba 5|0 A := high_bound - low_bound sta 3|0 store A aos 3|0 add one epp0 6|op_work,* PR0 --> pascal_operators ldq 3|0 load Q tsp3 0|32 Convert integer to real dfmp 2|0 multiply dfst 2|0 store intermediate result ldq 5|0 Load Q for convertion tsp3 0|32 Convert integer to real dfad 2|0 add low_bound spri0 2|2 for op_work is modified by TRUNC tsp3 0|63 call TRUNC operator sta 2|0 store reel result epp0 2|2,* restor pr0 spri0 6|op_work store PR0 at the right place common_random_return: lpri 6|op_work restor pointer registers lreg 6|save_regs restor other registers tra 3|0 return " " " " " "END INCLUDE simone_operators_.incl.alm " " " ----------------------------------------------------------- " " " " Historical Background " " This edition of the Multics software materials and documentation is provided and donated " to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. " as a contribution to computer science knowledge. " This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology, " Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull " and Bull HN Information Systems Inc. to the development of this operating system. " Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970), " renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership " of Professor Fernando Jose Corbato. Users consider that Multics provided the best software architecture for " managing computer hardware properly and for executing programs. Many subsequent operating systems " incorporated Multics principles. " Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., " as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. . " " ----------------------------------------------------------- " " Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without " fee is hereby granted,provided that the below copyright notice and historical background appear in all copies " and that both the copyright notice and historical background and this permission notice appear in supporting " documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining " to distribution of the programs without specific prior written permission. " Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc. " Copyright 2006 by Bull HN Information Systems Inc. " Copyright 2006 by Bull SAS " All Rights Reserved " "