Kurs programowania w asemblerze


Jak to się robi w asemblerze?

Dźwięk

Często podczas pisania programów zachodzi potrzeba wydobycia z komputera jakiegoś sygnału. Można to uczynić w bardzo prosty sposób używając głośnika znajdującego się w naszym PC. Do wytwarzania dźwięku trzeba odpowiednio zaprogramować licznik czasu, czyli układ INTEL 8253, który pracuje jako programowalny dzielnik częstotliwości. Wydobycie dźwięku składa się więc z dwóch głównych czynności: zaprogramowaniu odpowiednio licznika i przesłaniu sygnału do głośnika. Aby uzyskać dźwięk o danej częstotliwości f należy skorzystać z prostej zależności: K=1193181/f, gdzie nasze K, jest to współczynnik podziału. Teraz do portu 43H należy wpisać liczbę B6H. Jest to stała sterująca, ustalająca konfigurację dzielnika częstotliwości. Następnie do portu 42H ładujemy młodszy, a potem starszy bajt naszego współczynnika podziału K. Teraz trzeba wydobyć z głośnika dźwięk. Głośnik używa dwóch najmłodszych bitów portu 61H. Aby włączyć głośnik, musimy ustawić te bity na wartość 1. Nie można podczas tej operacji zmieniać wartości innych bitów. By wyłączyć dźwięk trzeba te bity wyzerować. By wydobyć więc prosty dźwięk należy napisać:

MOV BX,K          ; K - współczynnik podziału
MOV AL,0B6H
OUT 43H,AL        ; ustalenie konfiguracji dzielnika
MOV AL,BL         ; AL- mniej znaczący bajt K
OUT 42H,AL        ; wysłanie do portu 42H
MOV AL,BH         ; AL- bardziej znaczący bajt K
OUT 42H,AL        ; wysłanie do portu 42H
IN AL,61H         ; wczytanie zawartości portu 61H
OR AL,11B         ; ustawienie dwa najniższe bity na 1
OUT 61H,AL        ; i wysłanie do portu 61H
...               ; dowolne operacje <dźwięk teraz gra>
IN AL,61H         ; do AL wartość portu 61H
AND AL,11111100B  ; wyzerowanie dwóch najniższych bitów
OUT 61H,AL        ; i wysłanie do portu 61H

Implementacja w Turbo Pascalu procedur SOUND i NoSoudn:

SOUND:
 MOV BX,SP
 MOV BX,SS:[BX+4]
 MOV AX,34DDH
 MOV DX,0012H
 CMP DX,BX
 JNC @@2 ;ustalenie wartości dzielnika
 DIV BX
 MOV BX,AX ;sprawdzenie, czy głośnik nie jest już włączony
 IN AL,61H
 TEST AL,3
 JNZ @@1 ;włączenie bramki poprzez układ 8255
 OR AL,3
 OUT 61H,AL ;wpis do rejestru sterującego 8253
 MOV AL,0B6H
 OUT 43H,AL ;wpisanie wartości podzielnika do rejestru 42H
@@1:
 MOV AL,BL
 OUT 42H,AL
 MOV AL,BH
 OUT 42H,AL
@@2:
 RETF 2
NOSOUND:
 IN AL,61H
 AND AL,0FCH
 OUT 61H,AL
 RETF

Liczby losowe

Bardzo często zachodzi potrzeba wygenerowania jakiejś liczby losowej. Jest to bardzo proste, wystarczy posłużyć się poniższą procedurą. Zwraca ona w rejestrze AX liczbę losową z danego przedziału:

RANDOM PROC
 MOV BX,Seed
 ADD BX,9248h
 ROR BX,1
 ROR BX,1
 ROR BX,1
 MOV Seed,BX
 MOV AX,RndHi
 SUB AX,RndLo
 MUL BX
 MOV AX,DX
 ADD AX,RndLo
 RET
ENDP

Seed DW 1111h ; zmienna pomocnicza do generatora
RndHi DW ? ; górny zakres generowanych liczb
RndLo DW ? ; dolny zakres generowanych liczb

By uniknąć cykliczne powtarzanie się liczb, należy zmieniać po pewnej liczbie losowań zmienną Seed, np. według zegarka.

Obsługa klawiatury

Odczyt pojedynczego znaku

Klawiaturę można obsługiwać na dwóch poziomach: BIOSa i DOSa. My zajmiemy się tym pierwszym. Do obsługi klawiatury BIOS daje nam przerwanie 16H. Dzięki niemu mamy pełną kontrole na tym urządzeniem.

Do odczytu pojedynczego znaku służy funkcja 10H, a w przypadku klawiatury podstawowej 0H. Zwraca nam ona w rejestrze AH kod SCAN naciśniętego klawisza. W rejestrze AL dostaniem kod ASCII również tego klawisza. Jeśli podczas wywołania przerwania w buforze klawiatury nie znajduje się żaden znak, to funkcja będzie czekać, aż takowy zostanie naciśnięty. Funkcja również nie wyświetla naciśniętego znaku.

MOV AH,10H
INT 16H


AH - kod SCAN
AL - kod ASCII

Sprawdzenie bufora klawiatury

Bardzo często zachodzi potrzeba sprawdzenia, czy w buforze klawiatury nie znajduje się jakiś znak. Np. jeśli chcemy wykonywać pętlę aż zostanie kliknięty klawisze jest to jedynym rozwiązaniem.

Do tego celu służy funkcja 11H, a przy klawiaturze podstawowej 01H, przerwania 16H. Jeśli w buforze znajdował się klawisz, znacznik Z jest wyzerowany, a w rejestrach: AH - znajduje się kod SCAN i w AL - znajduje się kod ASCII. Jeśli podczas wywołania przerwania w buforze nie było żadnego znaku, znacznik Z jest ustawiony (równy 1).

Funkcja ta po odczycie z bufora kodu znaku nie czyści tego bufora. Znajduje się on w niej, aż zostanie odczytany za pomocą funkcji 10H.

Odczyt stanu klawiszy dodatkowych

Podczas pisania programów zachodzi czasami potrzeba sprawdzenie stanu klawiatury, tzn. sprawdzenie, czy np. CAPS LOCK jest włączony, czy nie. Do tego celu służy funkcja 02H, która w rejestrze AL zwraca kod stanu klawiatury. Poszczególne bity mają następujące znaczenie:

bit 0 - prawy Shift
bit 1 - lewy Shift
bit 2 - Ctrl
bit 3 - Alt
bit 4 - Scroll Lock
bit 5 - Num Lock
bit 6 - Caps Lock
bit 7 - Insert

Funkcja jednak nie rozróżnia klawiszy Alt i Ctrl, czy jest wciśnięty lewy, czy prawy. Znacznie lepszym rozwiązaniem jest użycie funkcji 12H. Wówczas otrzymujemy kod stanu klawiatury w rejestrze AX. Ma on następującą postać:

bit 0 - prawy Shift
bit 1 - lewy Shift
bit 2 - Ctrl
bit 3 - Alt
bit 4 - Scroll Lock
bit 5 - Num Lock
bit 6 - Caps Lock
bit 7 - Insert
bit 8 - lewy Ctrl
bit 9 - lewy Alt
bit 10 - prawy Ctrl
bit 11 - prawy Alt
bit 12 - Scroll Lock
bit 13 - Num Lock
bit 14 - Caps Lock
bit 15 - SysReq

Ustawienie parametrów klawiatury

Przerwanie 16H daje nam również możliwość ustawienia parametrów naszej klawiatury i tak:

AX=0305H
BH= opóźnienie

00H - 0.25s
01H - 0.50s
02H - 0.75s

BL= częstotliwość samo powtarzania

00H - 30 znaków/sek
01H - 27 znaków
02H - 24 znaki
03H - 22 znaki
04H - 20 znaków
itd.

Wstawienie znaku do bufora klawiatury

Dzięki funkcji 05H przerwania 16H mamy możliwość wstawienia znaku do bufora klawiatury. Wówczas w rejestrze CH podajemy kod SCAN, a w rejestrze CL kod ASCII. Po wykonaniu przerwania nie wystąpił żaden błąd znacznik C jest wyzerowany, a AH=0. Gdy wystąpił błąd znacznik C=1 i AH=1.

Obsługa joysticka

Do obsługi joysticka zaliczamy sprawdzenie położenia i stanu przycisków. W tym celu wykonujemy przerwanie 15H, funkcję 84H. Jeśli w rejestrze DX podamy wartość 1, to w odpowiedzi w AX znajdzie się pozycja X joysticka pierwszego, w BX pozycja Y joysticka pierwszego, w CX pozycja X joysticka drugiego i w DX pozycja Y joysticka drugiego. By sprawdzić stan przycisków w DX podajemy 0. W odpowiedzi dostaniemy liczbę w AL. Poszczególne jej bity oznaczają:

bit4 : stan przycisku 1 joysticka 1
bit5 : stan przycisku 2 joysticka 1
bit6 : stan przycisku 1 joysticka 2
bit7 : stan przycisku 2 joysticka 2

joystick.zip - opis programowania joysticka PC 3.67KB

Obsługa myszki

Sprawdzenie statusu myszy

Przed uruchomieniem programy, który ma obsługiwać myszkę, należy najpierw sprawdzić, czy jest ona zainstalowana. Do tego celu, jak i do innych operacji związanych z myszką, służy przerwanie 33H. Funkcja 00H sprawdza status zainstalowania i wynik zwraca w rejestrze AX. Jeśli AX=0H, to myszka nie jest zainstalowana, a jeśli AX=0FFFFH, to jest obecna w systemie i wówczas w BX mamy liczbę przycisków myszy.

Wyświetlenie kursora myszy

Kursor myszy trzeba najpierw odkryć, gdyż po uruchomieniu programu nie jest on automatycznie wyświetlany. Do tego celu służy funkcja 01H przerwania 33H. Na ekranie pokaże się, w zależności o trybu pracy, kursor graficzny lub tekstowy.

Wyłączenie kursora myszy

Czasami zachodzi potrzeba ukrycia kursora myszki. Wówczas stosujemy funkcję 02H przerwania 33H.

Odczyt pozycji i stanu przycisków

Dobra. Wiemy już jak pokazać kursor. Ruszamy myszką i zmienia on swoje położenie, ale jak sprawdzić w jakim aktualnie miejscu się znajduje, albo który klawisz jest wciśnięty? Trzeba posłużyć się funkcją 03H przerwania 33H. Zwraca ona w rejestrze CX wartość przesunięcia kursora względem osi X, a w DX względem osi Y. Kursor jest więc ustawiony o współrzędnych [CX,DX]. W rejestrze BX dostajemy status wciśniętych klawiszy. Bit 0 odpowiada za klawisz lewy, bit 1 za klawisz prawy, a bit 3 za klawisz środkowy.

Ustawienie pozycji kursora myszy

Przerwanie 33H i funkcja 04H dają nam możliwość ustawienia kursora myszy. Dzięki temu możemy programowo przesuwać wskaźnik w prawo i w lewo. Wówczas w rejestrze CX podajemy współrzędną X, a w DX współrzędną Y.

Ustawienie granic dla kursora

Czasami zachodzi konieczność ustalenia granic dla kursora, by np. nie wyjeżdżał za ekran. Należy się wtedy posłużyć funkcją:

AH=07H - ustawianie granic poziomych
CX - numer lewej kolumny
DX - numer prawej kolumny

AH=08H - ustalenie granic poziomych
CX - numer górnego wiersza
DX - numer dolnego wiersza

Ustalenie prędkości dla przesuwania kursora

Przerwanie 33H daje nam całkowitą kontrolę nad myszką. Dzięki funkcji 0FHmożemy ustalić nawet prędkość, z jaką kursor się porusza. Wówczas do rejestru CX podajemy prędkość przesuwania się po osi X, a w DX prędkość przesuwania się po osi Y.

Pamięć

Chyba każdy program posiada jakieś tablica. Zazwyczaj deklarujemy je np. tak:

tablica DB 1024 DUP(0)

Można również zarezerwować pamięć dla danej tablicy. Przydatne jest to szczególnie, gdy wykorzystujemy duże tablice. Do obsługi pamięci służy przerwanie 21H.

Podczas uruchamiania programu, procesor rezerwuje dla niego całą dostępną pamięć, dlatego jeśli chcemy sami ją zadeklarować, musimy najpierw zmniejszyć rozmiar tego bloku. Do tego celu służy funkcja 4AH. W ES podajemy segment rezerwowany, a w BX nowy rozmiar w paragrafach. Po wykonaniu przerwania otrzymamy w rejestrze BX rozmiar największego bloku i jeśli wystąpił błąd (C=1) kod błędu w rejestrze AX.

Do rezerwacji bloku służy funkcja 48H. Wówczas to do BX podajemy rozmiar bloku rezerwowanego. Jeśli wystąpi błąd (C=1) w AX będzie kod błędu, a jeśli nie, w AX dostaniemy segment bloku przydzielonej pamięci. Adres więc naszego wolnego bloku jest: AX:000.

Na koniec pracy naszego programu trzeba zwolnić przydzieloną wcześniej pamięć. Do tego celu używamy funkcji 49H przerwania 21H. Jako parametr podajemy w ES segment zarezerwowanego przy pomocy funkcji 48H bloku.

Operacje na plikach

Tworzenie nowego pliku

Pisząc w dowolnym języku często zachodzi potrzeba stworzenia jakieś pliku, np. z danymi. W Asemblerze nie ma do tego celu żadnych instrukcji (jak i do innych operacji z tym związanych). By stworzyć plik trzeba użyć pewnych przerwań i tak do tworzenia pliku używamy przerwania 21H i funkcji 3CH. Przerwania wykonuje się w Asemblerze za pomocą instrukcji INT, a funkcja jest to wartość rejestru AH. Przed wywołaniem tego przerwania w rejestrze CX podajemy atrybuty naszego pliku (o atrybutach powiemy później), a w DS:DX nazwę, jaką ma mieć. Nazwa ma być zapisana w kodzie ASCIIZ, tzn. musi być zakończona znakiem o kodzie 0, np. jeśli chcemy stworzyć plik o nazwie "PLIK.TXT" napiszemy tak:

MOV AH,3CH
MOV CX,0
MOV DX,OFFSET Nazwa
INT 21H
...
Nazwa DB "PLIK.TXT",0

Jeśli operacja zakończy się sukcesem, to w rejestrze AX znajdzie się numer dojścia do pliku. Jest on bardzo ważny. Identyfikuje on plik, do którego będą później zapisywane dane. Jeśli jednak operacja tworzenia pliku zakończy się niepowodzeniem to zostanie ustawiony znacznik C, a rejestr AX będzie posiadał kod powstałego błędu.

Otwieranie pliku

By otworzyć plik, należy użyć funkcji 3DH przerwania 21H. Jako parametry podajemy: w DS:DX adres do nazwy pliku (ASCIIZ); AL - tryb dostępu. Mamy do dyspozycji następujące tryby:

bitywartośćopis
70Procesy potomne dziedziczą dojście wraz z numerem
4..6000Każdy proces może otworzyć plik wielokrotnie z prawem do pisania i/lub czytania, ale tylko w tym trybie
4..6001Pełna wyłączność. Nie mogą istnieć żadne inne dojścia do pliku.
4..6010Wyłączność pisania, pozostałe dojścia mogą mieć tylko prawo do czytania, jednak nie mogą być otwarte w trybie 000
4..6011Wyłączność pisania, pozostałe dojścia mogą mieć prawo tylko do czytania i mogą być otwarte w trybie 000
4..6100Mogą istnieć inne dojścia z prawem do czytania i/lub pisania, jednak nie mogą być otwarte w trybie 000
0..3000Prawo do czytania
0..3001Prawo do pisania
0..3010Prawo do czytania i pisania

My będziemy zazwyczaj używali trzech trybów:
AL=0 - czytanie
AL=1 - pisanie
AL=2 - czytanie i pisanie

Jeśli więc chcemy otworzyć istniejący plik o nazwie PLIK.TXT napiszemy:

MOV AH,3DH
MOV AL,0
MOV DX,OFFSET Nazwa
INT 21H
...
Nazwa DB "PLIK.TXT",0

Podczas otwierania mogą wystąpić również błędy i wtedy znacznik C jest ustawiany, a AX posiada kod błędu. Jeśli operacja została wykonana poprawnie C=0, a AX zawiera numer dojścia.

Zapis do pliku

Jeśli mamy już otwarty plik i chcemy w nim coś zapisać musimy użyć funkcji 40H przerwania 21H. W rejestrze BX podajemy numer dojścia (uzyskaliśmy go podczas otwierania pliku), w rejestrach DS:DX podajemy adres początku danych, które chcemy zapisać, a w rejestrze CX podajmy ilość bajtów do zapisania. Jeśli operacja zakończy się sukcesem znacznik C jest wyzerowany, a AX zawiera liczbę bajtów zapisanych. Jeśli podczas zapisu wystąpił błąd C=1, a AX zawiera kod błędu. Jeśli więc chcemy zapisać w naszym (otworzonym wcześniej) pliku napis "KURS ASSEMBLERA" napiszemy:

MOV AH,40H
MOV BX,Numer dojścia
MOV DX,OFFSET Napis
MOV CX,15
INT 21H
...
Napis DB "KURS ASSEMBLERA"

Czytanie z pliku

Do czytania z pliku służy funkcja 3FH przerwania 21H. W rejestrze BX podajemy również numer dojścia, CX ilość bajtów, które chcemy przeczytać, a w DS:DX adres bufora, gdzie mają zostać one zapamiętane. Jeśli operacja zakończy się sukcesem w rejestrze AX będziemy mieli ilość przeczytanych bajtów, a znacznik C=0. Ilość przeczytanych bajtów nie musi być równa ilość bajtów, które kazaliśmy przeczytać. Jeśli plik zawiera np. 30 bajtów danych, a my mu każemy przeczytać 50 bajtów, to AX będzie zawierało 30 bajtów.

Zamknięcie dojścia do pliku

Każdy plik, który został wcześniej otwarty trzeba na koniec zamknąć Do tego celu służy funkcja 3EH przerwania 21H. Podajemy w rejestrze BX numer dojścia do pliku , który chcemy zamknąć. Jeśli wystąpi jakiś błąd to znacznik C zostanie ustawiony, a AX zawiera kod powstałego błędu.

Zmiana wskaźnika w pliku

Do ustawiania wskaźnika w pliku służy funkcja 42H. W rejestrze BX podajemy numer dojścia, w AL sposób przesunięcia wskaźnika, a w CX:DX odległość na jaką chcemy przesunąć. Istnieją trzy rodzaje przesunięć:
AL=0 - licząc od początku pliku
AL=1 - licząc od bieżącej pozycji kursora
AL=2 - licząc od końca zbioru

Przesunięcie względem końca zbioru używa się również do obliczania wielkości zbioru, gdyż wynikiem funkcji 42H jest w DX:AX wartość aktualnego położenia (o ile nie wystąpił błąd, wtedy C=1, a AX kod błędu).

Usuwanie pliku

Do usuwania zbiorów z dysku służy funkcja 41H przerwania 21H. W rejestrze DS:DX podajemy nazwę zbioru w kodzie ASCIIZ. Jeśli nie wystąpi błąd znacznik C zostaje ustawiony, a AX zawiera kod powstałego błędu.

Sprawdzenie atrybutów pliku

Jeśli chcemy sprawdzić jakie dany plik ma atrybuty musimy posłużyć się funkcją 43Hprzerwania 21H. Podajemy wówczas w AL wartość 0, a w DS:DX nazwę pliku w kodzie ASCIIZ. Po wykonaniu przerwania w CX będą atrybuty pliku.

Atrybuty mają następujący format:

  • bit0 - tylko do odczytu
  • bit1 - ukryty
  • bit2 - systemowy
  • bit5 - archiwalny

Nadawanie atrybutów pliku

Do nadawania atrybutów dla pliku służy również funkcja 43H. Podajemy teraz w AL wartość 1, w DS:DX nazwę pliku, a w rejestrze CX atrybuty, które chcemy nałożyć.

Zmiana nazwy pliku

Czasami zachodzi potrzeba zmiany nazwy pliku. Wtedy trzeba posłużyć się funkcją 56H. W rejestrze DS:DX podajemy pierwotną nazwę pliku, a w rejestrze ES:DI nową nazwę pliku. Jeśli operacja zakończy się niepowodzeniem zostanie ustawiony znacznik C, a rejestr AX będzie zawierał kod błędu.

Operacje na katalogach

Tworzenie katalogu

Do tworzenia nowych katalogów służy funkcja 39H przerwania 21H. W rejestrze DS:DX podajemy nazwę katalogu (w kodzie ASCIIZ). Jeśli operacja zakończy się błędem, zostanie on przekazany w rejestrze AX i zostanie ustawiony znacznik C

Usunięcie katalogu

Do usuwania katalogów służy funkcja 3AH. W rejestrze DS:DX podajemy wówczas adres nazwy usuwanego katalogu.

Zmiana katalogu

Do ustalania katalogu bieżącego służy funkcja 3BH przerwania 21H. Jako parametr podajemy w DS:DX adres nowej nazwy katalogu.

Pobranie nazwy aktualnego katalogu

Jeśli chcemy dowiedzieć się o aktualnym katalogu bieżącym posłużymy się przerwaniem 21H i funkcją 47H. Jako parametry podajemy w DL numer dysku (o który nam chodzi). Jeśli mamy na myśli dysk bieżący wpisujemy 0, oraz w DS:SI adres 64-bajtowego bufora, w którym ma zostać zapamiętana ścieżka.. Jeśli operacja zakończy się sukcesem w buforze jest ścieżka, w przeciwnym wypadku znacznik C=1, a AX -kod błędu.

Windows

Wykrywanie Windows w pamięci

Podczas programowania zachodzi czasami potrzeba sprawdzenia, czy w pamięci znajduje się Windows, czy pracujemy w środowisku DOS. Można to uczynić wykonując przerwanie 2FH i funkcję 160AH. Jeśli po wykonaniu przerwania w rejestrze AX znajduje się wartość 0, tzn. że jest uruchomiony Windows. Wówczas w rejestrze BX znajduje się jego wersja (BH-numer wersji i BL-podnumer). Jeśli w rejestrze CX znajduje się wartość 2 tzn. że jest uruchomiony tryb standardowy. Jeśli CX=3, to uruchomiony jest tryb rozszerzony 386. Przerwanie to działa jednak tylko pod Windows 3.11 i nowszych.

Blokada klawiszy

Czasami program musi wykonać jakąś operacje, które nie może zostać mu przerwana. Jednak system operacyjny Windows umożliwia przerwanie wykonywania programu kombinacją klawiszy ALT+TAB, lub wciskając CTRL+ESC. By zapobiec takim sytuacjom trzeba użyć funkcji 1681H przerwania 2FH. Powoduje ona włączenie blokady tych klawiszy. By wyłączyć blokadę trzeba wywołać to samo przerwanie, tylko funkcję 1682H.

Monitor

Nowe monitory posiadają możliwość włączenia tzw. trybu czuwania. Jest to znacznie lepsze od wygaszaczy ekranu. Za pomocą przerwania 10H i funkcji 4F10H można sterować pracą monitora. By zmienić stan monitora do rejestru BL wpisujemy 1, a do rejestru BH wstawiamy jedną z następujących wartości:

  • BH=0 - ON (monitor włączony, obraz widoczny)
  • BH=1 - STANDBY (monitor w stanie czuwania)
  • BH=2 - SUSPEND (monitor w stanie uśpienia)
  • BH=4 - OFF (monitor w stanie głębokiego uśpienia)
  • BH=8 0 REDUCED ON (opcja występuje tylko przy niektórych monitorach z płaskim ekranem)

Nieudokumentowane instrukcje PENTIUM

Zliczanie taktów

Do czasu pojawienia się procesorów PENTIUM problemu z obliczeniem, ile procesorowi potrzeba taktów na wykonanie danej procedury, nie było żadnym problemem. Jednak kiedy się one pojawiły problem się również pojawił, gdyż posiadają one architekturę superskalarną, tzn. ilość cykli danego kodu nie równa się sumie cykli poszczególnych instrukcji. Zazwyczaj jest mniej, ale może być również więcej.

Na szczęście procesor PENTIUM posiada jedną instrukcję o nazwie RDTSC (jej kod 0FH 31H), która odczytuje wbudowany 64-bitowy licznik cyklów zegara, który startuje wraz z procesorem. Wystarczy więc odczytać jego wartość na początku procedury, później na końcu, odjąć jedno od drugiego i koniec! Oto przykład:

.DATA
  Cykle_L DD 0
  Cykle_H DD 0
.CODE
  ...
  DB 0FH, 31H
  MOV Cykle_H,EDX
  MOV Cykle_L,EAX
  ...
  ...
  DB 0FH, 31H
  SUB EAX,Cykle_L
  SUB EAX,9		; odliczenie RDTSC
  SBB EDX,CykleH
  ...

Autor: Karol Wierzchołowski, opracowano: 12.01.2002 r. Wszelkie prawa zastrzeżone.
Kontakt

Jeśli chcesz się z nami skontaktować napisz na adres: info(at)binboy.org lub odwiedź nasz profil na Facebooku!

O Nas

Serwis binboy.org to kopalnia wiedzy dla wszystkich z branży IT, w szczególności dla programistów i webmasterów. To duży zbiór kursów programowania, tutoriali, darmowych ebooków, setki kodów źródłowych itp.

Bądź w kontakcie

Panel użytkownika

Zaloguj się do panelu użytkownika.
Nie masz konta? Zarejestruj się!
Zapomniałeś hasła?