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

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