Programowanie g這郾iczka w asemblerze

Czy nie my郵icie czasem, jakby to by這, gdyby mo積a by這 wzbogaci sw鎩 program opr鏂z efektu wizualnego, tak瞠 o efekt d德i瘯owy?
Programowanie kart d德i瘯owych (zw豉szcza tych nowoczesnych) mo瞠 sprawia niema貫 k這poty. Stary, poczciwy PC-Speaker jest jednak urz康zeniem wzgl璠nie prostym w programowaniu i to w豉郾ie tutaj udowodni. Najpierw troszk teorii, potem - do dzie豉!

Sporo urz康ze w komputerze ma w豉sne porty, przez kt鏎e mo積a si z nimi komunikowa. Jednak g這郾iczek komputerowy nie ma w豉snego portu.
Jest tak przede wszystkim ze wzgl璠u na oszcz璠no軼i w budowie pierwszych PC-t闚. Zamiast da osobny port na g這郾ik, firmy produkuj帷e komputery wcisn窸y go pod opiek dw鏂h innych urz康ze:

Podstawowe porty czasomierza to porty od 40h do 43h (ca造 zakres to 40h - 5fh, h oznacza szesnastkowo), kontrolera klawiatury za - 60h do 64h (ca造 zakres: 60h - 6fh).
Nie b璠ziemy ich jednak wszystkich u篡wa. B璠 na interesowa tylko porty 42h, 43h i 61h.

Zacznijmy wi璚 co pisa:

	in al,61h
	or al,3
	out 61h,al

Co zrobili鄉y? W spisie port闚 Listy Przerwa Ralfa Brown'a czytamy:


(przeskocz port 61h)
	0061  R-  KB controller port B control register (ISA, EISA)
	0061  -W  KB controller port B (ISA, EISA)

	(R - czytanie (read) , W - pisanie (write))

oraz:


(przeskocz opis portu 61h)
	Bitfields for KB controller port B (system control port) [output]:
	Bit(s)  Description     (Table P0392)
	 7      pulse to 1 for IRQ1 reset (PC,XT)
	 6-4    reserved
	 3      I/O channel parity check disable
	 2      RAM parity check disable
	 1      speaker data enable
	 0      timer 2 gate to speaker enable

Komenda IN AL,61h czyta bie膨cy status kontrolera, OR AL,3 ustawia (w陰cza) bity 0 (w陰czenie bramki do g這郾iczka) oraz 1 (w陰czenie mo磧iwo軼i wysy豉nia danych do g這郾iczka), OUT 61h,AL zapisuje nowy status do kontrolera.

G這郾iczek jest w陰czony. Trzeba mu poda jaki sygna. Do tego pos逝篡 nam czasomierz. W spisie port闚 czytamy:


(przeskocz opis port闚 42h i 43h)
	0042  RW  PIT  counter 2, cassette & speaker

	0043  RW  PIT  mode port, control word register for counters 0-2
	    Once a control word has been written (43h), it must be followed
	    immediately by performing the corresponding action to the counter
	    registers (40h-42h), else the system may hang!!

Do port闚 tych nie b璠ziemy wysy豉 jednak cz瘰totliwo軼i, kt鏎 chcemy uzyska. Czasomierz pracuje na cz瘰totliwo軼i 1193181 (1234DDh) Hz i to t warto嗆 dzielimy przez 膨dan cz瘰totliwo嗆, a wynik wysy豉my do odpowiednich port闚.

Piszmy wi璚:


(przeskocz w陰czanie g這郾iczka)
	mov bx,440h	; Standardowy d德i瘯 A, 440 Hz
	mov dx,12h	; g鏎na cz窷 liczby 1234dd
	mov ax,34ddh	; dolna cz窷 liczby 1234dd
	div bx		; ax = warto嗆 do wys豉nia

	pushf		; zachowaj flagi
	push ax		; zachowaj warto嗆 do wys豉nia
	cli		; wy陰cz przerwania
	mov al,0b6h
	out 43h,al	; wy郵ij komend

	pop ax
	out 42h,al	; wy郵ij pierwsz po這w licznika
	mov al,ah
	out 42h,al	; wy郵ij drug po這w licznika
	popf		; przywr鵵 stan flagi przerwa
	

No i co my tutaj znowu zrobili鄉y?
4 pierwsze komendy to oczywi軼ie uzyskanie warto軼i do wys豉nia na port, ale reszta?

Najpierw: 0b6h = 1011 0110

Bity 7 i 6 = 10 = wybierz (standardowo niezaj皻y) czasomierz nr 2 (陰cznie s 3: zegar czasu rzeczywistego, czasomierz od鈍ie瘸nia pami璚i RAM i ten trzeci, nieu篡wany)
Bity 5 i 4 = 11 = zapisujemy do czasomierza najpierw m這dsze bity (0-7) warto軼i, potem starsze (8-15)
Bity 3-1 = 011 = wybierz tryb nr 3, czyli generator fali kwadratowej
Bit 0 = 0 = licznik binarny 16-bitowy.

Zgodnie z tym, najpierw wysy豉my m這dszy bajt, AL a potem starszy, AH.

Skoro na port mo積a wys豉 najwi瘯sz warto嗆 0ffffh (teoretycznie najwi瘯sza jest 10000h, obcinana do 0000h), to jakiej odpowiada to cz瘰totliwo軼i?
1234dd / 10000h to ok. 12h, czyli 18. A dok豉dniej jest to co oko這 18,2 Hz - standardowa cz瘰totliwo嗆 zegara w komputerze (aby odmierzy 1 sekund trzeba ok 18 tykni耩 tego zegara)

Nasz g這郾iczek ju gra. Teraz trzeba sprawi, bo to troszk potrwa這. Pomocne b璠zie przerwanie 15h, funkcja 86h:

	mov cx,0fh
	mov dx,4240h
	mov ah,86h
	int 15h			; pauza o d逝go軼i CX:DX mikrosekund

I d德i瘯 trwa 1 sekund (F4240h = 1.000.000). Teraz trzeba go wy陰czy. Nic prostszego. Po prostu zamkniemy przej軼ie mi璠zy czasomierzem a g這郾iczkiem:

	in al,61h
	and al,not 3		; zerujemy bity 0 i 1
				; NASM:  "and al,~3"
	out 61h,al

Mam nadziej, 瞠 poda貫m wystarczaj帷o informacji, aby軼ie samodzielnie zacz瘭i programowa g這郾iczek. Je郵i mi si nie uda這, to zawsze mo瞠cie skorzysta z gotowej procedury z mojej biblioteki.

To ju koniec. Mi貫j zabawy!



Spis tre軼i off-line (Alt+1)
Spis tre軼i on-line (Alt+2)
U豉twienia dla niepe軟osprawnych (Alt+0)