;;;; ;;; Default People Library File ;;;; ; Usage: ; Define library functions ; arguments delivered in q0 ; return values should be placed in q0 ; ; queues q0-q4 are available for use ; after the func completes, all should be ; empty and unmapped, except possibly a return ; value in q0. ; ; given a type from: int,float,boolean,ANY,source,sink,void ; ; Libfuncs come in two varieties: inline and call ; * inline funcs are copied verbatim at point of ; usage ; * call funcs are BRL'd to, leaving link value in q0 ; upon termination, they should JMP to this value. ;; Print values, not strings print inline void PRINTQNNL q0 ; print value end ;; Prints a pair of values printspec inline void MOVE q0, q1 PRINTSPEC q1, q0 ; print pair of vals end ;; Prints a pair of values with a different header printspecb inline void MOVE q0, q1 PRINTSPECB q1, q0 ; print pair of vals end ;; Print Strings (place holder, it's hardcoded ;; due to lack of String implementation) prints inline void PRINTS "You should never see this.\n" end ;; Integer Random function random inline int RANDOM q0 ; generate random number end ;; Floating point random function ;; remember to cast result to float: [float]frandom() frandom inline float FRANDOM q0 ; generate floating point random number end ;; Touch - ensure value present ;; if it's been invoked, it's argument has been copied to ;; q0, and copying only happens if the value is present. touch inline void CONSUME q0 ; eat value, touched end ;; Store commit - all stores completed after finished membar inline void MSYNC ; ensure store data sent end ;; Cycles - print out cycles cycles inline void CYCLES ; print cycles end ;; Yield processor to another thread yield inline void YIELD ; let another thread run end ;; Return's thread id getId inline ANY PROCID q0 ; gets a unique ID for the thread end ;; Shortcut to print out local id, proc# printId inline void PROCID q0 ; get id PRINTQ q0 ; print it end ;; compute a square root sqrt inline float SQRT q0, q0 ; compute square root end ;; compute integer absolute value abs call int SLTC @q0, 0, q1 ; negative? BRNZ q1, _abs_neg ; do neg MOVE q0, q0 ; return JMP q0 ; jump to caller _abs_neg: MULC q0, -1, q0 ; flip sign JMP q0 ; jump to caller end rand call int MOVECL 0, q3 ; mask = 0 MOVE @q0, q4 ; temp = val _rand_test: SLEC @q4, 0, q1 ; test temp > 0 BRNZ q1, _rand_after ; if false, do false _rand_body: SHLC q3, 1, q3 ; mask = mask << 1 ORC q3, 1, q3 ; mask = mask | 1 SHRC q4, 1, q4 ; temp = temp >> 1 SLEC @q4, 0, q1 ; test temp <= 0 BRZ q1, _rand_body ; if false, do false _rand_after: RANDOM @q4 ; generate random number into res SHRC q4, 10, q4 ; res = res >> 10 AND q4, q3, q4 ; res = res & mask SLE @q4, @q0, q1 ; test res > val BRNZ q1, _rand_over ; if false, do false SUB q4, q0, q0 ; return res - val JMP q0 ; jump back to caller _rand_over: MOVE q4, q0 ; return res CONSUME q0 ; throw out val JMP q0 ; jump back to caller end enqueueAcquire call int EXCH q2, q3, q4 ; set up exchange MOVE @q0, q2 ; send queue BR _enqueue_poll_entry ; skip yield first time _enqueue_poll_loop: YIELD _enqueue_poll_entry: MOVECL 0, q2 ; base 0 MOVECL 0, q3 ; store a 0 BRZ q4, _enqueue_poll_loop ; got a 1? MOVECL 2, q2 ; get size MOVECL 0, q3 ; replace with 0 SLTC @q4, 256, q1 ; space? BRNZ q1, _enqueue_next ; go on MOVECL 2, q2 ; size MOVE q4, q3 ; send size back CONSUME q4 ; eat 0 BR _enqueue_poll_loop ; try again _enqueue_next: MOVE q4, q0 ; return size CONSUME q0 ; eat size UNMAPQ q2 ; unmap UNMAPQ q3 ; unmap UNMAPQ q4 ; unmap JMP q0 end dequeueAcquire call int EXCH q2, q3, q4 ; set up exchange MOVE @q0, q2 ; send queue BR _dequeue_poll_entry ; skip yield first time _dequeue_poll_loop: YIELD _dequeue_poll_entry: MOVECL 0, q2 ; base 0 MOVECL 0, q3 ; store a 0 BRZ q4, _dequeue_poll_loop ; got a 1? MOVECL 2, q2 ; get size MOVECL 0, q3 ; replace with 0 BRNZ @q4, _dequeue_next ; go on CONSUME q4 ; eat 0 BR _dequeue_poll_loop ; try again _dequeue_next: MOVE q4, q0 ; return size CONSUME q0 ; eat queue UNMAPQ q2 ; unmap UNMAPQ q3 ; unmap UNMAPQ q4 ; unmap JMP q0 end ;; syncCreate - creates a synchronization point before ;; the given source[]. syncCreate call ANY SPAWNC @q0, _hub_code, q1 ; build hub MAPQC q2, q0, @q1 ; connect MOVE q0, q2 ; send source context MOVE q0, q2 ; send source queue number EEQ q2 ; ensure sent UNMAPQ q2 ; disconnect MOVE q1, q0 ; return hub context JMP q0 ; return end ;; syncSource - create a terminal from a hub syncSource call source SPAWNC @q0, _terminal_code, q1 ; build terminal MAPQC q2, q0, @q1 ; connect MOVE q0, q2 ; send hub context EEQ q2 ; ensure sent UNMAPQ q2 ; disconnect MOVE q1, q0 ; return source context MOVECL 1, q0 ; terminal receives in q1 JMP q0 ; return end ;; syncSend - have terminal send data syncSend call void MAPQC q2, q0, q0 ; connect to terminal PROCID q2 ; send send command EEQ q2 ; ensure sent UNMAPQ q2 ; disconnect CONSUME q0 ; eat queue number CONSUME q3 ; wait for complete JMP q0 ; return end ;; syncForward - have terminal send data, returns source (uniqueness issue) syncForward call source MAPQC q2, q0, @q0 ; connect to terminal PROCID q2 ; send send command MOVE q0, q0 ; cycle context to back MOVE q0, q0 ; cycle queue to back EEQ q2 ; ensure sent UNMAPQ q2 ; disconnect CONSUME q3 ; wait for complete JMP q0 ; return end ;; twiddleHub forces the hub to send whatever it's got twiddleHub call void MAPQC q1, q0, @q0 ; connect to hub ctrl PROCID q1 ; send request CONSUME q4 ; wait for accept UNMAPQ q1 ; disconnect MAPQC q1, q3, q0 ; connect to end MOVECL 1, q1 ; send end signal EEQ q1 ; ensure sent UNMAPQ q1 ; disconnect JMP q0 ; return end breakHub call source MOVE q0, q0 ; return context MOVECL 1, q0 ; dump to hub's data JMP q0 ; return end ;; code to implement the synchronization point above a source ;; q0 - ctrl ;; q1 - data ;; q2 - accept ;; q3 - end ;; q4 - forward hub_code call void MOVE q0, q1 ; extract source MAPQ q4, q0, q1 ; construct forw _hub_top: MAPQC q2, q4, q0 ; connect to terminal's accept MOVECL 1, q2 ; send accept signal EEQ q2 ; wait for send UNMAPQ q2 ; disconnect CONSUME q3 ; wait for end signal, assumes end can't lead data _hub_send_loop: MOVE q1, q4 ; move value SEMPTY q1, q5 ; done yet? BRZ q5, _hub_send_loop ; keep moving BR _hub_top ; go to top end ;; special source/sink to negotiate with hub ;; q0 - ctrl ;; q1 - data ;; q2 - forward ;; q3 - req ;; q4 - accept ;; q5 - end ;; q6 - reply ;; q7 - temp terminal_code call void MAPQC q2, q1, @q0 ; connect forw to hub data MAPQC q3, q0, @q0 ; connect req to hub ctrl MAPQC q5, q3, q0 ; connect end to hub end _terminal_top: MAPQC q6, q3, q0 ; connect to sender PROCID q3 ; send request CONSUME q4 ; wait for go ahead _terminal_send: MOVE q1, q2 ; move value SEMPTY q1, q7 ; done yet? BRZ q7, _terminal_send ; keep moving MOVECL 1, q6 ; signal end to sender MOVECL 1, q5 ; signal end of data EEQ q6 ; ensure sent UNMAPQ q6 ; disconnect from sender BR _terminal_top ; go to top end ;; code to hold args for durasive methods ;; q0 - data ;; q1 - forw ;; q2 - signal holding_code call void MAPQC q1, q0, q0 ; connect forw to dur args _holding_top: MOVE q2, q3 ; pull counter _holding_loop: MOVE q0, q1 ; send value SUBC q3, 1, q3 ; dec counter BRNZ @q3, _holding_loop ; done? CONSUME q3 ; eat 0 BR _holding_top ; go to top end ;; load file, always loads same file... ;; returns a sink (should assign to sink variable) ;; sink[int] s = file(); file inline sink PROCID q1 ; grab cur location SPAWNC q1, _file_load, q0 ; fork thread for new load sink end ;; Sink code ;; this is required for streams to work. It may ;; use any queues it desires, as it's always forked ;; off. sink_code call void SIC @q0, q2 ; control code? BRZ q2, _sink_control ; goto control tests MOVE q0, q2 ; grab context MAPQ q3, q0, q2 ; map back MOVE q1, q3 ; send word EEQ q3 ; ensure sent UNMAPQ q3 ; disconnect BR _sink_code ; do it again _sink_control: BRZ @q0, _sink_kill ; kill? SUBC @q0, 1, q2 ; next BRZ q2, _sink_forward ; forward? CONSUME q0 ; who knows, eat it BR _sink_code ; loop back _sink_kill: HALT ; die _sink_forward: CONSUME q0 ; eat code MOVE q0, q2 ; pull context MAPQ q3, q0, q2 ; forward data _sink_forward_loop: MOVE q1, q3 ; send value on BR _sink_forward_loop ; do it again.. and again.. _file_load: FILE "file.bin", q1 ; load file into sink data queue BR _sink_code ; branch to top end