Linux x86_64 implementation of libglitch : https://github.com/erlehmann/libglitch.git
x86-64
nasm
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.

yaglitch.asm 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. ; yaglitch : Yet Another Glitch
  2. ; Copyright (C) 2018 Weber Yann
  3. ;
  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. ; any later version.
  8. ;
  9. ; This program is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ; GNU General Public License for more details.
  13. ;
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;
  17. [bits 64]
  18. %include "sdl.asm"
  19. %include "utils.asm"
  20. %define STACK_SZ 256
  21. %define MAX_FILE_SZ (16 * 17) ; 16 lines of 16 chars + newline chr
  22. %define NL "!"
  23. section .data
  24. op_ptrs:
  25. dq OP.t
  26. dq OP.put
  27. dq OP.drop
  28. dq OP.mul
  29. dq OP.div
  30. dq OP.add
  31. dq OP.sub
  32. dq OP.mod
  33. dq 0 ; syntax error
  34. dq OP.lshift
  35. dq OP.rshift
  36. dq OP.and
  37. dq OP.or
  38. dq OP.xor
  39. dq OP.not
  40. dq OP.dup
  41. dq OP.pick
  42. dq OP.swap
  43. dq OP.lt
  44. dq OP.gt
  45. dq OP.eq
  46. audiospec_wanted:
  47. dd 8000 ; freq
  48. dw AUDIO_U8 ; format
  49. db 1 ; channels
  50. db 0 ; silence
  51. dw 4096 ; samples
  52. dd 0 ; size
  53. dw 0 ; allign
  54. dq audio_cllbck
  55. dq 0 ; userdata
  56. def_str usage, "Usage : "
  57. def_str opts, {" FILE.glitch",0xA}
  58. def_str openerr, {'Error opening file : "', 0xA}
  59. def_str syntax_error, {"Syntax error", 0xA}
  60. def_str bigline_error, {"Line with more than 16 tokens !", 0xA}
  61. def_str nl_error, {"Character \n is not the last one", 0xA}
  62. def_str badop_error, {"Bad OP", 0xA}
  63. ;
  64. ; Old stuff for first oscillator
  65. ;
  66. val: db 0
  67. dir: db 0
  68. dot: db "."
  69. nl: db 0xA
  70. section .bss
  71. ; glitch name (1st line) : len 16 + \0
  72. glitch_name: resb 17
  73. ; program internal repr for stack machine
  74. ; each token uses 2 words : 1st for the callback address 2nd for
  75. ; optional value
  76. glitch_pgm: resq 16 * 16 * 2
  77. ; stack machine ring buffer
  78. stack_buff: resd STACK_SZ
  79. ; top of stack pointer
  80. tosp: resq 1
  81. ; stack machine rgister
  82. t: resd 1
  83. ; audiospec returned from SDL
  84. audiospec_recv: resb 32
  85. ; Event receveid from SDL
  86. ;event: resb 24
  87. section .text
  88. global _start
  89. _start:
  90. ; checking args
  91. mov rcx, [rsp]
  92. cmp rcx, 2
  93. jne exit.badarg
  94. mov rax, 0x2 ; sys_open
  95. mov rdi, [rsp+16] ; argv[1]
  96. xor rsi, rsi ; no flags
  97. xor rdx, rdx ; O_RDONLY
  98. syscall
  99. cmp rax, 0
  100. jl exit.err_open
  101. push rax ; source fd
  102. mov rax, 0xc ; brk
  103. xor rdi, rdi
  104. syscall
  105. push rax ; heap start
  106. mov rdi, rax
  107. add rdi, MAX_FILE_SZ ; new heap end
  108. mov rax, 0xc ; brk
  109. syscall
  110. pop rsi ; heap start
  111. mov r14, rsi
  112. xor rax, rax ; sys_read
  113. mov rdi, [rsp] ; source_fd
  114. mov rdx, MAX_FILE_SZ
  115. syscall
  116. cmp rax, 0
  117. jl exit.err_open
  118. mov r15, rax
  119. mov rax, 0x3 ; sys_close
  120. pop rdi ; source_fd
  121. syscall
  122. mov rbx, r15 ;read size
  123. mov rdi, r14 ; heap start
  124. add rdi, rbx ; heap end
  125. mov r15, rdi
  126. mov rax, 0xc ; brk
  127. syscall ; shrink heap to read size
  128. ; init program space
  129. mov rdi, glitch_pgm
  130. xor rax, rax
  131. stosq
  132. stosq
  133. mov rsi, r14
  134. push rsi
  135. xor r13, r13
  136. xor rbx, rbx
  137. parse:
  138. ; go trhough file , with rsi current ptr, r15 file stop
  139. ; r13 will contain updated lineno and rbx chr in current line
  140. ; rdi store the destination pointer
  141. ; parse glitch name
  142. mov rcx, 16
  143. mov rdi, glitch_name
  144. .name_loop:
  145. inc rbx
  146. lodsb
  147. test al, al ; EOF
  148. jz .no_nl
  149. cmp al, 0xA
  150. je .trailing_nl
  151. cmp al, "!" ; EOL
  152. je .name_end
  153. cmp al, "_"
  154. je .chrname
  155. cmp al, "0"
  156. jl exit.syntax_error
  157. cmp al, "9"
  158. jle .chrname
  159. cmp al, "a"
  160. jl exit.syntax_error
  161. cmp al, "z"
  162. jg exit.syntax_error
  163. .chrname:
  164. stosb
  165. loop .name_loop
  166. jmp exit.bigline
  167. .name_end:
  168. inc r13 ; lineno
  169. xor rbx, rbx
  170. xor al, al
  171. stosb
  172. ; parsing tokens
  173. xor edx, edx ; 32bits numeric token value
  174. xor eax, eax
  175. xor r10, r10 ; numeric token flag (1 mean in numeric token)
  176. xor r11, r11 ; numeric token len
  177. mov rcx, r15
  178. sub rcx, r14
  179. mov rdi, glitch_pgm
  180. .parse_loop:
  181. inc rbx
  182. lodsb
  183. test al, al
  184. jz .no_nl
  185. cmp al, 0xA
  186. je .trailing_nl
  187. cmp al, "!" ; EOL
  188. je .next_line
  189. cmp al, "." ; token separator
  190. je .next_token
  191. cmp al, "0"
  192. jl exit.syntax_error
  193. cmp al, "9"
  194. jle .dec_token
  195. cmp al, "A"
  196. jl exit.syntax_error
  197. cmp al, "F"
  198. jle .hex_token
  199. jmp .op_match ; allowing loop near jump
  200. .end_op:
  201. stosq
  202. xor rax, rax
  203. stosq
  204. loop .parse_loop
  205. .hex_token:
  206. sub al, "A" - 10
  207. jmp .numeric_token
  208. .dec_token:
  209. sub al, "0"
  210. .numeric_token:
  211. cmp r11, 8
  212. je exit.syntax_error ; Numeric constant OF
  213. inc r11
  214. mov r10, 1
  215. shl edx, 4
  216. add edx, eax
  217. loop .parse_loop
  218. .next_token:
  219. test r10, r10 ; check for numeric constant
  220. jnz .add_numeric
  221. loop .parse_loop
  222. .next_line:
  223. inc r13
  224. xor rbx, rbx
  225. .loop_parse_loop:
  226. loop .parse_loop
  227. .add_numeric:
  228. mov rax, OP.numeric
  229. stosq
  230. xor rax, rax
  231. xor r11, r11
  232. xor r10, r10
  233. xchg rax, rdx
  234. shl rax, 32
  235. stosq
  236. xor rax, rax
  237. jmp .loop_parse_loop
  238. .trailing_nl:
  239. ; check that NL is the last chr, else syntax error
  240. cmp rsi, r15
  241. jne exit.nl_not_last
  242. jmp .parse_end
  243. .op_match:
  244. ; allow loop .parse_loop near jump
  245. cmp al, "a"
  246. jl exit.syntax_error
  247. cmp al, "u"
  248. jg exit.syntax_error
  249. ; OP shortand matching
  250. ; checking for previous numeric token to write
  251. test r10, r10
  252. jz .match_op
  253. push rax
  254. ; add previous numeric token
  255. mov rax, OP.numeric
  256. stosq
  257. xor rax, rax
  258. xor r11, r11 ; numeric token length raz
  259. xor r10, r10 ; numeric token flag raz
  260. xchg rax, rdx
  261. shl rax, 32 ; shl to allow reading as dword ?
  262. stosq
  263. pop rax
  264. .match_op:
  265. sub al, "a"
  266. shl rax, 3 ; mul by 8 (size of ptr)
  267. add rax, op_ptrs
  268. mov rax, [rax]
  269. test rax, rax
  270. jz exit.bad_op
  271. jmp .end_op
  272. .no_nl: ; TODO : print warning
  273. ; no NL at EOF
  274. .parse_end:
  275. ; clean heap
  276. mov rax, 0xc
  277. pop rdi
  278. syscall
  279. ; print glitch name
  280. mov rax, "Playing "
  281. push rax
  282. mov rax, 1
  283. mov rdi, 1
  284. mov rsi, rsp
  285. mov rdx, 8
  286. syscall
  287. pop rax
  288. mov rdi, glitch_name
  289. call strlen
  290. mov rdx, rax
  291. mov rax, 1
  292. mov rdi, 1
  293. mov rsi, glitch_name
  294. syscall
  295. mov rax, `\n`
  296. push rax
  297. mov rax, 1
  298. mov rdi, 1
  299. mov rsi, rsp
  300. mov rdx, 1
  301. syscall
  302. pop rax
  303. ; init stack machine runtime
  304. stack_init:
  305. mov rcx, STACK_SZ
  306. mov rdi, stack_buff
  307. xor rax, rax
  308. mov [t], eax
  309. .loop_buff_init:
  310. stosd
  311. loop .loop_buff_init
  312. mov al, 7 * 4
  313. mov [tosp], al
  314. sdl_init:
  315. mov rdi, 0x0000FFFF
  316. call SDL_Init
  317. mov rdi, audiospec_wanted
  318. mov rsi, audiospec_recv
  319. call SDL_OpenAudio
  320. ;mov rdi, 256
  321. ;mov rsi, 255
  322. ;mov rdx, 32
  323. ;;mov rcx, SDL_SWSURFACE
  324. ;xor rcx, rcx
  325. ;call SDL_SetVideoMode
  326. audio_start:
  327. ;start audio
  328. xor rdi, rdi
  329. call SDL_PauseAudio
  330. ;mov rdi, 15000
  331. ;call SDL_Delay
  332. xor rdi, rdi
  333. call SDL_WaitEvent
  334. exit:
  335. call SDL_Quit
  336. xor rdi, rdi
  337. mov rax, 0x3c
  338. syscall
  339. .err_open:
  340. mov rax, 1
  341. mov rdi, 2
  342. mov rsi, openerr
  343. mov rdx, openerr_len - 1
  344. syscall
  345. mov rdi, [rsp+16]
  346. push rdi
  347. call strlen
  348. mov rdx, rax
  349. mov rax, 1
  350. mov rdi, 2
  351. pop rsi
  352. syscall
  353. mov rax, 1
  354. mov rdi, 2
  355. mov rsi, openerr + openerr_len - 2
  356. mov rdx, 2
  357. syscall
  358. .badarg:
  359. mov rax, 1
  360. mov rdi, 2
  361. mov rsi, usage
  362. mov rdx, usage_len
  363. syscall
  364. mov rdi, [rsp+8]
  365. call strlen
  366. mov rdx, rax
  367. mov rax, 1
  368. mov rdi, 2
  369. mov rsi, [rsp+8]
  370. syscall
  371. mov rax, 1
  372. mov rdi, 2
  373. mov rsi, opts
  374. mov rdx, opts_len
  375. syscall
  376. mov rdi, 1
  377. .exit_err: ; with rdi error code
  378. mov rax, 0x3c ; exit
  379. syscall
  380. ; expect : r13 lineno, rbx chr num in line
  381. ; TODO: real error message
  382. .nl_not_last:
  383. mov rsi, nl_error
  384. mov rsi, nl_error_len
  385. push qword 3
  386. jmp exit.parse_error
  387. .syntax_error:
  388. mov rsi, syntax_error
  389. mov rdx, syntax_error_len
  390. push qword 2
  391. jmp exit.parse_error
  392. .bigline:
  393. mov rsi, bigline_error
  394. mov rdx, bigline_error_len
  395. push qword 2
  396. jmp exit.parse_error
  397. .bad_op:
  398. mov rsi, badop_error
  399. mov rdx, badop_error_len
  400. push qword 2
  401. jmp exit.parse_error
  402. .parse_error:
  403. ; print error lineno & chrno
  404. push rsi ; source ptr
  405. push rdx
  406. push rbx ; chrno in line
  407. sub r14, rsi ; chr count
  408. push 14
  409. mov rdi, "chr:0x"
  410. mov rsi, 6
  411. call short_err
  412. pop rdi ; chr count
  413. mov rsi, 2
  414. call print_hnum
  415. mov rdi, ",line:0x"
  416. mov rsi, 8
  417. call short_err
  418. mov rdi, r13
  419. mov rsi, 2
  420. call print_hnum
  421. mov rdi, ",col:0x"
  422. mov rsi, 7
  423. call short_err
  424. pop rdi
  425. mov rsi, 2
  426. call print_hnum
  427. mov rdi, ` :\t`
  428. mov rsi, 3
  429. call short_err
  430. pop rdx
  431. pop rsi
  432. mov rax, 1
  433. mov rdi, 2
  434. syscall
  435. pop rdi
  436. jmp exit.exit_err
  437. short_err:
  438. ; rdi is the message (less than 8 chr)
  439. ; rsi is message len
  440. push rdi
  441. mov rdx, rsi
  442. mov rsi, rsp
  443. mov rax, 1
  444. mov rdi, 1
  445. syscall
  446. pop rdi
  447. ret
  448. strlen:
  449. ; rdi containing str pointer
  450. ; rax will contain strlen and rdi is unchanged
  451. mov rsi, rdi
  452. xor rdx, rdx
  453. pushf
  454. cld
  455. .loop:
  456. inc rdx
  457. lodsb
  458. mov cl, al
  459. test al, al
  460. jnz .loop
  461. dec rdx
  462. mov rax, rdx
  463. popf
  464. ret
  465. print_hnum:
  466. ; rdi : number to print
  467. ; rsi : output fd
  468. pushf
  469. mov rax, rdi
  470. xor rcx, rcx
  471. push rcx ; using stack as buffer
  472. std
  473. lea rdi, [rsp + 8]
  474. .loop:
  475. test rax, rax
  476. jz .endloop
  477. inc rcx
  478. inc rcx
  479. push rax
  480. and al, 0x0F
  481. call .al2digit
  482. stosb
  483. mov rax, [rsp]
  484. shr al, 4
  485. call .al2digit
  486. stosb
  487. pop rax
  488. shr rax, 8
  489. jmp .loop
  490. .endloop:
  491. mov rax, 1
  492. xchg rdi, rsi
  493. inc rsi
  494. ;mov rdi, rsi
  495. ;mov rsi, rsp
  496. mov rdx, rcx
  497. syscall
  498. pop rax
  499. popf
  500. ret
  501. .al2digit:
  502. cmp al, 9
  503. jg .hex
  504. add al, "0"
  505. ret
  506. .hex:
  507. add al, "A" - 10
  508. ret
  509. audio_cllbck:
  510. ; rdi -> *userdata
  511. ; rsi -> *stream
  512. ; rdx -> stream_len
  513. mov rcx, rdx
  514. mov rdi, rsi
  515. .loop:
  516. push rcx
  517. push rdi
  518. call run_glitch
  519. pop rdi
  520. stosb
  521. pop rcx
  522. inc dword [t]
  523. loop .loop
  524. ret
  525. run_glitch:
  526. ; Run the glitch_pgm
  527. ; return TOSP value in eax
  528. mov rsi, glitch_pgm
  529. .loop:
  530. lodsq
  531. test rax, rax
  532. jz .end_glitch
  533. push rax
  534. lodsq
  535. mov rdi, rax
  536. pop rax
  537. push rsi
  538. call rax
  539. pop rsi
  540. jmp .loop
  541. .end_glitch:
  542. xor rbx, rbx
  543. mov bl, [tosp]
  544. lea rdi, [stack_buff + rbx]
  545. mov eax, [rdi]
  546. ; DEBUG
  547. ;push rax
  548. ;xor rdi, rdi
  549. ;mov rdi, rax
  550. ;mov rsi, 1
  551. ;call print_hnum
  552. ;mov rax, " "
  553. ;push rax
  554. ;mov rax, 1
  555. ;mov rdi, 1
  556. ;mov rsi, rsp
  557. ;mov rdx, 1
  558. ;syscall
  559. ;pop rax
  560. ;pop rax
  561. ; /DEBUG
  562. ret
  563. OP:
  564. .numeric:
  565. ; rdi contain the number
  566. shr rdi, 32
  567. ._push:
  568. ; push rdi (edi) on stack_buff
  569. mov eax, edi
  570. xor rbx, rbx
  571. mov bl, [tosp]
  572. add bl, 4
  573. cmp bl, 8 * 4
  574. jl .go_push
  575. mov bl, 0
  576. .go_push:
  577. mov [tosp], bl
  578. lea rdi, [stack_buff+rbx]
  579. stosd
  580. ret
  581. .drop: ; drop just calls pop
  582. ._pop:
  583. ; pop eax from stack_buff
  584. xor rbx, rbx
  585. mov bl, [tosp]
  586. lea rsi, [stack_buff+rbx]
  587. xor rax, rax
  588. lodsd
  589. test bl, bl
  590. jz .pop_no_dec
  591. sub bl, 4
  592. jmp .pop_end
  593. .pop_no_dec:
  594. mov bl, 7 * 4
  595. .pop_end:
  596. mov [tosp], bl
  597. ret
  598. .t: ; push t on the stack
  599. mov edi, [t]
  600. call ._push
  601. ret
  602. .put:
  603. pushf
  604. cld
  605. xor rbx, rbx
  606. xor rax, rax
  607. mov bl, [tosp]
  608. lea rsi, [stack_buff+rbx]
  609. lodsd
  610. and eax, 0xFF
  611. inc eax
  612. mov edx, eax
  613. lodsd
  614. neg rdx
  615. lea rdi, [stack_buff + rdx]
  616. stosq
  617. call OP._pop
  618. popf
  619. ret
  620. .mul:
  621. call .prep_2arg
  622. mul ebx
  623. mov edi, eax
  624. call OP._push
  625. ret
  626. .div:
  627. call .prep_2arg
  628. test ebx, ebx
  629. jz .nodiv
  630. xor rdx, rdx
  631. div ebx
  632. jmp .divend
  633. .nodiv:
  634. xor eax, eax
  635. .divend:
  636. mov edi, eax
  637. call OP._push
  638. ret
  639. .add:
  640. call .prep_2arg
  641. add eax, ebx
  642. mov edi, eax
  643. call OP._push
  644. ret
  645. .sub:
  646. call .prep_2arg
  647. sub eax, ebx
  648. mov edi, eax
  649. call OP._push
  650. ret
  651. .mod:
  652. call .prep_2arg
  653. test rbx, rbx
  654. jz .nomod
  655. xor edx, edx
  656. div ebx
  657. jmp .endmod
  658. .nomod:
  659. xor edx, edx
  660. .endmod:
  661. mov edi, edx
  662. call OP._push
  663. ret
  664. .lshift:
  665. call OP._pop
  666. push rax
  667. call OP._pop
  668. pop rcx
  669. .lshift_loop:
  670. shl eax, 1
  671. loop .lshift_loop
  672. mov edi, eax
  673. call OP._push
  674. ret
  675. .rshift:
  676. call OP._pop
  677. push rax
  678. call OP._pop
  679. pop rcx
  680. .rshift_loop:
  681. shr eax, 1
  682. loop .rshift_loop
  683. mov edi, eax
  684. call OP._push
  685. ret
  686. .and:
  687. call .prep_2arg
  688. and eax, ebx
  689. mov edi, eax
  690. call OP._push
  691. ret
  692. .or:
  693. call .prep_2arg
  694. or eax, ebx
  695. mov edi, eax
  696. call OP._push
  697. ret
  698. .xor:
  699. call .prep_2arg
  700. xor eax, ebx
  701. mov edi, eax
  702. call OP._push
  703. ret
  704. .not:
  705. call OP._pop
  706. neg eax
  707. mov edi, eax
  708. call OP._push
  709. ret
  710. .dup:
  711. call OP._pop
  712. push rax
  713. mov edi, eax
  714. call OP._push
  715. pop rdi
  716. call OP._push
  717. ret
  718. .pick:
  719. call OP._pop
  720. inc eax
  721. and eax, 0xFF
  722. neg eax
  723. lea rsi, [stack_buff+eax]
  724. lodsd
  725. push rax
  726. call OP._pop
  727. pop rdi
  728. call OP._push
  729. ret
  730. .swap:
  731. call OP._pop
  732. push rax
  733. call OP._pop
  734. xchg rax, [rsp]
  735. mov edi, eax
  736. call OP._push
  737. pop rdi
  738. call OP._push
  739. ret
  740. .lt:
  741. call .prep_2arg
  742. xor rdi, rdi
  743. cmp eax, ebx
  744. jge .lt_false
  745. not rdi
  746. .lt_false:
  747. call OP._push
  748. ret
  749. .gt:
  750. call .prep_2arg
  751. xor rdi, rdi
  752. cmp eax, ebx
  753. jle .gt_false
  754. not rdi
  755. .gt_false:
  756. call OP._push
  757. ret
  758. .eq:
  759. call .prep_2arg
  760. xor rdi, rdi
  761. cmp eax, ebx
  762. jne .eq_false
  763. not rdi
  764. .eq_false:
  765. call OP._push
  766. ret
  767. .prep_2arg:
  768. ; utils that pop both arguments V1 in eax, V2 in ebx
  769. call OP._pop
  770. push rax
  771. call OP._pop
  772. pop rbx
  773. ret