Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
5.3KB

  1. ; core
  2. ;
  3. ; Routines used by pretty much all parts. You will want to include it first
  4. ; in your glue file.
  5. ; *** CONSTS ***
  6. .equ ASCII_BS 0x08
  7. .equ ASCII_CR 0x0d
  8. .equ ASCII_LF 0x0a
  9. .equ ASCII_DEL 0x7f
  10. ; *** DATA ***
  11. ; Useful data to point to, when a pointer is needed.
  12. P_NULL: .db 0
  13. ; *** REGISTER FIDDLING ***
  14. ; add the value of A into DE
  15. addDE:
  16. push af
  17. add a, e
  18. jr nc, .end ; no carry? skip inc
  19. inc d
  20. .end:
  21. ld e, a
  22. pop af
  23. noop: ; piggy backing on the first "ret" we have
  24. ret
  25. ; copy (HL) into DE, then exchange the two, utilising the optimised HL instructions.
  26. ; ld must be done little endian, so least significant byte first.
  27. intoHL:
  28. push de
  29. ld e, (hl)
  30. inc hl
  31. ld d, (hl)
  32. ex de, hl
  33. pop de
  34. ret
  35. intoDE:
  36. ex de, hl
  37. call intoHL
  38. ex de, hl ; de preserved by intoHL, so no push/pop needed
  39. ret
  40. intoIX:
  41. push ix
  42. ex (sp), hl ;swap hl with ix, on the stack
  43. call intoHL
  44. ex (sp), hl ;restore hl from stack
  45. pop ix
  46. ret
  47. ; add the value of A into HL
  48. ; affects carry flag according to the 16-bit addition, Z, S and P untouched.
  49. addHL:
  50. push de
  51. ld d, 0
  52. ld e, a
  53. add hl, de
  54. pop de
  55. ret
  56. ; subtract the value of A from HL
  57. ; affects flags according to the 16-bit subtraction.
  58. subHL:
  59. push de
  60. ld d, 0
  61. ld e, a
  62. or a ;reset carry flag
  63. sbc hl, de ;There is no 'sub hl, de', so we must use sbc
  64. pop de
  65. ret
  66. ; Compare HL with DE and sets Z and C in the same way as a regular cp X where
  67. ; HL is A and DE is X.
  68. cpHLDE:
  69. push hl
  70. or a ;reset carry flag
  71. sbc hl, de ;There is no 'sub hl, de', so we must use sbc
  72. pop hl
  73. ret
  74. ; Write the contents of HL in (DE)
  75. ; de and hl are preserved, so no pushing/popping necessary
  76. writeHLinDE:
  77. ex de, hl
  78. ld (hl), e
  79. inc hl
  80. ld (hl), d
  81. dec hl
  82. ex de, hl
  83. ret
  84. ; Call the method (IX) is a pointer to. In other words, call intoIX before
  85. ; callIX
  86. callIXI:
  87. push ix
  88. call intoIX
  89. call callIX
  90. pop ix
  91. ret
  92. ; jump to the location pointed to by IX. This allows us to call IX instead of
  93. ; just jumping it. We use IX because we seldom use this for arguments.
  94. callIX:
  95. jp (ix)
  96. callIY:
  97. jp (iy)
  98. ; Ensures that Z is unset (more complicated than it sounds...)
  99. ; There are often better inline alternatives, either replacing rets with
  100. ; appropriate jmps, or if an 8 bit register is known to not be 0, an inc
  101. ; then a dec. If a is nonzero, 'or a' is optimal.
  102. unsetZ:
  103. or a ;if a nonzero, Z reset
  104. ret nz
  105. cp 1 ;if a is zero, Z reset
  106. ret
  107. ; *** STRINGS ***
  108. ; Fill B bytes at (HL) with A
  109. fill:
  110. push bc
  111. push hl
  112. .loop:
  113. ld (hl), a
  114. inc hl
  115. djnz .loop
  116. pop hl
  117. pop bc
  118. ret
  119. ; Increase HL until the memory address it points to is equal to A for a maximum
  120. ; of 0xff bytes. Returns the new HL value as well as the number of bytes
  121. ; iterated in A.
  122. ; If a null char is encountered before we find A, processing is stopped in the
  123. ; same way as if we found our char (so, we look for A *or* 0)
  124. ; Set Z if the character is found. Unsets it if not
  125. findchar:
  126. push bc
  127. ld c, a ; let's use C as our cp target
  128. ld a, 0xff
  129. ld b, a
  130. .loop: ld a, (hl)
  131. cp c
  132. jr z, .match
  133. or a ; cp 0
  134. jr z, .nomatch
  135. inc hl
  136. djnz .loop
  137. .nomatch:
  138. call unsetZ
  139. jr .end
  140. .match:
  141. ; We ran 0xff-B loops. That's the result that goes in A.
  142. ld a, 0xff
  143. sub b
  144. cp a ; ensure Z
  145. .end:
  146. pop bc
  147. ret
  148. ; Format the lower nibble of A into a hex char and stores the result in A.
  149. fmtHex:
  150. ; The idea here is that there's 7 characters between '9' and 'A'
  151. ; in the ASCII table, and so we add 7 if the digit is >9.
  152. ; daa is designed for using Binary Coded Decimal format, where each
  153. ; nibble represents a single base 10 digit. If a nibble has a value >9,
  154. ; it adds 6 to that nibble, carrying to the next nibble and bringing the
  155. ; value back between 0-9. This gives us 6 of that 7 we needed to add, so
  156. ; then we just condtionally set the carry and add that carry, along with
  157. ; a number that maps 0 to '0'. We also need the upper nibble to be a
  158. ; set value, and have the N, C and H flags clear.
  159. or 0xf0
  160. daa ; now a =0x50 + the original value + 0x06 if >= 0xfa
  161. add a, 0xa0 ; cause a carry for the values that were >=0x0a
  162. adc a, 0x40
  163. ret
  164. ; Formats value in A into a string hex pair. Stores it in the memory location
  165. ; that HL points to. Does *not* add a null char at the end.
  166. fmtHexPair:
  167. push af
  168. ; let's start with the rightmost char
  169. inc hl
  170. call fmtHex
  171. ld (hl), a
  172. ; and now with the leftmost
  173. dec hl
  174. pop af
  175. push af
  176. rra \ rra \ rra \ rra
  177. call fmtHex
  178. ld (hl), a
  179. pop af
  180. ret
  181. ; Compares strings pointed to by HL and DE up to A count of characters. If
  182. ; equal, Z is set. If not equal, Z is reset.
  183. strncmp:
  184. push bc
  185. push hl
  186. push de
  187. ld b, a
  188. .loop:
  189. ld a, (de)
  190. cp (hl)
  191. jr nz, .end ; not equal? break early. NZ is carried out
  192. ; to the called
  193. cp 0 ; If our chars are null, stop the cmp
  194. jr z, .end ; The positive result will be carried to the
  195. ; caller
  196. inc hl
  197. inc de
  198. djnz .loop
  199. ; We went through all chars with success, but our current Z flag is
  200. ; unset because of the cp 0. Let's do a dummy CP to set the Z flag.
  201. cp a
  202. .end:
  203. pop de
  204. pop hl
  205. pop bc
  206. ; Because we don't call anything else than CP that modify the Z flag,
  207. ; our Z value will be that of the last cp (reset if we broke the loop
  208. ; early, set otherwise)
  209. ret
  210. ; Transforms the character in A, if it's in the a-z range, into its upcase
  211. ; version.
  212. upcase:
  213. cp 'a'
  214. ret c ; A < 'a'. nothing to do
  215. cp 'z'+1
  216. ret nc ; A >= 'z'+1. nothing to do
  217. ; 'a' - 'A' == 0x20
  218. sub 0x20
  219. ret