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 12KB

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