123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838 |
- ; yaglitch : Yet Another Glitch
- ; Copyright (C) 2018 Weber Yann
- ;
- ; This program is free software; you can redistribute it and/or modify
- ; it under the terms of the GNU General Public License as published by
- ; the Free Software Foundation; either version 3 of the License, or
- ; any later version.
- ;
- ; This program is distributed in the hope that it will be useful,
- ; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ; GNU General Public License for more details.
- ;
- ; You should have received a copy of the GNU General Public License
- ; along with this program. If not, see <http://www.gnu.org/licenses/>.
- ;
-
- [bits 64]
-
- %include "sdl.asm"
- %include "utils.asm"
-
- %define STACK_SZ 256
- %define MAX_FILE_SZ (16 * 17) ; 16 lines of 16 chars + newline chr
- %define NL "!"
-
- section .data
-
- op_ptrs:
- dq OP.t
- dq OP.put
- dq OP.drop
- dq OP.mul
- dq OP.div
- dq OP.add
- dq OP.sub
- dq OP.mod
- dq 0 ; syntax error
- dq OP.lshift
- dq OP.rshift
- dq OP.and
- dq OP.or
- dq OP.xor
- dq OP.not
- dq OP.dup
- dq OP.pick
- dq OP.swap
- dq OP.lt
- dq OP.gt
- dq OP.eq
-
-
- audiospec_wanted:
- dd 8000 ; freq
- dw AUDIO_U8 ; format
- db 1 ; channels
- db 0 ; silence
- dw 4096 ; samples
- dd 0 ; size
- dw 0 ; allign
- dq audio_cllbck
- dq 0 ; userdata
-
-
- def_str usage, "Usage : "
- def_str opts, {" FILE.glitch",0xA}
- def_str openerr, {'Error opening file : "', 0xA}
- def_str syntax_error, {"Syntax error", 0xA}
- def_str bigline_error, {"Line with more than 16 tokens !", 0xA}
- def_str nl_error, {"Character \n is not the last one", 0xA}
- def_str badop_error, {"Bad OP", 0xA}
-
- ;
- ; Old stuff for first oscillator
- ;
- val: db 0
- dir: db 0
-
- dot: db "."
- nl: db 0xA
-
-
- section .bss
-
- ; glitch name (1st line) : len 16 + \0
- glitch_name: resb 17
- ; program internal repr for stack machine
- ; each token uses 2 words : 1st for the callback address 2nd for
- ; optional value
- glitch_pgm: resq 16 * 16 * 2
- ; stack machine ring buffer
- stack_buff: resd STACK_SZ
- ; top of stack pointer
- tosp: resq 1
- ; stack machine rgister
- t: resd 1
- ; audiospec returned from SDL
- audiospec_recv: resb 32
- ; Event receveid from SDL
- ;event: resb 24
-
- section .text
- global _start
- _start:
-
- ; checking args
- mov rcx, [rsp]
- cmp rcx, 2
- jne exit.badarg
-
- mov rax, 0x2 ; sys_open
- mov rdi, [rsp+16] ; argv[1]
- xor rsi, rsi ; no flags
- xor rdx, rdx ; O_RDONLY
- syscall
- cmp rax, 0
- jl exit.err_open
- push rax ; source fd
-
- mov rax, 0xc ; brk
- xor rdi, rdi
- syscall
- push rax ; heap start
-
- mov rdi, rax
- add rdi, MAX_FILE_SZ ; new heap end
- mov rax, 0xc ; brk
- syscall
-
- pop rsi ; heap start
- mov r14, rsi
- xor rax, rax ; sys_read
- mov rdi, [rsp] ; source_fd
- mov rdx, MAX_FILE_SZ
- syscall
- cmp rax, 0
- jl exit.err_open
- mov r15, rax
-
- mov rax, 0x3 ; sys_close
- pop rdi ; source_fd
- syscall
-
- mov rbx, r15 ;read size
- mov rdi, r14 ; heap start
- add rdi, rbx ; heap end
- mov r15, rdi
- mov rax, 0xc ; brk
- syscall ; shrink heap to read size
-
- ; init program space
- mov rdi, glitch_pgm
- xor rax, rax
- stosq
- stosq
-
- mov rsi, r14
- push rsi
- xor r13, r13
- xor rbx, rbx
- parse:
- ; go trhough file , with rsi current ptr, r15 file stop
- ; r13 will contain updated lineno and rbx chr in current line
- ; rdi store the destination pointer
- ; parse glitch name
- mov rcx, 16
- mov rdi, glitch_name
- .name_loop:
- inc rbx
- lodsb
- test al, al ; EOF
- jz .no_nl
- cmp al, 0xA
- je .trailing_nl
- cmp al, "!" ; EOL
- je .name_end
- cmp al, "_"
- je .chrname
- cmp al, "0"
- jl exit.syntax_error
- cmp al, "9"
- jle .chrname
- cmp al, "a"
- jl exit.syntax_error
- cmp al, "z"
- jg exit.syntax_error
- .chrname:
- stosb
- loop .name_loop
- jmp exit.bigline
- .name_end:
- inc r13 ; lineno
- xor rbx, rbx
- xor al, al
- stosb
-
- ; parsing tokens
- xor edx, edx ; 32bits numeric token value
- xor eax, eax
- xor r10, r10 ; numeric token flag (1 mean in numeric token)
- xor r11, r11 ; numeric token len
- mov rcx, r15
- sub rcx, r14
- mov rdi, glitch_pgm
- .parse_loop:
- inc rbx
- lodsb
- test al, al
- jz .no_nl
- cmp al, 0xA
- je .trailing_nl
- cmp al, "!" ; EOL
- je .next_line
- cmp al, "." ; token separator
- je .next_token
- cmp al, "0"
- jl exit.syntax_error
- cmp al, "9"
- jle .dec_token
- cmp al, "A"
- jl exit.syntax_error
- cmp al, "F"
- jle .hex_token
- jmp .op_match ; allowing loop near jump
- .end_op:
- stosq
- xor rax, rax
- stosq
- loop .parse_loop
- .hex_token:
- sub al, "A" - 10
- jmp .numeric_token
- .dec_token:
- sub al, "0"
- .numeric_token:
- cmp r11, 8
- je exit.syntax_error ; Numeric constant OF
- inc r11
- mov r10, 1
- shl edx, 4
- add edx, eax
- loop .parse_loop
- .next_token:
- test r10, r10 ; check for numeric constant
- jnz .add_numeric
- loop .parse_loop
- .next_line:
- inc r13
- xor rbx, rbx
- .loop_parse_loop:
- loop .parse_loop
- .add_numeric:
- mov rax, OP.numeric
- stosq
- xor rax, rax
- xor r11, r11
- xor r10, r10
- xchg rax, rdx
- shl rax, 32
- stosq
- xor rax, rax
- jmp .loop_parse_loop
- .trailing_nl:
- ; check that NL is the last chr, else syntax error
- cmp rsi, r15
- jne exit.nl_not_last
- jmp .parse_end
- .op_match:
- ; allow loop .parse_loop near jump
- cmp al, "a"
- jl exit.syntax_error
- cmp al, "u"
- jg exit.syntax_error
- ; OP shortand matching
- ; checking for previous numeric token to write
- test r10, r10
- jz .match_op
- push rax
- ; add previous numeric token
- mov rax, OP.numeric
- stosq
- xor rax, rax
- xor r11, r11 ; numeric token length raz
- xor r10, r10 ; numeric token flag raz
- xchg rax, rdx
- shl rax, 32 ; shl to allow reading as dword ?
- stosq
- pop rax
- .match_op:
- sub al, "a"
- shl rax, 3 ; mul by 8 (size of ptr)
- add rax, op_ptrs
- mov rax, [rax]
- test rax, rax
- jz exit.bad_op
- jmp .end_op
-
- .no_nl: ; TODO : print warning
- ; no NL at EOF
-
- .parse_end:
-
- ; clean heap
- mov rax, 0xc
- pop rdi
- syscall
-
- ; print glitch name
- mov rax, "Playing "
- push rax
- mov rax, 1
- mov rdi, 1
- mov rsi, rsp
- mov rdx, 8
- syscall
- pop rax
-
- mov rdi, glitch_name
- call strlen
- mov rdx, rax
- mov rax, 1
- mov rdi, 1
- mov rsi, glitch_name
- syscall
-
- mov rax, `\n`
- push rax
- mov rax, 1
- mov rdi, 1
- mov rsi, rsp
- mov rdx, 1
- syscall
- pop rax
-
- ; init stack machine runtime
- stack_init:
-
- mov rcx, STACK_SZ
- mov rdi, stack_buff
- xor rax, rax
- mov [t], eax
- .loop_buff_init:
- stosd
- loop .loop_buff_init
- mov al, 7 * 4
- mov [tosp], al
-
- sdl_init:
- mov rdi, 0x0000FFFF
- call SDL_Init
-
- mov rdi, audiospec_wanted
- mov rsi, audiospec_recv
- call SDL_OpenAudio
-
- ;mov rdi, 256
- ;mov rsi, 255
- ;mov rdx, 32
- ;;mov rcx, SDL_SWSURFACE
- ;xor rcx, rcx
- ;call SDL_SetVideoMode
-
- audio_start:
- ;start audio
- xor rdi, rdi
- call SDL_PauseAudio
-
- ;mov rdi, 15000
- ;call SDL_Delay
-
- xor rdi, rdi
- call SDL_WaitEvent
-
-
- exit:
- call SDL_Quit
-
- xor rdi, rdi
- mov rax, 0x3c
- syscall
-
-
- .err_open:
- mov rax, 1
- mov rdi, 2
- mov rsi, openerr
- mov rdx, openerr_len - 1
- syscall
-
- mov rdi, [rsp+16]
- push rdi
- call strlen
-
- mov rdx, rax
- mov rax, 1
- mov rdi, 2
- pop rsi
- syscall
-
- mov rax, 1
- mov rdi, 2
- mov rsi, openerr + openerr_len - 2
- mov rdx, 2
- syscall
- .badarg:
- mov rax, 1
- mov rdi, 2
- mov rsi, usage
- mov rdx, usage_len
- syscall
-
- mov rdi, [rsp+8]
- call strlen
- mov rdx, rax
-
- mov rax, 1
- mov rdi, 2
- mov rsi, [rsp+8]
- syscall
-
- mov rax, 1
- mov rdi, 2
- mov rsi, opts
- mov rdx, opts_len
- syscall
- mov rdi, 1
- .exit_err: ; with rdi error code
- mov rax, 0x3c ; exit
- syscall
-
- ; expect : r13 lineno, rbx chr num in line
- ; TODO: real error message
- .nl_not_last:
- mov rsi, nl_error
- mov rsi, nl_error_len
- push qword 3
- jmp exit.parse_error
- .syntax_error:
- mov rsi, syntax_error
- mov rdx, syntax_error_len
- push qword 2
- jmp exit.parse_error
- .bigline:
- mov rsi, bigline_error
- mov rdx, bigline_error_len
- push qword 2
- jmp exit.parse_error
- .bad_op:
- mov rsi, badop_error
- mov rdx, badop_error_len
- push qword 2
- jmp exit.parse_error
- .parse_error:
- ; print error lineno & chrno
- push rsi ; source ptr
- push rdx
- push rbx ; chrno in line
- sub r14, rsi ; chr count
- push 14
- mov rdi, "chr:0x"
- mov rsi, 6
- call short_err
- pop rdi ; chr count
- mov rsi, 2
- call print_hnum
- mov rdi, ",line:0x"
- mov rsi, 8
- call short_err
- mov rdi, r13
- mov rsi, 2
- call print_hnum
- mov rdi, ",col:0x"
- mov rsi, 7
- call short_err
- pop rdi
- mov rsi, 2
- call print_hnum
- mov rdi, ` :\t`
- mov rsi, 3
- call short_err
- pop rdx
- pop rsi
- mov rax, 1
- mov rdi, 2
- syscall
- pop rdi
- jmp exit.exit_err
-
- short_err:
- ; rdi is the message (less than 8 chr)
- ; rsi is message len
- push rdi
- mov rdx, rsi
- mov rsi, rsp
- mov rax, 1
- mov rdi, 1
- syscall
- pop rdi
- ret
-
- strlen:
- ; rdi containing str pointer
- ; rax will contain strlen and rdi is unchanged
- mov rsi, rdi
- xor rdx, rdx
- pushf
- cld
- .loop:
- inc rdx
- lodsb
- mov cl, al
- test al, al
- jnz .loop
- dec rdx
- mov rax, rdx
- popf
- ret
-
- print_hnum:
- ; rdi : number to print
- ; rsi : output fd
- pushf
- mov rax, rdi
- xor rcx, rcx
- push rcx ; using stack as buffer
- std
- lea rdi, [rsp + 8]
- .loop:
- test rax, rax
- jz .endloop
- inc rcx
- inc rcx
- push rax
- and al, 0x0F
- call .al2digit
- stosb
- mov rax, [rsp]
- shr al, 4
- call .al2digit
- stosb
- pop rax
- shr rax, 8
- jmp .loop
- .endloop:
- mov rax, 1
- xchg rdi, rsi
- inc rsi
- ;mov rdi, rsi
- ;mov rsi, rsp
- mov rdx, rcx
- syscall
- pop rax
- popf
- ret
- .al2digit:
- cmp al, 9
- jg .hex
- add al, "0"
- ret
- .hex:
- add al, "A" - 10
- ret
-
- audio_cllbck:
- ; rdi -> *userdata
- ; rsi -> *stream
- ; rdx -> stream_len
- mov rcx, rdx
- mov rdi, rsi
- .loop:
- push rcx
- push rdi
- call run_glitch
- pop rdi
- stosb
- pop rcx
- inc dword [t]
- loop .loop
- ret
-
- run_glitch:
- ; Run the glitch_pgm
- ; return TOSP value in eax
-
- mov rsi, glitch_pgm
- .loop:
- lodsq
- test rax, rax
- jz .end_glitch
- push rax
- lodsq
- mov rdi, rax
- pop rax
- push rsi
- call rax
- pop rsi
- jmp .loop
- .end_glitch:
- xor rbx, rbx
- mov bl, [tosp]
- lea rdi, [stack_buff + rbx]
- mov eax, [rdi]
- ; DEBUG
- ;push rax
- ;xor rdi, rdi
- ;mov rdi, rax
- ;mov rsi, 1
- ;call print_hnum
- ;mov rax, " "
- ;push rax
- ;mov rax, 1
- ;mov rdi, 1
- ;mov rsi, rsp
- ;mov rdx, 1
- ;syscall
- ;pop rax
- ;pop rax
- ; /DEBUG
- ret
-
- OP:
- .numeric:
- ; rdi contain the number
- shr rdi, 32
- ._push:
- ; push rdi (edi) on stack_buff
- mov eax, edi
- xor rbx, rbx
- mov bl, [tosp]
- add bl, 4
- cmp bl, 8 * 4
- jl .go_push
- mov bl, 0
- .go_push:
- mov [tosp], bl
- lea rdi, [stack_buff+rbx]
- stosd
- ret
-
- .drop: ; drop just calls pop
- ._pop:
- ; pop eax from stack_buff
- xor rbx, rbx
- mov bl, [tosp]
- lea rsi, [stack_buff+rbx]
- xor rax, rax
- lodsd
- test bl, bl
- jz .pop_no_dec
- sub bl, 4
- jmp .pop_end
- .pop_no_dec:
- mov bl, 7 * 4
- .pop_end:
- mov [tosp], bl
- ret
-
-
- .t: ; push t on the stack
- mov edi, [t]
- call ._push
- ret
-
- .put:
- pushf
- cld
- xor rbx, rbx
- xor rax, rax
- mov bl, [tosp]
- lea rsi, [stack_buff+rbx]
- lodsd
- and eax, 0xFF
- inc eax
- mov edx, eax
- lodsd
- neg rdx
- lea rdi, [stack_buff + rdx]
- stosq
- call OP._pop
- popf
- ret
- .mul:
- call .prep_2arg
- mul ebx
- mov edi, eax
- call OP._push
- ret
- .div:
- call .prep_2arg
- test ebx, ebx
- jz .nodiv
- xor rdx, rdx
- div ebx
- jmp .divend
- .nodiv:
- xor eax, eax
- .divend:
- mov edi, eax
- call OP._push
- ret
- .add:
- call .prep_2arg
- add eax, ebx
- mov edi, eax
- call OP._push
- ret
- .sub:
- call .prep_2arg
- sub eax, ebx
- mov edi, eax
- call OP._push
- ret
- .mod:
- call .prep_2arg
- test rbx, rbx
- jz .nomod
- xor edx, edx
- div ebx
- jmp .endmod
- .nomod:
- xor edx, edx
- .endmod:
- mov edi, edx
- call OP._push
- ret
- .lshift:
- call OP._pop
- push rax
- call OP._pop
- pop rcx
- .lshift_loop:
- shl eax, 1
- loop .lshift_loop
- mov edi, eax
- call OP._push
- ret
- .rshift:
- call OP._pop
- push rax
- call OP._pop
- pop rcx
- .rshift_loop:
- shr eax, 1
- loop .rshift_loop
- mov edi, eax
- call OP._push
- ret
- .and:
- call .prep_2arg
- and eax, ebx
- mov edi, eax
- call OP._push
- ret
- .or:
- call .prep_2arg
- or eax, ebx
- mov edi, eax
- call OP._push
- ret
- .xor:
- call .prep_2arg
- xor eax, ebx
- mov edi, eax
- call OP._push
- ret
- .not:
- call OP._pop
- neg eax
- mov edi, eax
- call OP._push
- ret
- .dup:
- call OP._pop
- push rax
- mov edi, eax
- call OP._push
- pop rdi
- call OP._push
- ret
- .pick:
- call OP._pop
- inc eax
- and eax, 0xFF
- neg eax
- lea rsi, [stack_buff+eax]
- lodsd
- push rax
- call OP._pop
- pop rdi
- call OP._push
- ret
-
-
- .swap:
- call OP._pop
- push rax
- call OP._pop
- xchg rax, [rsp]
- mov edi, eax
- call OP._push
- pop rdi
- call OP._push
- ret
- .lt:
- call .prep_2arg
- xor rdi, rdi
- cmp eax, ebx
- jge .lt_false
- not rdi
- .lt_false:
- call OP._push
- ret
- .gt:
- call .prep_2arg
- xor rdi, rdi
- cmp eax, ebx
- jle .gt_false
- not rdi
- .gt_false:
- call OP._push
- ret
- .eq:
- call .prep_2arg
- xor rdi, rdi
- cmp eax, ebx
- jne .eq_false
- not rdi
- .eq_false:
- call OP._push
- ret
-
- .prep_2arg:
- ; utils that pop both arguments V1 in eax, V2 in ebx
- call OP._pop
- push rax
- call OP._pop
- pop rbx
- ret
|