int64.asm 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. ;; This file is part of asmc, a bootstrapping OS with minimal seed
  2. ;; Copyright (C) 2018-2019 Giovanni Mascellani <gio@debian.org>
  3. ;; https://gitlab.com/giomasce/asmc
  4. ;; This program is free software: you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. ;; Easy conversions from 32 bits numbers
  15. i64_from_32:
  16. mov ecx, [esp+8]
  17. mov eax, [esp+4]
  18. cdq
  19. mov [ecx], eax
  20. mov [ecx+4], edx
  21. ret
  22. i64_from_u32:
  23. mov ecx, [esp+8]
  24. mov eax, [esp+4]
  25. xor edx, edx
  26. mov [ecx], eax
  27. mov [ecx+4], edx
  28. ret
  29. ;; Bitwise operations are pretty straightforward
  30. i64_not:
  31. mov eax, [esp+4]
  32. not DWORD [eax]
  33. not DWORD [eax+4]
  34. ret
  35. i64_and:
  36. mov eax, [esp+8]
  37. mov ecx, [esp+4]
  38. mov edx, [ecx]
  39. and [eax], edx
  40. mov edx, [ecx+4]
  41. and [eax+4], edx
  42. ret
  43. i64_or:
  44. mov eax, [esp+8]
  45. mov ecx, [esp+4]
  46. mov edx, [ecx]
  47. or [eax], edx
  48. mov edx, [ecx+4]
  49. or [eax+4], edx
  50. ret
  51. i64_xor:
  52. mov eax, [esp+8]
  53. mov ecx, [esp+4]
  54. mov edx, [ecx]
  55. xor [eax], edx
  56. mov edx, [ecx+4]
  57. xor [eax+4], edx
  58. ret
  59. ;; For logical operations, the complicated part is normalizing input
  60. ;; values: this is done by or-ing the two dwords together, then
  61. ;; applying test, sete and movzx on the result; after that,
  62. ;; logical operations can be done bitwise
  63. i64_lnot:
  64. mov eax, [esp+4]
  65. mov ecx, [eax]
  66. or ecx, [eax+4]
  67. mov [eax+4], edx
  68. test ecx, ecx
  69. sete dl
  70. movzx edx, dl
  71. mov [eax], edx
  72. ret
  73. i64_land:
  74. mov ecx, [esp+4]
  75. mov edx, [ecx]
  76. or edx, [ecx+4]
  77. test edx, edx
  78. setne dl
  79. movzx edx, dl
  80. mov eax, [esp+8]
  81. mov ecx, [eax]
  82. or ecx, [eax+4]
  83. test ecx, ecx
  84. setne cl
  85. movzx ecx, cl
  86. and ecx, edx
  87. xor edx, edx
  88. mov [eax], ecx
  89. mov [eax+4], edx
  90. ret
  91. i64_lor:
  92. mov ecx, [esp+4]
  93. mov edx, [ecx]
  94. or edx, [ecx+4]
  95. test edx, edx
  96. setne dl
  97. movzx edx, dl
  98. mov eax, [esp+8]
  99. mov ecx, [eax]
  100. or ecx, [eax+4]
  101. test ecx, ecx
  102. setne cl
  103. movzx ecx, cl
  104. or ecx, edx
  105. xor edx, edx
  106. mov [eax], ecx
  107. mov [eax+4], edx
  108. ret
  109. ;; First we add the lower dwords, then add with carry the upper dwords
  110. i64_add:
  111. mov eax, [esp+4]
  112. mov ecx, [eax]
  113. mov edx, [eax+4]
  114. mov eax, [esp+8]
  115. add [eax], ecx
  116. adc [eax+4], edx
  117. ret
  118. ;; First we subtract the lower dwords, then subtract with borrow the upper dwords
  119. i64_sub:
  120. mov eax, [esp+4]
  121. mov ecx, [eax]
  122. mov edx, [eax+4]
  123. mov eax, [esp+8]
  124. sub [eax], ecx
  125. sbb [eax+4], edx
  126. ret
  127. i64_neg:
  128. mov eax, [esp+4]
  129. neg [eax]
  130. adc DWORD [eax+4], 0
  131. neg [eax+4]
  132. ret
  133. ;; Multiplication is a bit more complicated: first of all, we treat
  134. ;; the operation as unsigned, since we are going to retain only
  135. ;; the lower 64 bits, so signedness does not matter; suppose the
  136. ;; two operands are AB and CD (A is the lower dword of the first
  137. ;; operand, B is the upper dword of the first operand and so
  138. ;; on). Suppose that the unsigned multiplication of A and C gives
  139. ;; the result EF. Then the product of AB and CD is EG, where G =
  140. ;; F + A*D + B*C (in these last two multiplications the upper
  141. ;; dwords of the results are discarded; for this reason, we can
  142. ;; use the two operands form of imul).
  143. i64_mul:
  144. push ebx
  145. push esi
  146. mov ecx, [esp+12]
  147. mov ebx, [esp+16]
  148. mov eax, [ecx]
  149. mul DWORD [ebx]
  150. mov esi, eax
  151. mov eax, [ecx]
  152. mov ecx, [ecx+4]
  153. imul eax, [ebx+4]
  154. imul ecx, [ebx]
  155. add edx, eax
  156. add edx, ecx
  157. mov [ebx], esi
  158. mov [ebx+4], edx
  159. pop esi
  160. pop ebx
  161. ret
  162. ;; Division is not implemented directly in Assembly, because that
  163. ;; would require a lot of obscure code; instead, here we
  164. ;; implement only the unsigned division of a 64 bits number by a
  165. ;; 32 bits number. The rest is implemented in G.
  166. i64_udiv_64_by_32:
  167. mov ecx, [esp+8]
  168. mov edx, [ecx+4]
  169. mov eax, [ecx]
  170. div [esp+4]
  171. xor edx, edx
  172. mov [ecx+4], edx
  173. mov [ecx], eax
  174. ret
  175. ;; Left shifts are done independently on the two dwords, except that
  176. ;; for the upper dword we have to shift in bits from the lower
  177. ;; dword using shld; if the shift count is 32 or more, we also
  178. ;; have to move the upper dword to the lower one, and then reset
  179. ;; the upper one (x86 architecture guarantees that shifts are
  180. ;; done modulo 32 anyway)
  181. i64_shl:
  182. push ebx
  183. mov eax, [esp+12]
  184. mov ecx, [esp+8]
  185. mov ecx, [ecx]
  186. mov ebx, [eax]
  187. mov edx, [eax+4]
  188. shld edx, ebx, cl
  189. shl ebx, cl
  190. cmp cl, 32
  191. jb i64_shl_little
  192. mov edx, ebx
  193. xor ebx, ebx
  194. i64_shl_little:
  195. mov [eax], ebx
  196. mov [eax+4], edx
  197. pop ebx
  198. ret
  199. ;; Logical right shift is similar to left shift; notice that lower
  200. ;; and upper dwords have to be inverted
  201. i64_shr:
  202. push ebx
  203. mov eax, [esp+12]
  204. mov ecx, [esp+8]
  205. mov ecx, [ecx]
  206. mov ebx, [eax]
  207. mov edx, [eax+4]
  208. shrd ebx, edx, cl
  209. shr edx, cl
  210. cmp cl, 32
  211. jb i64_shr_little
  212. mov ebx, edx
  213. xor edx, edx
  214. i64_shr_little:
  215. mov [eax], ebx
  216. mov [eax+4], edx
  217. pop ebx
  218. ret
  219. ;; Arithmetic right shift is similar to logic right shift, but when
  220. ;; the count is 32 or more the upper word has to be filled with
  221. ;; the sign, not with zero
  222. i64_sar:
  223. push ebx
  224. mov eax, [esp+12]
  225. mov ecx, [esp+8]
  226. mov ecx, [ecx]
  227. mov ebx, [eax]
  228. mov edx, [eax+4]
  229. shrd ebx, edx, cl
  230. sar edx, cl
  231. cmp cl, 32
  232. jb i64_shr_little
  233. mov ebx, edx
  234. sar edx, 31
  235. i64_sar_little:
  236. mov [eax], ebx
  237. mov [eax+4], edx
  238. pop ebx
  239. ret
  240. ;; Helpers for comparison functions
  241. i64_ret_true:
  242. xor edx, edx
  243. mov [eax+4], edx
  244. inc edx
  245. mov [eax], edx
  246. ret
  247. i64_ret_false:
  248. xor edx, edx
  249. mov [eax+4], edx
  250. mov [eax], edx
  251. ret
  252. ;; Comparison are many, but straightforward: first compare upper
  253. ;; dwords and, if needed, then compare lower dwords; leave address
  254. ;; of return value in EAX, so that i64_ret_true and i64_ret_false
  255. ;; do the right thing
  256. i64_eq:
  257. mov eax, [esp+8]
  258. mov edx, [esp+4]
  259. mov ecx, [eax+4]
  260. cmp ecx, [edx+4]
  261. jne i64_ret_false
  262. mov ecx, [eax]
  263. cmp ecx, [edx]
  264. jne i64_ret_false
  265. jmp i64_ret_true
  266. i64_neq:
  267. mov eax, [esp+8]
  268. mov edx, [esp+4]
  269. mov ecx, [eax+4]
  270. cmp ecx, [edx+4]
  271. jne i64_ret_true
  272. mov ecx, [eax]
  273. cmp ecx, [edx]
  274. jne i64_ret_true
  275. jmp i64_ret_false
  276. i64_le:
  277. mov eax, [esp+8]
  278. mov edx, [esp+4]
  279. mov ecx, [eax+4]
  280. cmp ecx, [edx+4]
  281. jg i64_ret_false
  282. jl i64_ret_true
  283. mov ecx, [eax]
  284. cmp ecx, [edx]
  285. ja i64_ret_false
  286. jmp i64_ret_true
  287. i64_ule:
  288. mov eax, [esp+8]
  289. mov edx, [esp+4]
  290. mov ecx, [eax+4]
  291. cmp ecx, [edx+4]
  292. ja i64_ret_false
  293. jb i64_ret_true
  294. mov ecx, [eax]
  295. cmp ecx, [edx]
  296. ja i64_ret_false
  297. jmp i64_ret_true
  298. i64_l:
  299. mov eax, [esp+8]
  300. mov edx, [esp+4]
  301. mov ecx, [eax+4]
  302. cmp ecx, [edx+4]
  303. jg i64_ret_false
  304. jl i64_ret_true
  305. mov ecx, [eax]
  306. cmp ecx, [edx]
  307. jae i64_ret_false
  308. jmp i64_ret_true
  309. i64_ul:
  310. mov eax, [esp+8]
  311. mov edx, [esp+4]
  312. mov ecx, [eax+4]
  313. cmp ecx, [edx+4]
  314. ja i64_ret_false
  315. jb i64_ret_true
  316. mov ecx, [eax]
  317. cmp ecx, [edx]
  318. jae i64_ret_false
  319. jmp i64_ret_true
  320. i64_ge:
  321. mov eax, [esp+8]
  322. mov edx, [esp+4]
  323. mov ecx, [eax+4]
  324. cmp ecx, [edx+4]
  325. jg i64_ret_true
  326. jl i64_ret_false
  327. mov ecx, [eax]
  328. cmp ecx, [edx]
  329. jae i64_ret_true
  330. jmp i64_ret_false
  331. i64_uge:
  332. mov eax, [esp+8]
  333. mov edx, [esp+4]
  334. mov ecx, [eax+4]
  335. cmp ecx, [edx+4]
  336. ja i64_ret_true
  337. jb i64_ret_false
  338. mov ecx, [eax]
  339. cmp ecx, [edx]
  340. jae i64_ret_true
  341. jmp i64_ret_false
  342. i64_g:
  343. mov eax, [esp+8]
  344. mov edx, [esp+4]
  345. mov ecx, [eax+4]
  346. cmp ecx, [edx+4]
  347. jg i64_ret_true
  348. jl i64_ret_false
  349. mov ecx, [eax]
  350. cmp ecx, [edx]
  351. ja i64_ret_true
  352. jmp i64_ret_false
  353. i64_ug:
  354. mov eax, [esp+8]
  355. mov edx, [esp+4]
  356. mov ecx, [eax+4]
  357. cmp ecx, [edx+4]
  358. ja i64_ret_true
  359. jb i64_ret_false
  360. mov ecx, [eax]
  361. cmp ecx, [edx]
  362. ja i64_ret_true
  363. jmp i64_ret_false