1. ; Copyright (c) 2012 Teresa Bradbury
  2.  
  3. ; Execution starts here
  4. ; In this example there are 3 threads
  5. ; Thread 2 prints twice then kills itself (by returning)
  6. ; Thread 1 loops until the main thread kills it
  7. 0x0100:
  8. call threadinit
  9. load #thread1 R1
  10. load #thread1stack R2
  11. call threadcreate
  12. store R1 thread1id
  13. load #thread2 R1
  14. load #thread2stack R2
  15. call threadcreate
  16. store R1 thread2id
  17. mainloop:
  18. load #mainstr R1
  19. call printstring
  20. call threadyield
  21. ;jump mainloop ; uncomment this for inf-loop
  22. load #mainstr R1
  23. call printstring
  24. call threadyield
  25. load #mainstr R1
  26. call printstring
  27. call threadyield
  28. load #mainstr R1
  29. call printstring
  30. call threadyield
  31. load thread1id R1
  32. call threaddestroy
  33. load #mainstr R1
  34. call printstring
  35. call threadyield
  36. load #mainstr R1
  37. call printstring
  38. call threadselfdestruct
  39.  
  40. thread1id : block 1
  41. thread2id : block 1
  42. mainstr : block #"Main Thread\n"
  43.  
  44. thread1 :
  45. load #thread1str R1
  46. call printstring
  47. call threadyield
  48. jump thread1
  49. ;return
  50.  
  51. thread2 :
  52. load #thread2str R1
  53. call printstring
  54. call threadyield
  55. ;jump thread2
  56. load #thread2str R1
  57. call printstring
  58. call threadyield
  59. return
  60.  
  61. thread1stack : block 8
  62. thread2stack : block 8
  63. thread1str : block #"Thread 1\n"
  64. thread2str : block #"Thread 2\n"
  65.  
  66. ; R1 : string pointer (changed)
  67. printstring :
  68. load R1 R2
  69. jumpz R2 printstring_end
  70. store R2 0xfff0
  71. add R1 ONE R1
  72. jump printstring
  73. printstring_end :
  74. return
  75.  
  76. ; -------------------------------------
  77. ; --------- Concurrency Data ----------
  78. ; -------------------------------------
  79.  
  80. maxthreads : block #3
  81. ; For each thread, the first word is one if the thread exists
  82. ; and zero otherwise. The second word is the stack pointer.
  83. threaddata : block 6
  84. currentthreadid : block 1
  85.  
  86. ; -------------------------------------
  87. ; ------- Concurrency Functions -------
  88. ; -------------------------------------
  89.  
  90. ; must be called at start of the program
  91. ; it initializes the data structures
  92. ; No parameters
  93. threadinit :
  94. load maxthreads R0
  95. threadinit_threaddatainit :
  96. ; R0 is the thread that is being initialised. It counts down.
  97. add R0 MONE R0
  98. ; thread id
  99. move R0 R1
  100. ; structure offset
  101. move ZERO R2
  102. ; no flags
  103. move ZERO R3
  104. call threaddatastore
  105. jumpnz R0 threadinit_threaddatainit
  106. ; set thread zero to active
  107. move ZERO R1
  108. move ZERO R2
  109. move ONE R3
  110. call threaddatastore
  111. store ZERO currentthreadid
  112. return
  113.  
  114. ; R1 : in thread id
  115. ; R2 : in structure offset
  116. ; R1 : out data
  117. ; preserves R0
  118. threaddataload :
  119. ; structure has size 2
  120. load #2 R3
  121. mult R1 R3 R3
  122. add R3 R2 R3
  123. load R3 #threaddata R1
  124. return
  125.  
  126. ; R1 : in thread id
  127. ; R2 : in structure offset
  128. ; R3 : in data
  129. ; preserves R0
  130. threaddatastore :
  131. ; structure has size 2
  132. load #2 R4
  133. mult R1 R4 R4
  134. add R4 R2 R4
  135. store R3 #threaddata R4
  136. return
  137.  
  138. ; R1 : in function pointer
  139. ; R2 : in stack pointer
  140. ; R1 : out thread id (-1 for error)
  141. ; Stack needs to be big enough for thread's workings,
  142. ; plus at least 3
  143. threadcreate :
  144. push R1
  145. push R2
  146. ; find a free thread id (in R0)
  147. move ZERO R0
  148. threadcreate_findid :
  149. load maxthreads R1
  150. sub R1 R0 R2
  151. ; if R2 == 0 then R0 == maxthreads
  152. ; so return -1 as no available threads
  153. jumpnz R2 threadcreate_no_error
  154. move MONE R1
  155. return
  156. threadcreate_no_error :
  157. move R0 R1
  158. move ZERO R2
  159. call threaddataload
  160. jumpz R1 threadcreate_foundid
  161. add ONE R0 R0
  162. jump threadcreate_findid
  163.  
  164. threadcreate_foundid :
  165. ; created thread is inactive (not current) and
  166. ; the stack contains a pointer to selfdestruct then
  167. ; the provided stack pointer so first it will
  168. ; return to the given function and if it returns
  169. ; again it will be destroyed
  170. pop R2 ; stack pointer
  171. pop R1 ; function pointer
  172. store R1 #1 R2
  173. load #threadselfdestruct R1
  174. store R1 #0 R2
  175. ; Store the stack pointer
  176. move R0 R1
  177. add R2 ONE R3
  178. move ONE R2
  179. call threaddatastore
  180. ; Mark the thread as existant
  181. move R0 R1
  182. move ZERO R2
  183. move ONE R3
  184. call threaddatastore
  185.  
  186. ; Return the created thread id
  187. move R0 R1
  188. return
  189.  
  190. ; Pass thread id in R1
  191. threaddestroy :
  192. ; If thread id is not current, we just mark nonexistant
  193. ; If thread id *is* current, we mark nonexistant and then call
  194. ; threadyield to switch to another thread
  195. move R1 R0 ; because R0 survives the function calls
  196. ; Turn off the thread
  197. move R0 R1
  198. move ZERO R2
  199. move ZERO R3
  200. call threaddatastore
  201. ; Is this the current thread?
  202. load currentthreadid R1
  203. sub R0 R1 R2
  204. jumpnz R2 threaddestroy_notcurrentthread
  205. call threadyield
  206. threaddestroy_notcurrentthread :
  207. return
  208.  
  209. ; No parameters - destroys current thread
  210. ; this is called on returning from a thread function
  211. threadselfdestruct :
  212. load currentthreadid R1
  213. jump threaddestroy
  214.  
  215. ; No parameters
  216. threadyield :
  217. ; store the stackpointer
  218. load currentthreadid R1
  219. move ONE R2
  220. move SP R3
  221. call threaddatastore
  222. ; round robin scheduling
  223. ; we will eventually choose the thread id in R0
  224. load currentthreadid R0
  225. threadyield_findnext :
  226. load maxthreads R1
  227. add R0 ONE R0
  228. sub R1 R0 R2
  229. ; if R2 == 0 then R0 == maxthreads
  230. ; so R0 := 0
  231. jumpnz R2 threadyield_mod
  232. move ZERO R0
  233. threadyield_mod :
  234. move R0 R1
  235. move ZERO R2
  236. call threaddataload
  237. jumpnz R1 threadyield_foundnext
  238. ; if none of the threads exist, halt
  239. load currentthreadid R4
  240. sub R4 R0 R4
  241. jumpnz R4 threadyield_findnext
  242. halt
  243. threadyield_foundnext :
  244. store R0 currentthreadid
  245. ; load the new stack pointer
  246. load currentthreadid R1
  247. move ONE R2
  248. call threaddataload
  249. move R1 SP
  250. return