sointu/vm/compiler/templates/amd64-386/library.asm
5684185+vsariola@users.noreply.github.com f72f29188b feat(vm/compiler): increase native synth delaylines to 128
Closes #155
2025-04-27 21:47:27 +03:00

135 lines
5.9 KiB
NASM

{{template "structs.asm" .}}
struc su_synth
.synth_wrk resb su_synthworkspace.size
.delay_wrks resb su_delayline_wrk.size * 128
.delaytimes resw 768
.sampleoffs resb su_sample_offset.size * 256
.randseed resd 1
.globaltime resd 1
.opcodes resb 32 * 64
.operands resb 32 * 64 * 8
.polyphony resd 1
.numvoices resd 1
endstruc
{{.ExportFunc "su_render" "SynthStateParam" "BufferPtrParam" "SamplesParam" "TimeParam"}}
{{- if .Amd64}}
{{- if eq .OS "windows"}}
{{- .PushRegs "rdi" "NonVolatileRDI" "rsi" "NonVolatileRSI" "rbx" "NonVolatileRBX" "rbp" "NonVolatileRBP" | indent 4}}
mov rsi, r8 ; rsi = &samples
mov rbx, r9 ; rbx = &time
{{- else}} ; SystemV amd64 ABI, linux mac or hopefully something similar
{{- .PushRegs "rbx" "NonVolatileRBX" "rbp" "NonVolatileRBP" | indent 4}}
mov rbx, rcx ; rbx points to time
xchg rsi, rdx ; rdx points to buffer, rsi points to samples
mov rcx, rdi ; rcx = &Synthstate
{{- end}}
{{- else}}
{{- .PushRegs | indent 4 }} ; push registers
mov ecx, [{{.Stack "SynthStateParam"}}] ; ecx = &synthState
mov edx, [{{.Stack "BufferPtrParam"}}] ; edx = &buffer
mov esi, [{{.Stack "SamplesParam"}}] ; esi = &samples
mov ebx, [{{.Stack "TimeParam"}}] ; ebx = &time
{{- end}}
{{.SaveFPUState | indent 4}} ; save the FPU state to stack & reset the FPU
{{.Push .SI "Samples"}}
{{.Push .BX "Time"}}
xor eax, eax ; samplenumber starts at 0
{{.Push .AX "BufSample"}}
mov esi, [{{.SI}}] ; zero extend dereferenced pointer
{{.Push .SI "BufSize"}}
{{.Push .DX "BufPtr"}}
{{.Push .CX "SynthState"}}
lea {{.AX}}, [{{.CX}} + su_synth.sampleoffs]
{{.Push .AX "SampleTable"}}
lea {{.AX}}, [{{.CX}} + su_synth.delaytimes]
{{.Push .AX "DelayTable"}}
mov eax, [{{.CX}} + su_synth.randseed]
{{.Push .AX "RandSeed"}}
mov eax, [{{.CX}} + su_synth.globaltime]
{{.Push .AX "GlobalTick"}}
mov ebx, dword [{{.BX}}] ; zero extend dereferenced pointer
{{.Push .BX "RowLength"}} ; the nominal rowlength should be time_in
xor eax, eax ; rowtick starts at 0
su_render_samples_loop:
push {{.DI}}
fnstsw [{{.SP}}] ; store the FPU status flag to stack top
pop {{.DI}} ; {{.DI}} = FPU status flag
and {{.DI}}, 0011100001000101b ; mask TOP pointer, stack error, zero divide and in{{.VAL}}id operation
test {{.DI}},{{.DI}} ; all the aforementioned bits should be 0!
jne su_render_samples_time_finish ; otherwise, we exit due to error
cmp eax, [{{.Stack "RowLength"}}] ; if rowtick >= maxtime
jge su_render_samples_time_finish ; goto finish
mov ecx, [{{.Stack "BufSize"}}] ; ecx = buffer length in samples
cmp [{{.Stack "BufSample"}}], ecx ; if samples >= maxsamples
jge su_render_samples_time_finish ; goto finish
inc eax ; time++
inc dword [{{.Stack "BufSample"}}] ; samples++
mov {{.CX}}, [{{.Stack "SynthState"}}]
{{.Push .AX "Sample"}}
mov eax, [{{.CX}} + su_synth.polyphony]
{{.Push .AX "PolyphonyBitmask"}}
mov eax, [{{.CX}} + su_synth.numvoices]
{{.Push .AX "VoicesRemain"}}
lea {{.DX}}, [{{.CX}}+ su_synth.synth_wrk]
lea {{.COM}}, [{{.CX}}+ su_synth.opcodes]
lea {{.VAL}}, [{{.CX}}+ su_synth.operands]
lea {{.WRK}}, [{{.DX}} + su_synthworkspace.voices]
lea {{.CX}}, [{{.CX}}+ su_synth.delay_wrks - su_delayline_wrk.filtstate]
{{.Call "su_run_vm"}}
{{.Pop .AX}}
{{.Pop .AX}}
mov {{.DI}}, [{{.Stack "BufPtr"}}] ; edi containts buffer ptr
mov {{.CX}}, [{{.Stack "SynthState"}}]
lea {{.SI}}, [{{.CX}} + su_synth.synth_wrk + su_synthworkspace.left]
movsd ; copy left channel to output buffer
movsd ; copy right channel to output buffer
mov [{{.Stack "BufPtr"}}], {{.DI}} ; save back the updated ptr
lea {{.DI}}, [{{.SI}}-8]
xor eax, eax
stosd ; clear left channel so the VM is ready to write them again
stosd ; clear right channel so the VM is ready to write them again
{{.Pop .AX}}
inc dword [{{.Stack "GlobalTick"}}] ; increment global time, used by delays
jmp su_render_samples_loop
su_render_samples_time_finish:
{{.Pop .CX}}
{{.Pop .BX}}
{{.Pop .DX}}
{{.Pop .CX}}
{{.Pop .CX}}
{{.Pop .CX}}
mov [{{.CX}} + su_synth.randseed], edx
mov [{{.CX}} + su_synth.globaltime], ebx
{{.Pop .BX}}
{{.Pop .BX}}
{{.Pop .DX}}
{{.Pop .BX}}
{{.Pop .SI}}
mov dword [{{.SI}}], edx ; *samples = samples rendered
mov dword [{{.BX}}], eax ; *time = time ticks rendered
mov {{.AX}},{{.DI}} ; {{.DI}} was the masked FPU status flag, {{.AX}} is return {{.VAL}}ue
{{.LoadFPUState | indent 4}} ; load the FPU state from stack
{{- if .Amd64}}
{{- if eq .OS "windows"}}
{{- .PopRegs "rdi" "rsi" "rbx" "rbp" | indent 4}}
{{- else}} ; SystemV amd64 ABI, linux mac or hopefully something similar
{{- .PopRegs "rbx" "rbp" | indent 4}}
{{- end}}
ret
{{- else}}
mov [{{.Stack "eax"}}],eax ; we want to return eax, but popad pops everything, so put eax to stack for popad to pop
{{- .PopRegs | indent 4 }} ; popad
ret 16
{{- end}}
{{template "patch.asm" .}}
;-------------------------------------------------------------------------------
; Constants
;-------------------------------------------------------------------------------
{{.SectData "constants"}}
{{.Constants}}