include 386power.inc
include 386video.inc
; BASIC VIDEO SERVICES
; _SetGameMode
; _RestoreTextMode
; _WaitVR
; _DisplayStart
; _PageFlip
code32 segment para public use32
assume cs:code32,ds:code32
_ActiveBase dd 0 ;base of page to write to
MidBase dd 0 ;base of "in between" page
_ViewBase dd 0 ;base of page to show
_ScoBase dd 0 ;base of "scoreboard" panel
; index of row start offsets from base of display screen (active,view,score)
_RowStart dd 0
dd VYHEIGHT dup(0)
; sottrai VGARAWOFFSET per passare da pointer code32 relativo
; ad offset nella vga memory window
VGARAWOFFSET dd 0
DispOffset dd 0 ; offset di scrolling
; old code for pix panning
; SmoothPix dd 0 ; valore per smooth scrolling
; XVGA MODE ENTRY/EXIT ROUTINES
;----------------------------------------------------------------------------
; void SetGameMode;
;
public _SetGameMode
_SetGameMode:
pushad
mov V86ax,0013h ; set 256-color mode BIOS MODE 13h
mov al,10h ;
int 33h ;
mov dx,SEQUENCER ; convert to X-mode addressing
; sequencer register 04h (MEMORY MODE)
; set chain mode off,no odd/even,more than 64k,graphics mode
mov ax,0604h ;
out dx,ax ;
WRITEMODE WPUT
WRITEPLANE WPA
@rlp edi,000A0000h
mov ecx,16*1024 ; CLEAR VIDEO MEMORY
xor eax,eax ; (addressing mode is planar
rep stosd ; but raster scanning is still the
; same of mode 13h)
; now change the raster scanning method
mov dx,CRTC
mov ax,00014h ; TURN OFF DWORD MODE (CRTC LONG MODE)
out dx,ax ; (change vram scanning method)
mov ax,0E317h ; TURN ON BYTE MODE
out dx,ax ;
; Tweaked mode fully activated, now perform other stuff
mov al,LINE_OFS
mov ah,SXWIDTH ; ampiezza di una linea/8
out dx,ax
;mov dx,GRAPHICS ; superfluo se non sei paranoide
;mov ax,ALL_BIT
;out dx,ax
; inizializza variabili "interne" ed "esterne"
@rlp eax,0A0000h
mov VGARAWOFFSET,eax
@rlp eax,SCOBASE
mov _ScoBase,eax
@rlp eax,BASE0
mov _ViewBase,eax
@rlp eax,BASE1
mov MidBase,eax
@rlp eax,BASE2
mov _ActiveBase,eax
; xor eax,eax
mov DispOffset,eax
; mov SmoothPix,eax
mov edi,offset _RowStart ; Row offset table
mov ecx,VYHEIGHT ;
mov eax,0 ;
mov ebx,PXWIDTH ;
iloop:
stosd
add eax,ebx
loop iloop
mov ecx,LYHEIGHT
call SplitScreen
call InstallPFLP
call _PageFlip
; ritorna a chi ha chiamato
popad
ret
;----------------------------------------------------------------------------
; void RestoreTextMode( void )
public _RestoreTextMode
_RestoreTextMode:
mov V86ax,0003h ; set text mode
mov al,10h
int 33h
ret
;----------------------------------------------------------------------------
; void _WaitVR(void) WAIT A FULL V.R TIME FRAME
;
public _WaitVR
_WaitVR: push edx
push eax
mov dx,STATUS
@@swap_retr1: cli
in al,dx
test al,8 ; VERTICAL RETRACE ?
jnz @@swap_retr1 ; loop if V.R. (into retrace)
@@swap_retr2:
in al,dx
test al,8 ; V.R. ?
jz @@swap_retr2 ; loop if not V.R.
sti
pop eax
pop edx
; NOW you have a FULL V.R. time frame available
ret
;----------------------------------------------------------------------------
; void DisplayStart(eax= x,edx =y) SET DISPLAY VIDEO WINDOW POSITION
; INSIDE DISPLAY PAGE
public _DisplayStart
_DisplayStart:
; eax= x_position , ebx = y_position
;;push ecx
push eax
;;mov ecx,eax ;
;;and ecx,3 ; maschera di bits per lo shifter
;;shl ecx,1 ;
;;mov SmoothPix,ecx ;
shr eax,2 ;offset nella pagina video corrente
add eax,_RowStart[edx*4] ;
mov DispOffset,eax ;
pop eax
;;pop ecx
ret
;----------------------------------------------------------------------------
; void DisplayPage(ECX= offset of display page )
; SHOW PAGE starting at offset eax (INTERNAL FUNCTION)
DisplayPage:
; ecx = offset di inizio pagina video corrente
mov bx,VSTART_HILO ;preload for fastest access
add ecx,DispOffset ; somma l' inizio video nella pagina
sub ecx,VGARAWOFFSET ; trasforma in raw vga offset
xchg bh,cl ; BX=prima coppia CX=seconda coppia
mov dx,STATUS
cli
;@@WaitNVS:
; in al,dx
; and al,08h
; jnz @@WaitNVS ;vertical sync is active high (0= drawing)
@@WaitHS:
in al,dx
and al,01
jnz @@WaitHS ;hor. sync is active high (1 = active)
; n.b. HSync is display enable too!!!
; Set the start offset in display memory of the page to display.
mov dx,CRTC
mov eax,ebx
out dx,ax ;start address low
mov eax,ecx
out dx,ax ;start address high
; mov dx,STATUS
;@@WaitVS:
; in al,dx
; and al,08h
; jz @@WaitVS ;vertical sync is active high (1 = active)
;@@QuickFlip:
; ; attribute controller already in address mode
; mov dx,ATTRIBUTE
; mov al,PEL_PANNING
; out dx,al
; mov al,byte ptr SmoothPix
;
; ; now give some time to old jerky vga cards
; jc zik
; zik:
; jnc zok
; zok:
; jc zik2
; zik2:
; jnc zok2
; zok2:
; jc zik3
; zik3:
; jnc zok3
; zok3:
out dx,al
sti
ret
;--------------------------------------------------------------------------
; void cdecl PageFlip(void)
;
public _PageFlip
_PageFlip: ; _Viewbase <-- _ActiveBase <-- MidBase <-- _ViewBase
; & show new _ViewBase
pushad
mov ebx,PageTicks
@pfgloop:
mov eax,_TimerTicks
mov edx,eax
sub eax,ebx
cmp eax,FrameTicks
jb @pfgloop ; loop if too few time has passed
mov PageTicks,edx
mov eax,MidBase
mov ebx,_ViewBase
mov ecx,_ActiveBase
mov _ActiveBase,eax
mov MidBase,ebx
mov _ViewBase,ecx
; ecx == new viewbase
call DisplayPage
popad
ret
;--------------------------------------------------------------------------
; void cdecl SplitScreen(ecx = Splitline)
; INTERNAL FUNCTION
SplitScreen:
; ecx = SplitLine (in low word)
; inanzitutto disabilita il panning
; dello splitscreen, ma prima salva il parametro
push ecx
cli
mov dx,STATUS ;poni attribute controller in address mode
in al,dx
mov ecx,200
okuto1: loop okuto1
; ora disabilita il panning dello splitscreen
mov al,ATTR_CONTROL
mov dx,ATTRIBUTE
out dx,al ; seleziona registro di panning
; lascia passare del tempo
mov ecx,200
okuto2: loop okuto2
inc dx
in al,dx ;leggi gli attributi correnti
or al,NOSPLITPAN
; lascia passare del tempo
mov ecx,200
okuto3: loop okuto3
mov ah,al ; salva i flag
mov dx,STATUS ;
in al,dx ; nuovamente in address mode (ripulisci il f/f di stato)
mov dx,ATTRIBUTE
mov al,ATTR_CONTROL ;pronto a ri-scrivere su attribute controller
out dx,al
; lascia passare del tempo
mov ecx,200
okuto4: loop okuto4
mov al,ah ; scrivi i nuovi flag degli attributi video
out dx,al ;
sti
; ora puoi modificare il line compare
; register e gli altri suoi bits
; sparsi in altri 2 registri
pop ecx
; Now wait for vertical sync, so the other page will be invisible when
; we start drawing to it.
mov dx,STATUS
cli
@@WVS:
in al,dx
and al,08h
jz @@WVS ;vertical sync is active high (1 = active)
mov dx,CRTC
; ECX = splitline
shl ecx,1 ; moltiplica per due
; (si e' in modo a doppia scansione)
dec ecx ; e riduci di 1
; write bit 0..7
mov al,LINE_COMPARE
mov ah,cl
out dx,ax
; write bit 8
mov cl,0
shr ecx,1 ; porta il bit 8
shr cl,3 ; nel bit 4 di BL
mov ax,0707h ;bit 8 is CRTC INDEX 7 BIT 4
out dx,al
inc dx
in al,dx
dec dx
and al,0EFh ;azzera bit 4
or al,cl ; registra il nuovo bit
xchg ah,al
out dx,ax
; write bit 9
mov cl,0
shr ecx,1
shr cl,1
mov ax,0909h
out dx,al
inc dx
in al,dx
dec dx
and al,0BFh ;azzera bit 6
or al,cl
xchg al,ah
out dx,ax
sti ;enable interrupts
ret
; EXTENDED INPUT, TIMER DRIVEN PAGE FLIPPING & SOUND OUTPUT
; questa sezione di 386VIDEO(game)
; gestisce in modo diretto la tastiera,lo speaker incorporato
; in ogni PC & il timer connesso a IRQ0.
; RAW KEYBOARD I/O
; 32bit section, Keyboard ISR for raw keyboard input
; Raw KeyBoard table
; Every key "description" is made of two consecutive bytes
; if a key has a keyboard scancode K
; address:
; _RKB+(K) bit meaning: description:
; 0 IS_PRESSED 0 == key K is currently not pressed
; 1 == key K is currently pressed
;
; 1 TOUCHED 0 == key K has not been pressed
; since last time you cleared this bit.
; 1 == key K has been pressed
;
; Use IS_PRESSED for "raw" control (i.e cursor keys in a game)
; and TOUCHED (but clear it before!!) for "keyboard-like" control
; when you have to choose items in a menu or when
; you have to check special "toggle" keys that may be pressed anytime
; (i.e. the all time high ESC key)
public _RKB,_RKBPressed
_RKB db 0
db 128 dup(0)
_RKBPressed db 0 ; 0 == no keys pressed since last time you reset this flag
; 1 == something happened, a key has been pressed
; (this is like a "general" TOUCHED flag)
IRQ1_ISR:
cli
push eax
push ebx
push ds
mov ds,cs:_SelData
in al,60h ; get scan code
movzx ebx,al ; move scan code to index register
in al,61h ; get control code
push eax
or al,80h ; clear keyboard of interrupt:
out 61h,al ;
pop eax ; first send control byte with inverted MSB
out 61h,al ; then send plain control byte
mov al,EOI ; send generic EOI to
out PIC0_CTRL,al ; PIC
; enabling other interrupts
mov al,bl
and bl,07Fh
; if the key was released, the high bit is set in the scan code
mov byte ptr[ebx+offset _RKB],02h ; reset "Is being pressed" flag
; and left set "Has been pressed"
rol al,1
jc key_released
mov byte ptr [ebx+offset _RKB],03h ; set "Is being pressed" flag
; and "Has been pressed" flag
key_released:
mov _RKBPressed,1 ; state of keyboard has changed
sti
pop ds
pop ebx
pop eax
iretd
public _WaitKey
_WaitKey:
; WAITS UNTIL A KEY IS PRESSED
mov _RKBPressed,0
@waitmore:
test _RKBPressed,1
jz @waitmore
ret
public _InstallRKB
_InstallRKB:
pushad
mov eax,0
mov edi,offset _RKB
mov ecx,32 ; 128bytes == 32 dwords
rep stosd
cli
test _386Man,IS_DPMI
jnz NoReflex
mov al,21h
mov V86ax,2509h
mov V86ds,seg code16
mov V86dx,offset IRQ1_RISR
int 33h
NoReflex:
mov bl,1
mov edx,offset IRQ1_ISR
call _SetIRQ
sti
popad
ret
; PWM SOUND ON PC-SPEAKER & TIMER-DRIVEN PAGE FLIPPING
; 32bit section
public _SoundOn,_SoundLen,_SoundPtr
public _DSoundOn,_DSoundLen,_DSoundPtr
align dword
; current sound data
_SoundLen dd 0 ; default = zero sound lenght
_SoundPtr dd 0 ; default = null, points to already decode sound data
; the installed sound driver must play
; default sound data
_DSoundLen dd 0 ; default = zero , default sound lenght
_DSoundPtr dd 0 ; default = null , default sound
align byte
_SoundOn db 0 ; Set this to turn on sound generation, all sound driver must
; refer to this flag to control sound output
_DSoundOn db 0 ;ditto for the default sound insertion at end of sound
Buzzing db 0 ; are we currently producing sound ? (private var.)
align dword
; decrementi di contatore usati come riferimento
PWMTICK = 149 ; conteggio equivalente a 8008Hz
VSyncTick dd 0 ; Vsync count ... Initialize with VSyncInit()
TIMERTICK = (64*1024) ; conteggio equivalente a 18.2 Hz
ONESECOND = 1193180
public _TimerTicks,_SysTicks,_Seconds
_TimerTicks dd 0 ; ticks in frequenza base a 1193180 Hz
; usa sempre la granularita piu fine a disposizione
PageTicks dd 0 ; tick counter for pageflips
FrameTicks = 19886 ; 1193180hz/60hz timer count
InnerTicks dd 0 ; simile a _TimerTicks, ma usato per calcolare systicks
SecTicks dd 0 ; idem, ma per _Seconds
_SysTicks dd 0 ; ticks a 18.2Hz
_Seconds dd 0 ; contasecondi totali
align byte
InstallPFLP:
; installs the pageflip support code
pushad
cli
; first in real mode
test _386Man,IS_DPMI
jnz @nopfreflex
mov al,21h
mov V86ax,2508h
mov V86ds,code16
mov V86dx,offset PFLP_RISR
int 33h
@nopfreflex:
; second in protected mode (it works only this way under DPMI)
mov bl,0
mov edx,offset PFLP_ISR
call _SetIRQ
mov al,T_SET0 ; set programmable interval timer 0 to FrameTicks
out PIT_CTRL,al ;
mov eax,FrameTicks
out PIT0,al ;
mov al,ah ;
out PIT0,al ;
; initialize counters
mov _TimerTicks,0
mov PageTicks,0
mov InnerTicks,0
mov SecTicks,0
mov _SysTicks,0
mov _Seconds,0
sti
popad
ret
PFLP_ISR:
sti
push eax
push ebx
push ds
mov ds,cs:_SelData
mov ebx,FrameTicks
add _TimerTicks,ebx
add InnerTicks,ebx
add SecTicks,ebx
mov eax,SecTicks
sub eax,ONESECOND
jb pdone_sec
mov SecTicks,eax
inc _Seconds
pdone_sec:
mov eax,InnerTicks
sub eax,TIMERTICK
jb pdone_irq0
mov InnerTicks,eax
; n.b. TTick conta i ticks di sistema in formato fixed point
; con una cifra decimale
inc _SysTicks
pzapped_time:
; it's time to call the old ISR
mov al,8
int 33h
jmp short pirq0_digged
pdone_irq0:
mov al,EOI
out PIC0_CTRL,al
pirq0_digged:
pop ds
pop ebx
pop eax
iretd ; ritorna il controllo a 386 power
public _InstallPWM
_InstallPWM:
; install irqs & set up voc_table
pushad
; initialize internal vars
mov Buzzing,0
mov _SoundOn,0
mov _DSoundOn,0
mov _SoundLen,0
mov _SoundPtr,0
mov _DSoundLen,0
mov _DSoundPtr,0
; set voc_table
mov esi,offset pwm_table
mov edi,offset voc_table
mov eax,0
mov ecx,64
set_up_voc_table:
movsd
loop set_up_voc_table
cli
; first install the real mode side
cmp _386Man,IS_DPMI
je @nopwreflex
mov al,21h
mov V86ax,2508h
mov V86ds,code16
mov V86dx,offset code16:IRQ0_RISR
int 33h
@nopwreflex:
; then the protected mode side (it works only this way in DPMI)
mov bl,0
mov edx,offset IRQ0_ISR
call _SetIRQ
mov ebx,F8008 ; 8008Hz count
cmp _386Man,IS_DPMI
jne @vcpispeed
shl ebx,1 ; freq to 4004Hz
@vcpispeed:
mov play_rate,ebx ; set playback frequency for voc converter
mov al,T_SET0 ; set programmable interval timer 0 to 8008Hz or 4004Hz
out PIT_CTRL,al ;
mov al,bl ;
out PIT0,al ;
mov al,bh ;
out PIT0,al ;
sti
; no need to initialize time counters
; InstallPFLP already did it
popad
ret
; PWM SOUND SPEAKER DRIVER
zarp_sound:
cmp _DSoundOn,0
je dont_buzz
mov eax,_DSoundLen
dec eax
mov ebx,_DSoundPtr
mov _SoundLen,eax
jmp doit_again
dont_buzz:
cmp Buzzing,0
je getoutsound
mov Buzzing,0
; turn speaker OFF
in al, 61h ;Read I/O port B into AL
and al, 11111100b ;mask lower two bits
out 61h, al ;to turn off speaker
jmp short getoutsound
DoTheSound macro
cmp _SoundOn,0
je dont_buzz ; no sound if sound flag is off
cmp _SoundLen,0
je zarp_sound ; no sound if at end of "soundtrack"
dec _SoundLen ; decrease "soundtrack" lenght
mov ebx,_SoundPtr ;get current count pointer
doit_again:
mov al,[ebx] ; count into AX
inc ebx ; & update sound pointer
mov _SoundPtr,ebx ; (only offset is changed)
mov ah,al ; copy count
or al,al ; zero count sets speaker off
;je dont_buzz ;
mov al,P_SET2S
out PIT_CTRL,al
mov al,ah
out PIT2, al
cmp Buzzing,0
jne getoutsound
mov Buzzing,1
; turn sound on
in al, 61h ;read I/O port B into AL
or al,3 ;turn on bits 0 and 1
out 61h,al ;to turn on speaker
getoutsound:
endm
; IRQ0 Timer handler, it handles TWO different "time driven" nested loops
; the 8008 Hz PWM sound system
; the 18,2 Hz System tick for periodic events and rough time keeping
IRQ0_ISR:
cli
push eax
push ebx
push ecx
push edx
push ds
mov ds,cs:_SelData
mov ebx,play_rate
add _TimerTicks,ebx
add InnerTicks,ebx
add SecTicks,ebx
DoTheSound
sti
mov eax,SecTicks
sub eax,ONESECOND
jb done_sec
mov SecTicks,eax
inc _Seconds
done_sec:
mov eax,InnerTicks
sub eax,TIMERTICK
jb done_irq0
mov InnerTicks,eax
; n.b. TTick conta i ticks di sistema in formato fixed point
; con una cifra decimale
inc _SysTicks
zapped_time:
; it's time to call the old ISR
mov al,8
int 33h
jmp short irq0_digged
done_irq0:
mov al,EOI
out PIC0_CTRL,al
irq0_digged:
pop ds
pop edx
pop ecx
pop ebx
pop eax
iretd ; ritorna il controllo a 386 power
;-----------------------------------------------------------------------------
; 8bit, not compressed VOC to "raw 8 bit pcm"
align dword
voc_rate dd ?
play_rate dd ? ; playback sample rate and IRQ0 frequency under PWM sound
align byte
pwm_table db 1 , 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20
db 21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30
db 31,31,31,32,32,32,33,33,33,34,34,34,35,35,35,36,36,36,37,37
db 37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,43,43,43,44
db 45,45,45,46,46,46,47,47,47,48,48,48,49,49,49,50,50,50,51,51
db 51,52,52,52,53,53,53,54,54,54,55,55,55,56,56,56,57,57,57,57
db 58,58,58,58,59,59,59,59,60,60,60,60,61,61,61,61,62,62,62,62
db 63,63,63,63,63,64,64,64,64,64,65,65,65,65,65,66,66,66,66,66
db 67,67,67,67,67,68,68,68,68,68,69,69,69,69,69,70,70,70,70,70
db 71,71,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,72
db 73,73,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74,74,74,74
db 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75
db 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75
voc_table db 1 , 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20
db 21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,30,30
db 31,31,31,32,32,32,33,33,33,34,34,34,35,35,35,36,36,36,37,37
db 37,38,38,38,39,39,39,40,40,40,41,41,41,42,42,42,43,43,43,44
db 45,45,45,46,46,46,47,47,47,48,48,48,49,49,49,50,50,50,51,51
db 51,52,52,52,53,53,53,54,54,54,55,55,55,56,56,56,57,57,57,57
db 58,58,58,58,59,59,59,59,60,60,60,60,61,61,61,61,62,62,62,62
db 63,63,63,63,63,64,64,64,64,64,65,65,65,65,65,66,66,66,66,66
db 67,67,67,67,67,68,68,68,68,68,69,69,69,69,69,70,70,70,70,70
db 71,71,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,72
db 73,73,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74,74,74,74
db 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75
db 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75
set_comp macro
lodsb
or al,al
mov al,2 ; compressed data
jne voc_end
endm
set_sample macro
lodsb
and eax,0FFh
mov ebx,256
mov edx,0
mov eax,1000000
div ebx
; eax = samples/sec
mov ebx,eax
mov edx,0
mov eax,1193180
div ebx
; eax = timer count equivalent to sample rate
mov voc_rate,eax
endm
blitquiet macro
; ecx =ctr
mov edx,0
mov ebx,voc_rate
mov ebp,play_rate
mov eax,0
stamp:
dec ecx
je end_sil
add edx,ebx
cmp edx,ebp
jb stamp
sub edx,ebp
stosb
jmp stamp
end_sil:
endm
blitsound macro
; ecx = ctr
mov edx,0
zound: mov ebx,0
mov eax,0
interp: add al,[esi]
adc ah,0
inc esi
inc ebx
dec ecx
je end_data
add edx,voc_rate
cmp edx,play_rate
jb interp
end_data: sub edx,play_rate
div bl
mov al,[eax + voc_table]
stosb
cmp ecx,0
jne zound
endm
VocPackets dd offset voc_end, offset voc_data, offset voc_cont
dd offset quiet, offset marker, offset ascii
dd offset rep_start, offset rep_end, offset extend
decoder: mov ebx,0
decode: lodsd
mov bl,al
cmp al,9
jnb voc_end
jmp [ebx*4+ VocPackets]
rep_end: mov al,1 ; rep end without rep_start if it is not matched
voc_end: ret
rep_start:
lodsw
push esi ; inserisci puntatore
reploop:
mov esi,[esp] ; ricarica puntatore
push eax
call decode
pop eax
dec ax
jne reploop
add esp,4 ; rimuovi puntatore
jmp decode
voc_data:
mov ecx,-2
shr eax,8
add ecx,eax
set_sample
set_comp
sblit:
blitsound
jmp decoder
voc_cont:
shr eax,8
mov ecx,eax
jmp sblit
quiet:
movzx eax, word ptr [esi]
mov ecx,1
add esi,2
add ecx,eax
set_sample
blitquiet
jmp decoder
extend: mov al,3 ; extended voc file
ret
marker:
add esi,2
jmp decode
ascii:
shr eax,8
add esi,eax
jmp decode
vocstamp db 'Creative Voice File',1Ah
public _Voc2RAW
_Voc2RAW:
; in:
; esi = .VOC data to translate, edi = destination for RAW data
; al = error code (0 == no errors)
; ebx = RAW datablock
; edi = end of RAW datablock + 1
push edi ; save data start
add edi,4
movzx ebx,word ptr [esi+14h]
mov edx,esi
mov ecx,0
add esi,ebx
mov ebx, offset vocstamp
votest: mov eax,[edx]
cmp eax,[ebx]
jne eend
add edx,4
add ebx,4
inc ecx
jmp votest
eend: cmp ecx,5
jne novoc
call decoder
pop ebx ; restore data start
sub edi,ebx
sub edi,4
mov [ebx],edi
; al is zero (value transmitted from decoder)
ret
novoc:
add esp,4 ; remove pointer to start of voc file
mov al,4 ; not a voc file
ret
code32 ends
code16 segment para public use16
assume cs:code16,ds:code32
; here comes the 16-bit handlers for irq0 and irq1
; (to support bimodal irqs without wasteful callbacks)
; RAW KEYBOARD
; 16bit section, Keyboard ISR for raw keyboard input
IRQ1_RISR: ;Real mode ISR
; WARNING! BE SURE 386Video IS LINKED IMMEDIATLY AFTER
; 386Power (to be sure all the var accessed are into a 64k range)
; OR STRANGE THINGS MAY HAPPEN!!!!!!!
; (depending on what assembler you use to assemble this stuff)
push eax
push ebx
push ds
mov ax,seg code32
mov ds,ax
in al,60h ; get scan code
movzx ebx,al ; move scan code to index register
in al,61h ; get control code
push eax
or al,80h ; clear keyboard of interrupt:
out 61h,al ;
pop eax ; first send control byte with inverted MSB
out 61h,al ; then send plain control byte
mov al,EOI ; send generic EOI to
out PIC0_CTRL,al ; PIC
; enabling other interrupts
mov al,bl
and bl,07Fh ; remove flag bit
; if the key was released, the high bit is set in the scan code
mov byte ptr ds:[ebx+offset _RKB],02h ; reset "Is being pressed" flag
; and left set "Has been pressed"
rol al,1 ;
jc rkey_released ;
mov byte ptr ds:[ebx+offset _RKB],03h ; set "Is being pressed" flag
; and "Has been pressed" flag
rkey_released:
mov ds:_RKBPressed,1 ; state of keyboard has changed
pop ds
pop ebx
pop eax
iret
; PWM SOUND SPEAKER DRIVER
rdont_buzz:
cmp Buzzing,0
je rgetoutsound
mov Buzzing,0
; turn speaker OFF
in al, 61h ;Read I/O port B into AL
and al, 11111100b ;mask lower two bits
out 61h, al ;to turn off speaker
jmp rgetoutsound
RDoTheSound macro
cmp _SoundOn,0
je rdont_buzz ; no sound if sound flag is off
cmp _SoundLen,0
je rdont_buzz ; no sound if at end of "soundtrack"
dec _SoundLen ; decrease "soundtrack" lenght
mov ebx,_SoundPtr ;get current count pointer
inc _SoundPtr ; increase pointer
mov eax,ebx
shr ebx,4
and ax,0Fh
add bx,seg code32
mov es,bx
mov al,es:[ebx] ; count into AX
or al,al ; zero count sets speaker off
;je rdont_buzz ;
mov ah,al ;
mov al,P_SET2S
out PIT_CTRL,al
mov al,ah
out PIT2, al
cmp Buzzing,0
jne rgetoutsound
mov Buzzing,1
; turn sound on
in al, 61h ;read I/O port B into AL
or al,3 ;turn on bits 0 and 1
out 61h,al ;to turn on speaker
rgetoutsound:
endm
; IRQ0 Timer handler, it handles TWO different "time driven" nested loops
; the 8008 Hz PWM sound sytem
; the 18,2 Hz System tick for periodic events and rough time keeping
IRQ0_RISR:
push eax
push ebx
push ecx
push edx
push ds
push es
mov ax,code32
mov ds,ax
mov ebx,play_rate
add _TimerTicks,ebx
add InnerTicks,ebx
add SecTicks,ebx
RDoTheSound
sti
mov eax,SecTicks
sub eax,TIMERTICK
jb rdone_sec
mov SecTicks,eax
inc _Seconds
rdone_sec:
mov eax,InnerTicks
sub eax,TIMERTICK
jb rdone_irq0
mov InnerTicks,eax
; n.b. TTick conta i ticks di sistema in formato fixed point
; con una cifra decimale
inc _SysTicks
rzapped_time:
; it's time to call the old ISR
pushf
call dword ptr cs:[(8*4) + offset _OldInt]
jmp short rirq0_digged
rdone_irq0:
mov al,EOI
out PIC0_CTRL,al
rirq0_digged:
pop es
pop ds
pop edx
pop ecx
pop ebx
pop eax
iret ; ritorna il controllo a 386 power
PFLP_RISR:
push eax
push ebx
push ds
mov ax,code32
mov ds,ax
mov ebx,FrameTicks
add _TimerTicks,ebx
add InnerTicks,ebx
add SecTicks,ebx
sti
mov eax,SecTicks
sub eax,ONESECOND
jb prdone_sec
mov SecTicks,eax
inc _Seconds
prdone_sec:
mov eax,InnerTicks
sub eax,TIMERTICK
jb prdone_irq0
mov InnerTicks,eax
; n.b. TTick conta i ticks di sistema in formato fixed point
; con una cifra decimale
inc _SysTicks
przapped_time:
; it's time to call the old ISR
pushf
call dword ptr cs:[(8*4) + offset _OldInt]
jmp short prirq0_digged
prdone_irq0:
mov al,EOI
out PIC0_CTRL,al
prirq0_digged:
pop ds
pop ebx
pop eax
iret ; ritorna il controllo a 386 power
code16 ends
END