gates_of_skeldal/libs/pcspeak.asm
2025-01-25 13:08:41 +01:00

304 lines
12 KiB
NASM

.model small
.386P
DGROUP group _DATA
;real procedura pro prehravani na PCSPEAKERu.
;Tato procedura musi obsahovat vsechny deklarace, ktere vyuziva Protect Mode
;Tyto deklarace jsou pristupne i s PM. Opacne to vsak nelze
rl_pm_bufseg equ (offset pm_bufseg-rm_proc)
rl_bufseg equ (offset bufseg-rm_proc)
rl_bufpos equ (offset bufpos-rm_proc)
rl_port equ (offset port-rm_proc)
rl_xlattab equ (offset xlattab-rm_proc)
_TEXT16 segment byte public 'CODE' use16
assume cs:_TEXT16
assume ds:_TEXT16
rm_proc: ;Zde zacina obsluha INT 8 z realu
cli
push ds ;Program nevstupuje do dalsich int kvuly zdrzovani
push ax ;Nejprve se ulozi vsechny ohrozene registry
push bx
push dx
push si
mov ax,cs:[rl_bufseg]
mov ds,ax ;ds segment ukazuje na buffer
mov dx,cs:[rl_port] ;nacti adresu portu
lea bx,cs:[rl_xlattab];nacti zacatek
mov si,cs:[rl_bufpos];nacti si - adresu prehravaneho bytu
lods ds:[si] ;precti byte
mov cs:[rl_bufpos],si;uloz si
add bl,al
adc bh,0
mov al,cs:[bx]
out dx,al ;posli ho na port
mov al,20h
out 20h,al ;posli end of interrupt
pop si ;obnov se ulozene.
pop dx
pop bx
pop ax
pop ds
iret
bufseg dw 0x1234 ;segment kde je ulozen playing buffer
;predpoklada se ze je 64Kb dlouhy.
bufpos dw ? ;ukazatel na aktualni prehravana data
;data jsou v bufferu ulozena unsigned
port dw ? ;cislo portu, kam je nutne data posilat
pm_bufseg dw ? ;buffer z protectu
xlattab db 256 dup (?) ;prekladova tabulka pro PC_SPEAK.
;pro DAC vyplnte cisli 0 - 255
rm_konec: ;ukazatel na konec rm_proc
_TEXT16 ends
.data
old8rmofs dw ?
old8rmseg dw ?
old8pmofs dd ?
old8pmseg dw ?
rmproc_rmseg dw ? ;segment rm_proc v realnem rezimu
rmproc_pmseg dw ? ;segment rm_proc v chranenem rezim
timer dw ? ;hodnota casovace pro simulaci puvodni INT 8
timer_max dw ? ;max hodnota casovace
zavora db 0 ;zavora do pm_proc
SPKTAB Db 20h, 1fh, 1eh, 1dh, 1ch, 1bh, 1ah, 19h, 18h, 17h, 16h, 15h, 14h, 13h
Db 12h, 11h, 11h, 10h, 10h, 0fh, 0fh, 0eh, 0eh, 0dh, 0dh, 0dh, 0ch, 0ch, 0ch, 0ch
Db 0bh, 0bh, 0bh, 0bh, 0Ah, 0ah, 0ah, 0ah, 0ah, 09h, 09h, 09h, 09h, 09h, 09h, 09h
Db 09h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 08h, 07h, 07h
Db 07h, 07h, 07h, 07h, 07h, 06h, 06h, 06h, 06h, 06h, 06h, 06h, 06h, 06h, 06h, 06h
Db 05h, 05h, 05h, 05h, 05h, 05h, 05h, 05h, 05h, 05h, 04h, 04h, 04h, 04h, 04h, 04h
Db 04h, 04h, 04h, 04h, 03h, 03h, 03h, 03h, 03h, 03h, 03h, 03h, 03h, 03h, 02h, 02h
Db 02h, 02h, 02h, 02h, 02h, 02h, 02h, 01h, 01h, 01h, 01h, 01h, 01h, 01h, 01h, 01h
Db 01h, 01h ;prekladova tabulka pro speakra.
db 40h, 40h, 40h, 40h, 40h, 40h, 40h, 40h, 40h, 40h, 3fh, 3fh, 3fh, 3fh
Db 3fh, 3fh, 3fh, 3fh, 3fh, 3fh, 3fh, 3eh, 3eh, 3eh, 3eh, 3eh, 3eh, 3eh, 3eh, 3eh
Db 3eh, 3eh, 3dh, 3dh, 3dh, 3dh, 3dh, 3dh, 3dh, 3dh, 3dh, 3ch, 3ch, 3ch, 3ch, 3ch
Db 3ch, 3ch, 3ch, 3ch, 3ch, 3bh, 3bh, 3bh, 3bh, 3bh, 3bh, 3bh, 3bh, 3bh, 3bh, 3ah
Db 3ah, 3ah, 3ah, 3ah, 3ah, 3ah, 3ah, 3ah, 3ah, 39h, 39h, 39h, 39h, 39h, 39h, 39h
Db 39h, 39h, 39h, 38h, 38h, 38h, 38h, 38h, 38h, 38h, 38h, 37h, 37h, 37h, 37h, 37h
Db 36h, 36h, 36h, 36h, 35h, 35h, 35h, 35h, 34h, 34h, 34h, 33h, 33h, 32h, 32h, 31h
Db 31h, 30h, 30h, 2fh, 2eh, 2dh, 2ch, 2bh, 2ah, 29h, 28h, 27h, 26h, 25h, 24h, 23h
Db 22h, 21h
_TEXT segment byte public 'CODE' use32
assume CS:_TEXT
assume DS:DGROUP
public load_rm_proc_ ;funkce nacte rm_proc do realne pameti
load_rm_proc_ :
mov ebx,(rm_konec-rm_proc+16) shr 4 ;velikost v paragrafech
mov eax,100h
int 31h ;alokuj DOS pamet
mov rmproc_rmseg,ax ;segment
mov rmproc_pmseg,dx ;selektor
sbb al,al ;al=0xff pri chybe
jc lrmp_e ;skok pri chybe
push es ;uchovej segmentove registry
push ds
mov es,dx
xor edi,edi
mov dx,ds
mov ds,dx
mov esi,offset rm_proc
mov ecx,(rm_konec-rm_proc)
rep movsb ;presun rm_proc z protect mem do real mem
pop ds
pop es
lrmp_e: ret
public purge_rm_proc_ ;funkce uvolni rm_proc z pameti
purge_rm_proc_:
mov dx,rmproc_pmseg
mov eax,101h
int 31h ;dealokuj
sbb al,al ;al obsahuje chybu
ret
;tutu proceduru je nutne volat jako posledni!
public rm_proc_set_ ;funkce nastavuje promenne v rm_proc
;ax - bufseg - rm adresa bufferu
;dx - bufseg - pm adresa bufferu
;cx - adresa portu
;bx - mod XLAT - 0 normal mode
; 1 pcspeak mode
assume es:_TEXT16
rm_proc_set_:
push es ;uloz es
mov si,ds ;seg bufseg
mov es,si
mov es:bufseg,ax ;zapis rm bufseg
mov es:pm_bufseg,dx ;zapis pm bufseg
mov es:port,cx ;zapis cislo portu
or bx,bx ;test bx
jz rps_nrm ;je li nulovy - normal mode
lea esi,SPKTAB ;vem spktab
lea edi,es:xlattab
mov ecx,256
rep movsb ;prenes ji do xlattab
jmp rps_pcs
rps_nrm:xor ah,ah ;al =0
mov al,80h
lea edi,es:xlattab
rps_nr1:stosb ;zapis al do xlattab
inc al ;al=al+1
inc ah
jnz rps_nr1 ;dokud to nebude cela tabulka
rps_pcs:pop es ;obnov es
ret
;POZNAMKA: tato procedura modifikuje data v originalnim vzoru. Proto ji je
;nutne volat pred vlastnim load_rm_proc
pc_speak_protect: ;funkce pro obsluhu pcspeak v protect mode
push ds
push es ;uchovej ohrozene registry
push eax
push ebx
push edx
push esi
mov ax,seg _DATA
mov ds,ax
mov ds,ds:rmproc_pmseg ;nacti ukazatel na datovou oblast v rmm
assume ds:_TEXT16
mov ebx,rl_xlattab ;nacti ukazatel na xlattab
movzx edx,word ptr ds:[rl_port] ;nacti cislo portu
movzx esi,word ptr ds:[rl_bufpos] ;nacti ukazatel na vzorek
mov es,word ptr ds:[rl_pm_bufseg] ;nacti pm_selector na buffer
lods byte ptr [es:esi];precti sample
mov word ptr ds:[rl_bufpos],si;uloz ukazatel na dalsi vzorek
xlatb ;preloz podle xlattab
out dx,al ;posli ho na port
mov ax,seg _DATA ;vem selector na globalni data
mov ds,ax ;napln jim ds
assume ds:DGROUP
mov al,20h ;posli eoi
out 20h,al
dec timer ;sniz citac
jnz pcs_p1 ;pokud neni na nule, skoc na konec
mov ax,timer_max ;napln citac maximalni hodnotou
mov timer,ax
cmp zavora,0 ;odtestuj zavoru
jnz pcs_p1 ;zavrena zavora by zpusobila preplneni INT8
mov zavora,1 ;zavri zavoru
pushfd ;uchovej flagy - simuluj INT
sti ;povol preruseni (vsechna preruseni na INT8 projdou zavorou)
call far dword ptr[old8pmofs] ;skok do puvodniho osetreni INT8
mov zavora,0 ;zakazovat int neni treba, jeho stav je ulozen ve flags
pcs_p1: pop esi ;otevri zavoru - obnov registry
pop edx
pop ebx
pop eax
pop es
pop ds
iretd ;konec obsluhy preruseni.
public pc_speak_run_ ;funkce instaluje bimodalni ovladac PCSPEAK
pc_speak_run_:
;eax - sample freq
;edx - frekvence simulace int 8 (18.2 HZ)
cli ;zakaz preruseni
push eax ;tyto parametry zatim nejsou potreba
push edx
mov eax,200h ;nejprve zjisti puvodni obsluhu RM
mov bl,8 ;INT 8
int 31h
mov old8rmofs,dx ;uloz hodnoty
mov old8rmseg,cx
mov eax,204h ;pak precti starou obsluhu PM
int 31h
mov old8pmofs,edx ;uloz hodnoty
mov old8pmseg,cx
mov eax,205h ;nastav novou obsluju PM
mov cx,cs
mov edx,offset pc_speak_protect
int 31h
mov eax,201h ;nastav novou obsluhu RM
mov cx,rmproc_rmseg
mov dx,0
int 31h
pop ebx ;obnov sample freq
pop eax ;obnov simint freq -> do ebx!
mov ecx,eax ;sample freq uchovej jeste v ecx
xor edx,edx ;vynuluj edx, horni polovina edx&eax
div ebx ;delenim ziskej timer (samplef/simintf)
mov timer,ax ;uloz timer -> deleni neni presne ale v ramci
mov timer_max,ax ;presnosti vyhovuje
mov eax,1234dch ;ziskej nastaveni 8253 delenim zakladni freqvence
xor edx,edx
div ecx ;to je ted v eax
mov ecx,eax ;uchovej ho v ecx
mov al,34h ;citac 1 word rezim 2 - 1:m
out 43h,al ;zapis nastaveni
mov al,cl ;dolni hodnotu citace
out 40h,al
mov al,ch ;horni hodnotu citace
out 40h,al
sti ;povol preruseni
ret
public pc_speak_stop_ ;tato funkce zasatvi prehravani PCSPEAK a vrati puvodni vektory
pc_speak_stop_:
cli
mov al,36h ;nejprve zpomal casovace
out 43h,al
mov al,0
out 40h,al
out 40h,al
mov bl,8
mov eax,201h ;vrat puvodni rm vektor
mov cx,old8rmseg
mov dx,old8rmofs
int 31h
mov eax,205h ;vrat puvodni pm vektor
mov cx,old8pmseg
mov edx,old8pmofs
int 31h
sti
ret
public pc_speak_enable_ ;povoluje prehravani na PCSpeaker(TM)
pc_speak_enable_: ;nastavuje specialni rezim prehravani.
in al,61H
or al,3
out 61H,al
mov AL,90H
out 43H,al
ret
public pc_speak_disable_ ;zakazuje prehravani na PCSpeaker(TM)
pc_speak_disable_: ;funkce defacto vraci puvodni nastaveni.
SPKOFF: in al,061H
and al,0FCH
out 61H,al
ret
public pc_speak_position_ ;ziska aktualni pozici
pc_speak_position_:
push es
mov es,rmproc_pmseg
movzx eax,word ptr es:[rl_bufpos]
movzx ebx,word ptr es:[rl_bufseg]
shl ebx,4
add eax,ebx
pop es
ret
public pc_speak_set_proc_ ;zapise na [edi] adresi na pc_speak_position_
pc_speak_set_proc_:
mov [edi],offset pc_speak_position_
ret
_TEXT ends
end