iserial.s 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. ;;; Serial - interrupt driven serial I/O
  2. ;;;
  3. ;;; Copyright (c) 2009 Openmoko Inc.
  4. ;;;
  5. ;;; Authors Christopher Hall <hsw@openmoko.com>
  6. ;;;
  7. ;;; Redistribution and use in source and binary forms, with or without
  8. ;;; modification, are permitted provided that the following conditions are
  9. ;;; met:
  10. ;;;
  11. ;;; 1. Redistributions of source code must retain the above copyright
  12. ;;; notice, this list of conditions and the following disclaimer.
  13. ;;;
  14. ;;; 2. Redistributions in binary form must reproduce the above copyright
  15. ;;; notice, this list of conditions and the following disclaimer in
  16. ;;; the documentation and/or other materials provided with the
  17. ;;; distribution.
  18. ;;;
  19. ;;; THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY
  20. ;;; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. ;;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22. ;;; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
  23. ;;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. ;;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  25. ;;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  26. ;;; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  27. ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  28. ;;; OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  29. ;;; IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. .include "regs.inc"
  31. ;;; register usage
  32. ;;; r0 .. r3 must be preserved
  33. ;;; r4 result low
  34. ;;; r5 result high
  35. ;;; r6 .. r9 arguments 1..4
  36. ;;; r10 ..r14 reserved
  37. ;;; r15 __dp value
  38. .section .bss
  39. ;;; buffer size = 2^n is conveient for modulo operation
  40. BufferSize = 2048
  41. ;;; buffer is full if: (write + 1) mod size == read
  42. ;;; buffer is full if: write == read
  43. RxBuffer:
  44. .space BufferSize
  45. RxRead:
  46. .long 0
  47. RxWrite:
  48. .long 0
  49. TxBuffer:
  50. .space BufferSize
  51. TxRead:
  52. .long 0
  53. TxWrite:
  54. .long 0
  55. .section .text
  56. ;;; wait wor serial output ready
  57. ;;; input:
  58. ;;; output:
  59. ;;; r4 = true if space in buffer, false if buffer is full
  60. ;;; r5 = address of TxWrite
  61. ;;; r6 = *NOT CHANGED* (will be byte to put)
  62. ;;; r7 = TxRead
  63. ;;; r8 = TxWrite (offset of byte to store)
  64. ;;; r9 = TxWrite + 1 (next free space)
  65. .global Serial_PutReady
  66. Serial_PutReady:
  67. xld.w %r7, TxRead
  68. xld.w %r5, TxWrite
  69. ld.w %r7, [%r7] ; read
  70. ld.w %r8, [%r5] ; write
  71. ld.w %r9, %r8
  72. add %r9, 1 ; write + 1
  73. xand %r9, (BufferSize - 1) ; mod buffer size
  74. cmp %r7, %r9 ; read == write ?
  75. jreq Serial_PutReady_buffer_full
  76. ld.w %r4, 1 ; TRUE => buffer is not full
  77. ret
  78. Serial_PutReady_buffer_full:
  79. ld.w %r4, 0 ; FALSE => buffer is full
  80. ret
  81. ;;; print a character
  82. ;;; input:
  83. ;;; r6 = char
  84. ;;; output:
  85. ;;; temporary:
  86. ;;; r4..r9
  87. .global Serial_PutChar
  88. Serial_PutChar_wait:
  89. xcall suspend ; suspend until buffer space available
  90. Serial_PutChar:
  91. call Serial_PutReady ; wait for buffer space
  92. or %r4, %r4
  93. jreq Serial_PutChar_wait
  94. xld.w %r4, TxBuffer ; buffer
  95. add %r4, %r8 ; buffer + offset
  96. ld.b [%r4], %r6 ; store byte
  97. xld.w %r4, R8_INT_ESIF01
  98. DISABLE_INTERRUPTS
  99. ld.ub %r8, [%r4]
  100. xand %r8, ESTX0 ; is Tx0 interrupt enabled
  101. jrne Serial_PutChar_l1
  102. ld.ub %r8, [%r4]
  103. xoor %r8, ESTX0 ; enable Tx0 interrupt
  104. ld.b [%r4], %r8
  105. xld.w %r5, R8_EFSIF0_TXD
  106. ld.b [%r5], %r6
  107. jp Serial_PutChar_l2
  108. Serial_PutChar_l1:
  109. ld.w [%r5], %r9 ; update TxWrite
  110. Serial_PutChar_l2:
  111. ENABLE_INTERRUPTS
  112. ret
  113. ;;; see if input is available
  114. ;;; input:
  115. ;;; output:
  116. ;;; r4 = 0 => not ready
  117. ;;; 1 => ready
  118. ;;; r5 = offset of byte to read
  119. ;;; r6 = address of RxRead
  120. ;;; temporary:
  121. .global Serial_InputAvailable
  122. Serial_InputAvailable:
  123. xld.w %r6, RxRead
  124. xld.w %r4, RxWrite
  125. ld.w %r5, [%r6] ; read
  126. ld.w %r4, [%r4] ; write
  127. cmp %r5, %r4 ; read == write ?
  128. jreq Serial_InputAvailable_buffer_empty
  129. ld.w %r4, 1 ; TRUE => buffer is not empty
  130. ret
  131. Serial_InputAvailable_buffer_empty:
  132. ld.w %r4, 0 ; FALSE => buffer is empty
  133. ret
  134. ;;; read a character
  135. ;;; input:
  136. ;;; output:
  137. ;;; r4 = char
  138. .global Serial_GetChar
  139. Serial_GetChar_wait:
  140. xcall suspend ; suspend until more input
  141. Serial_GetChar:
  142. call Serial_InputAvailable
  143. or %r4, %r4
  144. jreq Serial_GetChar_wait
  145. xld.w %r4, RxBuffer
  146. add %r4, %r5
  147. ld.ub %r4, [%r4]
  148. add %r5, 1
  149. xand %r5, (BufferSize - 1)
  150. ld.w [%r6], %r5 ; update RxRead
  151. ret
  152. ;;; flush input buffer
  153. ;;; input:
  154. ;;; output:
  155. .global Serial_FlushInput
  156. Serial_FlushInput:
  157. xld.w %r4, RxRead
  158. xld.w %r5, RxWrite
  159. ld.w %r6, 0
  160. DISABLE_INTERRUPTS
  161. ld.w [%r4], %r6
  162. ld.w [%r5], %r6
  163. ENABLE_INTERRUPTS
  164. ret
  165. ;;; initialisation
  166. ;;; input:
  167. ;;; output:
  168. .global Serial_initialise
  169. Serial_initialise:
  170. xld.w %r6, Vector_Serial_interface_Ch_0_Receive_buffer_full
  171. xld.w %r7, Serial_RxInterrupt
  172. xcall Vector_set
  173. xld.w %r6, Vector_Serial_interface_Ch_0_Receive_error
  174. xld.w %r7, Serial_RxInterrupt
  175. xcall Vector_set
  176. xld.w %r6, Vector_Serial_interface_Ch_0_Transmit_buffer_empty
  177. xld.w %r7, Serial_TxInterrupt
  178. xcall Vector_set
  179. ld.w %r5, 0
  180. xld.w %r4, RxRead
  181. ld.w [%r4], %r5
  182. xld.w %r4, RxWrite
  183. ld.w [%r4], %r5
  184. xld.w %r4, TxRead
  185. ld.w [%r4], %r5
  186. xld.w %r4, TxWrite
  187. ld.w [%r4], %r5
  188. DISABLE_INTERRUPTS
  189. xld.w %r4, R8_EFSIF_ADV ; set normal mode
  190. ld.w %r5, 0
  191. ld.b [%r4], %r5
  192. xld.w %r4, R8_INT_FSIF01 ; clear the interrupt
  193. xld.w %r5, FSTX0 | FSERR0 | FSRX0
  194. ld.b [%r4], %r5
  195. xld.w %r4, R8_INT_ESIF01
  196. ld.b %r5, [%r4]
  197. xand %r5, ~(ESRX0 | ESERR0 | ESTX0)
  198. xoor %r5, ESRX0
  199. ld.b [%r4], %r5
  200. xld.w %r4, R8_INT_PLCDC_PSIO0
  201. ld.ub %r5, [%r4]
  202. xand %r5, 0x0f
  203. xoor %r5, 0x70
  204. ld.b [%r4], %r5
  205. ENABLE_INTERRUPTS
  206. ret
  207. ;;; receive all bytes from receive FIFO
  208. ;;; input:
  209. ;;; output:
  210. .global Serial_RxInterrupt
  211. Serial_RxInterrupt:
  212. pushn %r14
  213. Serial_RxInterrupt_1:
  214. xld.w %r0, R8_INT_FSIF01 ; clear the interrupt
  215. xld.w %r2, FSRX0 | FSERR0
  216. ld.b [%r0], %r2
  217. xld.w %r0, R8_EFSIF0_STATUS
  218. xld.w %r1, R8_EFSIF0_RXD
  219. xld.w %r2, RxRead
  220. xld.w %r3, RxWrite
  221. Serial_RxInterrupt_loop:
  222. ld.ub %r4, [%r1] ; the received byte
  223. ld.w %r5, [%r3] ; RxWrite
  224. xld.w %r6, RxBuffer ; buffer start
  225. add %r6, %r5 ; + offset
  226. ld.b [%r6], %r4 ; store the byte
  227. ld.w %r6, [%r2] ; RxRead
  228. add %r5, 1 ; next position
  229. xand %r5, (BufferSize - 1) ; mod buffer size
  230. cmp %r6, %r5 ; read == write?
  231. jreq Serial_RxInterrupt_no_store ; ...yes => buffer overrun, byte is lost
  232. ld.w [%r3], %r5 ; update RxWrite
  233. Serial_RxInterrupt_no_store:
  234. ld.ub %r4, [%r0] ; read status
  235. ld.w %r5, 0
  236. ld.b [%r0], %r5 ; clear error flags
  237. xand %r4, RDBFx
  238. jrne Serial_RxInterrupt_loop
  239. Serial_RxInterrupt_done:
  240. popn %r14
  241. reti
  242. ;;; not being used - errors are treated as normal characters
  243. .if 0
  244. ;;; discard erroneous bytes from receive FIFO
  245. ;;; input:
  246. ;;; output:
  247. .global Serial_RxErrorInterrupt
  248. Serial_RxErrorInterrupt:
  249. pushn %r14
  250. xld.w %r0, R8_EFSIF0_STATUS
  251. xld.w %r1, R8_EFSIF0_RXD
  252. xld.w %r2, RxRead
  253. xld.w %r3, RxWrite
  254. Serial_RxErrorInterrupt_loop:
  255. ld.ub %r4, [%r0]
  256. xcall panic
  257. ld.w %r5, 0
  258. ld.b [%r0], %r5 ; clear error flags
  259. xand %r4, RDBFx
  260. jreq Serial_RxErrorInterrupt_done
  261. ld.ub %r4, [%r1] ; the received byte
  262. ld.w %r5, [%r3] ; RxWrite
  263. xld.w %r6, RxBuffer ; buffer start
  264. add %r6, %r5 ; + offset
  265. ld.b [%r6], %r4 ; store the byte
  266. ld.w %r6, [%r2] ; RxRead
  267. add %r5, 1 ; next position
  268. xand %r5, (BufferSize - 1) ; mod buffer size
  269. cmp %r6, %r5 ; read == write?
  270. jreq Serial_RxErrorInterrupt_loop ; ...yes => buffer overrun, byte is lost
  271. ld.w [%r3], %r5 ; update RxWrite
  272. jp Serial_RxErrorInterrupt_loop
  273. Serial_RxErrorInterrupt_done:
  274. xld.w %r0, R8_INT_FSIF01 ; clear the interrupt
  275. xld.w %r2, FSERR0 | FSRX0
  276. ld.b [%r0], %r2
  277. popn %r14
  278. reti
  279. .endif
  280. ;;; send one byte
  281. ;;; input:
  282. ;;; output:
  283. .global Serial_TxInterrupt
  284. Serial_TxInterrupt:
  285. pushn %r14
  286. xld.w %r0, R8_INT_FSIF01
  287. xld.w %r2, FSTX0
  288. ld.b [%r0], %r2 ; clear Tx0 interrupt
  289. xld.w %r0, TxRead
  290. xld.w %r1, TxWrite
  291. ld.w %r2, [%r0] ; read
  292. ld.w %r1, [%r1] ; write
  293. cmp %r1, %r2 ; read == write?
  294. jreq Serial_TxInterrupt_buffer_empty ; ...yes => all sent
  295. xld.w %r3, TxBuffer ; base address
  296. add %r3, %r2
  297. ld.ub %r4, [%r3] ; get the byte to send
  298. add %r2, 1 ; increment offset
  299. xand %r2, (BufferSize - 1) ; mod buffer size
  300. ld.w [%r0], %r2 ; update offset
  301. xld.w %r5, R8_EFSIF0_TXD ; transmit the byte
  302. ld.b [%r5], %r4
  303. cmp %r1, %r2 ; read == write?
  304. jrne Serial_TxInterrupt_exit ; ...no => more to send
  305. Serial_TxInterrupt_buffer_empty:
  306. xld.w %r0, R8_INT_ESIF01
  307. ld.b %r2, [%r0]
  308. xand %r2, ~ESTX0
  309. ld.b [%r0], %r2 ; disable Tx0 interrupt
  310. Serial_TxInterrupt_exit:
  311. xld.w %r0, R8_EFSIF0_STATUS ; check if pending receive
  312. ld.ub %r4, [%r0]
  313. xand %r4, RDBFx
  314. jrne Serial_RxInterrupt_1 ; if pending receive
  315. popn %r14
  316. reti