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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  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, "F"
  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, 8
  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. xchg rax, rdx
  244. shl rax, 32 ; shl to allow reading as dword ?
  245. stosq
  246. pop rax
  247. .match_op:
  248. sub al, "a"
  249. shl rax, 3 ; mul by 8 (size of ptr)
  250. add rax, op_ptrs
  251. mov rax, [rax]
  252. test rax, rax
  253. jz exit.bad_op
  254. jmp .end_op
  255. .no_nl: ; TODO : print warning
  256. ; no NL at EOF
  257. .parse_end:
  258. ; clean heap
  259. mov rax, 0xc
  260. pop rdi
  261. syscall
  262. ; print glitch name
  263. mov rax, "Playing "
  264. push rax
  265. mov rax, 1
  266. mov rdi, 1
  267. mov rsi, rsp
  268. mov rdx, 8
  269. syscall
  270. pop rax
  271. mov rdi, glitch_name
  272. call strlen
  273. mov rdx, rax
  274. mov rax, 1
  275. mov rdi, 1
  276. mov rsi, glitch_name
  277. syscall
  278. mov rax, `\n`
  279. push rax
  280. mov rax, 1
  281. mov rdi, 1
  282. mov rsi, rsp
  283. mov rdx, 1
  284. syscall
  285. pop rax
  286. ; init stack machine runtime
  287. stack_init:
  288. mov rcx, STACK_SZ
  289. mov rdi, stack_buff
  290. xor rax, rax
  291. mov [t], eax
  292. .loop_buff_init:
  293. stosd
  294. loop .loop_buff_init
  295. mov al, 7 * 4
  296. mov [tosp], al
  297. sdl_init:
  298. mov rdi, 0x0000FFFF
  299. call SDL_Init
  300. mov rdi, audiospec_wanted
  301. mov rsi, audiospec_recv
  302. call SDL_OpenAudio
  303. ;mov rdi, 256
  304. ;mov rsi, 255
  305. ;mov rdx, 32
  306. ;;mov rcx, SDL_SWSURFACE
  307. ;xor rcx, rcx
  308. ;call SDL_SetVideoMode
  309. audio_start:
  310. ;start audio
  311. xor rdi, rdi
  312. call SDL_PauseAudio
  313. mov rdi, 2000
  314. call SDL_Delay
  315. exit:
  316. call SDL_Quit
  317. xor rdi, rdi
  318. mov rax, 0x3c
  319. syscall
  320. .err_open:
  321. mov rax, 1
  322. mov rdi, 2
  323. mov rsi, openerr
  324. mov rdx, openerr_len - 1
  325. syscall
  326. mov rdi, [rsp+16]
  327. push rdi
  328. call strlen
  329. mov rdx, rax
  330. mov rax, 1
  331. mov rdi, 2
  332. pop rsi
  333. syscall
  334. mov rax, 1
  335. mov rdi, 2
  336. mov rsi, openerr + openerr_len - 2
  337. mov rdx, 2
  338. syscall
  339. .badarg:
  340. mov rax, 1
  341. mov rdi, 2
  342. mov rsi, usage
  343. mov rdx, usage_len
  344. syscall
  345. mov rdi, [rsp+8]
  346. call strlen
  347. mov rdx, rax
  348. mov rax, 1
  349. mov rdi, 2
  350. mov rsi, [rsp+8]
  351. syscall
  352. mov rax, 1
  353. mov rdi, 2
  354. mov rsi, opts
  355. mov rdx, opts_len
  356. syscall
  357. mov rdi, 1
  358. .exit_err: ; with rdi error code
  359. mov rax, 0x3c ; exit
  360. syscall
  361. ; expect : r13 lineno, rbx chr num in line
  362. ; TODO: real error message
  363. .nl_not_last:
  364. mov rsi, nl_error
  365. mov rsi, nl_error_len
  366. push qword 3
  367. jmp exit.parse_error
  368. .syntax_error:
  369. mov rsi, syntax_error
  370. mov rdx, syntax_error_len
  371. push qword 2
  372. jmp exit.parse_error
  373. .bigline:
  374. mov rsi, bigline_error
  375. mov rdx, bigline_error_len
  376. push qword 2
  377. jmp exit.parse_error
  378. .bad_op:
  379. mov rsi, badop_error
  380. mov rdx, badop_error_len
  381. push qword 2
  382. jmp exit.parse_error
  383. .parse_error:
  384. ; print error lineno & chrno
  385. push rsi ; source ptr
  386. push rdx
  387. push rbx ; chrno in line
  388. sub r14, rsi ; chr count
  389. push 14
  390. mov rdi, "chr:0x"
  391. mov rsi, 6
  392. call short_err
  393. pop rdi ; chr count
  394. mov rsi, 2
  395. call print_hnum
  396. mov rdi, ",line:0x"
  397. mov rsi, 8
  398. call short_err
  399. mov rdi, r13
  400. mov rsi, 2
  401. call print_hnum
  402. mov rdi, ",col:0x"
  403. mov rsi, 7
  404. call short_err
  405. pop rdi
  406. mov rsi, 2
  407. call print_hnum
  408. mov rdi, ` :\t`
  409. mov rsi, 3
  410. call short_err
  411. pop rdx
  412. pop rsi
  413. mov rax, 1
  414. mov rdi, 2
  415. syscall
  416. pop rdi
  417. jmp exit.exit_err
  418. short_err:
  419. ; rdi is the message (less than 8 chr)
  420. ; rsi is message len
  421. push rdi
  422. mov rdx, rsi
  423. mov rsi, rsp
  424. mov rax, 1
  425. mov rdi, 1
  426. syscall
  427. pop rdi
  428. ret
  429. strlen:
  430. ; rdi containing str pointer
  431. ; rax will contain strlen and rdi is unchanged
  432. mov rsi, rdi
  433. xor rdx, rdx
  434. pushf
  435. cld
  436. .loop:
  437. inc rdx
  438. lodsb
  439. mov cl, al
  440. test al, al
  441. jnz .loop
  442. dec rdx
  443. mov rax, rdx
  444. popf
  445. ret
  446. print_hnum:
  447. ; rdi : number to print
  448. ; rsi : output fd
  449. pushf
  450. mov rax, rdi
  451. xor rcx, rcx
  452. push rcx ; using stack as buffer
  453. std
  454. lea rdi, [rsp + 8]
  455. .loop:
  456. test rax, rax
  457. jz .endloop
  458. inc rcx
  459. inc rcx
  460. push rax
  461. and al, 0x0F
  462. call .al2digit
  463. stosb
  464. mov rax, [rsp]
  465. shr al, 4
  466. call .al2digit
  467. stosb
  468. pop rax
  469. shr rax, 8
  470. jmp .loop
  471. .endloop:
  472. mov rax, 1
  473. xchg rdi, rsi
  474. inc rsi
  475. ;mov rdi, rsi
  476. ;mov rsi, rsp
  477. mov rdx, rcx
  478. syscall
  479. pop rax
  480. popf
  481. ret
  482. .al2digit:
  483. cmp al, 9
  484. jg .hex
  485. add al, "0"
  486. ret
  487. .hex:
  488. add al, "A" - 10
  489. ret
  490. audio_cllbck:
  491. ; rdi -> *userdata
  492. ; rsi -> *stream
  493. ; rdx -> stream_len
  494. mov rcx, rdx
  495. mov rdi, rsi
  496. .loop:
  497. push rcx
  498. push rdi
  499. call run_glitch
  500. pop rdi
  501. stosb
  502. pop rcx
  503. inc dword [t]
  504. loop .loop
  505. ret
  506. run_glitch:
  507. ; Run the glitch_pgm
  508. ; return TOSP value in eax
  509. mov rsi, glitch_pgm
  510. .loop:
  511. lodsq
  512. test rax, rax
  513. jz .end_glitch
  514. push rax
  515. lodsq
  516. mov rdi, rax
  517. pop rax
  518. push rsi
  519. call rax
  520. pop rsi
  521. jmp .loop
  522. .end_glitch:
  523. xor rbx, rbx
  524. mov bl, [tosp]
  525. lea rdi, [stack_buff + rbx]
  526. mov eax, [rdi]
  527. ; DEBUG
  528. ;push rax
  529. ;xor rdi, rdi
  530. ;mov rdi, rax
  531. ;mov rsi, 1
  532. ;call print_hnum
  533. ;mov rax, " "
  534. ;push rax
  535. ;mov rax, 1
  536. ;mov rdi, 1
  537. ;mov rsi, rsp
  538. ;mov rdx, 1
  539. ;syscall
  540. ;pop rax
  541. ;pop rax
  542. ; /DEBUG
  543. ret
  544. OP:
  545. .numeric:
  546. ; rdi contain the number
  547. shr rdi, 32
  548. ._push:
  549. ; push rdi (edi) on stack_buff
  550. mov eax, edi
  551. xor rbx, rbx
  552. mov bl, [tosp]
  553. add bl, 4
  554. cmp bl, 8 * 4
  555. jl .go_push
  556. mov bl, 0
  557. .go_push:
  558. mov [tosp], bl
  559. lea rdi, [stack_buff+rbx]
  560. stosd
  561. ret
  562. .drop: ; drop just calls pop
  563. ._pop:
  564. ; pop eax from stack_buff
  565. xor rbx, rbx
  566. mov bl, [tosp]
  567. lea rsi, [stack_buff+rbx]
  568. xor rax, rax
  569. lodsd
  570. test bl, bl
  571. jz .pop_no_dec
  572. sub bl, 4
  573. jmp .pop_end
  574. .pop_no_dec:
  575. mov bl, 7 * 4
  576. .pop_end:
  577. mov [tosp], bl
  578. ret
  579. .t: ; push t on the stack
  580. mov edi, [t]
  581. call ._push
  582. ret
  583. .put:
  584. pushf
  585. cld
  586. xor rbx, rbx
  587. xor rax, rax
  588. mov bl, [tosp]
  589. lea rsi, [stack_buff+rbx]
  590. lodsd
  591. and eax, 0xFF
  592. inc eax
  593. mov edx, eax
  594. lodsd
  595. neg rdx
  596. lea rdi, [stack_buff + rdx]
  597. stosq
  598. call OP._pop
  599. popf
  600. ret
  601. .mul:
  602. call .prep_2arg
  603. mul ebx
  604. mov edi, eax
  605. call OP._push
  606. ret
  607. .div:
  608. call .prep_2arg
  609. test ebx, ebx
  610. jz .nodiv
  611. xor edx, edx
  612. div ebx
  613. jmp .divend
  614. .nodiv:
  615. xor eax, eax
  616. .divend:
  617. mov edi, eax
  618. call OP._push
  619. ret
  620. .add:
  621. call .prep_2arg
  622. add eax, ebx
  623. mov edi, eax
  624. call OP._push
  625. ret
  626. .sub:
  627. call .prep_2arg
  628. sub eax, ebx
  629. mov edi, eax
  630. call OP._push
  631. ret
  632. .mod:
  633. call .prep_2arg
  634. test ebx, ebx
  635. jz .nomod
  636. xor edx, edx
  637. div ebx
  638. jmp .endmod
  639. .nomod:
  640. xor edx, edx
  641. .endmod:
  642. mov edi, edx
  643. call OP._push
  644. ret
  645. .lshift:
  646. call OP._pop
  647. push rax
  648. call OP._pop
  649. pop rcx
  650. .lshift_loop:
  651. shl eax, 1
  652. loop .lshift_loop
  653. mov edi, eax
  654. call OP._push
  655. ret
  656. .rshift:
  657. call OP._pop
  658. push rax
  659. call OP._pop
  660. pop rcx
  661. .rshift_loop:
  662. shr eax, 1
  663. loop .rshift_loop
  664. mov edi, eax
  665. call OP._push
  666. ret
  667. .and:
  668. call .prep_2arg
  669. and eax, ebx
  670. mov edi, eax
  671. call OP._push
  672. ret
  673. .or:
  674. call .prep_2arg
  675. or eax, ebx
  676. mov edi, eax
  677. call OP._push
  678. ret
  679. .xor:
  680. call .prep_2arg
  681. xor eax, ebx
  682. mov edi, eax
  683. call OP._push
  684. ret
  685. .not:
  686. call OP._pop
  687. neg eax
  688. mov edi, eax
  689. call OP._push
  690. ret
  691. .dup:
  692. call OP._pop
  693. push rax
  694. mov edi, eax
  695. call OP._push
  696. pop rdi
  697. call OP._push
  698. ret
  699. .pick:
  700. call OP._pop
  701. inc eax
  702. and eax, 0xFF
  703. neg eax
  704. lea rsi, [stack_buff+eax]
  705. lodsd
  706. push rax
  707. call OP._pop
  708. pop rdi
  709. call OP._push
  710. ret
  711. .swap:
  712. call OP._pop
  713. push rax
  714. call OP._pop
  715. xchg rax, [rsp]
  716. mov edi, eax
  717. call OP._push
  718. pop rdi
  719. call OP._push
  720. ret
  721. .lt:
  722. call .prep_2arg
  723. xor rdi, rdi
  724. cmp eax, ebx
  725. jge .lt_false
  726. not rdi
  727. .lt_false:
  728. call OP._push
  729. ret
  730. .gt:
  731. call .prep_2arg
  732. xor rdi, rdi
  733. cmp eax, ebx
  734. jle .gt_false
  735. not rdi
  736. .gt_false:
  737. call OP._push
  738. ret
  739. .eq:
  740. call .prep_2arg
  741. xor rdi, rdi
  742. cmp eax, ebx
  743. jne .eq_false
  744. not rdi
  745. .eq_false:
  746. call OP._push
  747. ret
  748. .prep_2arg:
  749. ; utils that pop both arguments V1 in eax, V2 in ebx
  750. call OP._pop
  751. push rax
  752. call OP._pop
  753. pop rbx
  754. ret