1
0

queens.asm 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. ;
  2. ; queens app — by.avolver'11
  3. ; distributed under BEERWARE LICENSE
  4. ;
  5. ; @todo
  6. ; - Реализовать многопоточность...
  7. ; Fork работает, однако общее адресное пространство вносит долю хаоса в картину.
  8. ; Для начала нужно решить проблему выделения памяти и давать каждому потоку свой массив.
  9. ; Затем сохранить в регистре каждого потока адрес на его массив и параметры. Вероятно это будет r15. Счётчик же положить в память каждого потока.
  10. ; - Динамеческое выделение памяти. sys_brk не хочет работать. (или -1 в rcx ничего не значит?)
  11. ; Файл: /usr/src/linux/arch/x86/kernel/entry_64.S, строка: 422
  12. ; - Использовать нулевую ячейку массива ферзей, дабы немного сократить количество инструкций.
  13. ; - Сделать проверку на разрешённый диапазон N [5..256] и введённые в параметры буквы.
  14. ; - Вывод в JSON
  15. ; - Добавить функцию DumpDesk
  16. ; - Вывод времени работы в мс.
  17. ; - Порт под Windows. Используем команды препроцессора: IS_LINUX = 1; if IS_LINUX ... end if
  18. ; - Отобразить примерное время завершения.
  19. format ELF64 executable at 0000000100000000h
  20. segment readable executable
  21. appStart:
  22. entry $
  23. pop rax ; В стеке лежат параметры командной строки. По восемь байт на адрес параметра. Первый — количество;
  24. cmp rax, 1
  25. jbe fShowUsage
  26. pop rax ; Второй — название программы;
  27. pop rsi ; Третий — первый аргумент;
  28. call toDec
  29. cmp rax, 0
  30. je fShowUsage
  31. mov [iTotalLayers], rax
  32. mov r9, rax
  33. mov rbx, rax
  34. mov rax, 8
  35. mul rbx
  36. ;mov rcx, rax
  37. ;mov rax, 12 ; Запрос на расширение памяти. Syscall 12 — sys_brk. В rdi — адрес на желаемую границу сегмента данных.
  38. ;xor ebx, ebx
  39. ;syscall
  40. ;add rax, rcx
  41. ;mov rdi, rax
  42. ;xor rdi, rdi
  43. ;syscall
  44. mov r8, 1 ; Текущий уровень
  45. mov r15, 0 ; Счётчик совпадений
  46. mainLoop:
  47. lea rsi, [aQueens]
  48. mov rbx, r8
  49. mov rax, 8
  50. mul rbx
  51. add rsi, rax
  52. mov rax, [rsi] ; Получаем значение ферзя для текущего уровня
  53. cmp rax, r9
  54. jbe DoCheckPaths ; Если это значение больше максимального уровня
  55. lea rsi, [aQueens]
  56. add rsi, 8
  57. mov rax, [rsi]
  58. mov rbx, r9
  59. inc rbx
  60. cmp rax, rbx
  61. jne DoCont ; и если позиция ферзя первого уровня не вылезла за грани максимального положения
  62. jmp DoCheckPaths
  63. DoCont:
  64. lea rsi, [aQueens]
  65. mov rbx, r8
  66. mov rax, 8
  67. mul rbx
  68. add rsi, rax
  69. mov rax, 1
  70. mov [rsi], rax ; aQueens[iLevel] = 1 : Сбрасываем позицию текущего уровня в начальное положение
  71. dec r8 ; iLevel-- : Переходим на уровень ниже.
  72. sub rsi, 8
  73. mov rax, [rsi]
  74. inc rax
  75. mov [rsi], rax ; aQueens[iLevel]++ : На предыдущем уровне сдвигаемся направо
  76. jmp mainLoop
  77. DoCheckPaths:
  78. call CheckPaths
  79. cmp rdx, 1 ; Проверяем, свободны ли поля.
  80. je IncLevel
  81. inc r8
  82. cmp r8, r9
  83. jbe mainLoop
  84. lea rsi, [aQueens] ; Может это конец?
  85. add rsi, 8
  86. mov rax, [rsi]
  87. cmp rax, r9
  88. ja breakLoop ; Да? Брякаем цикл.
  89. inc r15 ; iCount++ : Ура, мы нашли решение!
  90. call fDumpSolution ; Выводим решение
  91. dec r8 ; iLevel--
  92. lea rsi, [aQueens]
  93. mov rbx, r8
  94. mov rax, 8
  95. mul rbx
  96. add rsi, rax
  97. mov rax, [rsi]
  98. inc rax
  99. mov [rsi], rax ; aQueens[iLevel]++;
  100. jmp mainLoop
  101. IncLevel:
  102. lea rsi, [aQueens]
  103. mov rbx, r8
  104. mov rax, 8
  105. mul rbx
  106. add rsi, rax
  107. mov rax, [rsi]
  108. inc rax
  109. mov [rsi], rax
  110. jmp mainLoop
  111. breakLoop:
  112. lea rsi, [sStatisticArea]
  113. mov rax, r15
  114. call fromDec
  115. mov rdx, sStatisticArea - sStatistics
  116. add rdx, rbx
  117. add rsi, rbx
  118. mov rcx, 0x0A
  119. mov [rsi], rcx
  120. inc rdx
  121. lea rsi, [sStatistics]
  122. mov edi, 1
  123. mov eax, 1
  124. syscall
  125. xor rax, rax
  126. xor edi, edi ; Выходим из себя. Syscall 60 — sys_exit
  127. mov eax, 60
  128. syscall
  129. ; Функция для проверки свободных путей.
  130. ; Возвращает: rdx = 1, если на пути встречается ферзь; либо rdx = 0, если дорога пуста.
  131. ; r10 — iTargetLayer; r11 — iVectorCenter; r12 — iVectorLeft; r13 — iVectorRight; r14 — iEnemyX
  132. CheckPaths:
  133. cmp r8, 1
  134. jne ChPathsP1
  135. mov rdx, 0
  136. ret
  137. ChPathsP1:
  138. mov r10, r8 ; iTargetLayer = iLevel
  139. lea rsi, [aQueens]
  140. mov rbx, r8
  141. mov rax, 8
  142. mul rbx
  143. add rsi, rax
  144. mov r11, [rsi] ; iVectorCenter, iVectorLeft, iVectorRight = aQueens[iLevel]
  145. mov r12, r11
  146. mov r13, r11
  147. ChPathsLoop:
  148. dec r10
  149. cmp r10, 0
  150. mov rdx, 0
  151. jbe ChPathsEnd
  152. lea rsi, [aQueens]
  153. mov rbx, r10
  154. mov rax, 8
  155. mul rbx
  156. add rsi, rax
  157. mov r14, [rsi] ; iEnemyX = aQueens[iTargetLevel]
  158. cmp r11, r14 ; Если iVectorCenter = iEnemyX, то сохраняем в rdx:1 и вываливаемся.
  159. jne ChPathNoCenter
  160. mov rdx, 1
  161. ret
  162. ChPathNoCenter:
  163. cmp r12, 0
  164. jbe ChPathNoLeft
  165. dec r12 ; Уменьшаем iVectorLeft
  166. cmp r12, r14 ; Если iVectorLeft = iEnemyX, то сохраняем в rdx:1 и возвращаемся.
  167. jne ChPathNoLeft
  168. mov rdx, 1
  169. ret
  170. ChPathNoLeft:
  171. cmp r13, r9
  172. ja ChPathsLoop
  173. inc r13 ; Увеличиваем iVectorRight
  174. cmp r13, r14 ; Если iVectorRight = iEnemyX, то сохраняем в rdx:1 и выпадаем.
  175. jne ChPathsLoop
  176. mov rdx, 1
  177. ret
  178. ChPathsEnd:
  179. ret
  180. ; Функция вывода решения.
  181. fDumpSolution:
  182. mov r11, 1
  183. mov r12, 1
  184. lea rdx, [aQueens]
  185. lea rsi, [tBackBuffer]
  186. mov rax, r15
  187. call fromDec
  188. add rsi, rbx
  189. add r12, rbx
  190. mov rax, 0x03A
  191. mov [rsi], rax
  192. inc rsi
  193. inc r12
  194. mov rax, 0x020
  195. mov [rsi], rax
  196. inc rsi
  197. inc r12
  198. mov rcx, r9
  199. fDSLoop:
  200. mov rax, r11
  201. call fromDec
  202. add rsi, rbx
  203. add r12, rbx
  204. mov rax, 0x03A
  205. mov [rsi], rax
  206. inc rsi
  207. inc r12
  208. add rdx, 8
  209. mov rax, [rdx]
  210. call fromDec
  211. inc r11
  212. add rsi, rbx
  213. add r12, rbx
  214. mov rax, 0x02C
  215. mov [rsi], rax
  216. inc rsi
  217. inc r12
  218. mov rax, 0x020
  219. mov [rsi], rax
  220. inc rsi
  221. inc r12
  222. loop fDSLoop
  223. dec rsi
  224. dec rsi
  225. dec r12
  226. dec r12
  227. mov rdx, 0x0A
  228. mov [rsi], rdx
  229. mov rdx, r12
  230. lea rsi, [tBackBuffer]
  231. mov edi, 1
  232. mov eax, 1
  233. syscall
  234. ret
  235. ; Отображение сообщения об использовании.
  236. fShowUsage:
  237. mov edx, iUsageSize
  238. lea rsi, [sUsage]
  239. mov edi, 1
  240. mov eax, 1 ; Выводим сообщение об использовании. Syscall 1 — sys_write: rsi — адрес на строку, edx — длинна, edi — stdout.
  241. syscall
  242. xor edi, edi ; Выходим из программы. Syscall 60 — sys_exit: edi — код возврата.
  243. mov eax, 60
  244. syscall
  245. fAllocationError:
  246. mov edx, iAllProSize
  247. lea rsi, [sAllocationProblem]
  248. mov edi, 1
  249. mov eax, 1
  250. syscall
  251. xor edi, edi
  252. mov eax, 60
  253. syscall
  254. ; Функция для перевода ASCII строки в число.
  255. ; rsi - адрес на строку
  256. ; rax - число результата
  257. ; Смотрим первую букву, если она — цифра — прибавляем её к rax. Если следующий байт не 0x0 — умножаем rax на десять и прибавляем следующую цифру.
  258. toDec:
  259. xor rax, rax
  260. mov cl, [rsi]
  261. toDecEnt:
  262. sub cl, 48
  263. jc toDecInc
  264. cmp cl, 10
  265. jae toDecInc
  266. add rax, rcx
  267. toDecInc:
  268. inc rsi
  269. mov cl, [rsi]
  270. cmp cl, 0
  271. je toDecEnd
  272. mov rbx, 10
  273. mul rbx
  274. jmp toDecEnt
  275. toDecEnd:
  276. ret
  277. ; Функция для обратного перевода числа в ASCII строку.
  278. ; rsi - адрес на временную строку
  279. ; rax - число, которое необходимо преобразовать
  280. ; rbx - длина строки
  281. ; Делим исходное число на десять — остаток записываем в ASCII-цифру.
  282. ; Если исходное число становится меньше десяти, то добавляем его как ASCII-последнюю цифру в поток.
  283. fromDec:
  284. push rcx
  285. push rdx
  286. push rdi
  287. xor rdi, rdi
  288. mov rcx, 10
  289. push rsi
  290. push rsi
  291. lea rsi, [sFromDecTemp]
  292. add rsi, 10
  293. fromDecEnt:
  294. inc rdi
  295. cmp rax, 10 ; Если rax < 10, то прыгнуть в конец
  296. jb fromDecEnd
  297. xor rdx, rdx ; Очищаем регистр для частного
  298. div rcx ; rcx = rax / rcx => rdx
  299. or dl, 0x30
  300. mov [rsi], dl
  301. dec rsi
  302. jmp fromDecEnt
  303. fromDecEnd:
  304. or al, 0x30
  305. mov [rsi], al
  306. mov rbx, rdi ; Копируем строку на первый байт необходимого адреса.
  307. mov rcx, rdi
  308. pop rdi
  309. cld
  310. rep movsb
  311. inc rdi
  312. mov ah, 0 ; Добавляя в конец нулевой стоп-символ
  313. mov [rdi], ah
  314. pop rsi
  315. pop rdi
  316. pop rdx
  317. pop rcx
  318. ret
  319. appEnd:
  320. segment readable writeable
  321. dataStart:
  322. iTotalLayers dq ?
  323. sTempPlaceForInt db 11 dup('b')
  324. sFromDecTemp db 11 dup('a')
  325. sUsage db 'Queens application', 0x0A
  326. db 'Finds a solution for the "eight queens puzzle"', 0x0A, 0x0A
  327. db 'Usage: queens <depth level>', 0x0A
  328. iUsageSize = $ - sUsage
  329. sStatistics db 'Number of solutions: '
  330. sStatisticArea db 11 dup(0)
  331. sAllocationProblem db 'Memory allocation error, sorry...', 0x0A
  332. iAllProSize = $ - sAllocationProblem
  333. aQueens:
  334. times 256 dq 1 ; Массив, собственно, ферзей
  335. tBackBuffer:
  336. times 3 db ? ; Дельта размера, дабы забить остатки бинарника до 4096 байт.
  337. times (4096 - (appEnd - appStart) - (tBackBuffer - dataStart) - 176) / 8 db '6dreams ' ; Great_&_be-e-e-eg backbuffer. (%