ASSEMBLER A SYSTÉM
Ahoj, tady je Joe of Agony. Jsem zde, protože minulí člověkově, kteří měli
psát tuhle rubriku, ji psát přestali. To způsobilo menší změnu, doufám že k
lepšímu... a teď jste v moci šíleného programátora, který za truchlivých nocí v
bledé záři monitorů... No nic. Každopádně o nic nepřijdete! Pokusím se navázat
na úvod, který po sobě zanechal můj předchůdce, a splnit co vám nasliboval...
(plán splníme, ba překročíme!) Howgh!
V minulé části tohoto seriálu jste (snad) získali jakouž takouž představu o
dvojkové a šestnáctkové soustavě a o tom, k čemu jsou dobré a bylo vám
předhozeno něco informací o procesoru, registrech, paměti atd. Pro jistotu
udělám malé shrnutí, na které navážu snůškou dat ohledně programování v
assembleru...
Procesor, a to stále ještě obecně
Jak už jistě víte, procesor řady MC68000 se z pohledu systémového
programátora (programátora, který ihned nezlikviduje systém jen proto, že s ním
neumí spolupracovat) jeví jako skupina registrů. Jsou to:
- Adresové registry A0-A7,
- Datové registry D0-D7,
- Stavový registr SR
Procesor obsahuje i jiné registry, ty však jsou většinou přístupné jen ze
Supervisor-módu nebo jejich změna může vážně narušit funkci celého systému,
takže je raději necháme na pokoji. K jejich ovládání nabízí systém speciální
služby.
Datové registry
Datové registry D0-D7 jsou 32-bitové, ale s každým z nich lze pracovat jako
by byl 8, 16 nebo 32 bitový. To znamená, že v nich lze uchovávat a zpracovávat
BYTE, WORD i LONG. Tyto registry jsou vlastně jakousi "pracovní oblastí", ve
které se provádí naprostá většina výpočtů a operací prováděných programem.
Výhodou práce s registry je jejich RYCHLOST. Je to proto, že tyto registry má
procesor "po ruce", kdežto přístup do paměti je mnohem pomalejší. Je proto
krajně výhodné na začátku zpracování data načíst do datových registrů procesoru,
tam s nimi provést požadovanou operaci, a potom výsledek uložit zpět do paměti.
Stavový registr SR
Stavový registr je z pohledu USER-mode velký pouze 5 bitů. Těchto 5 bitů
jsou tak zvané "příznaky" nebo "flagy". Jsou to jednotlivé bity, které jsou
nastavovány po provedení některých operací procesoru podle výsledků těchto
operací. Tyto příznaky je pak možno testovat a na jejich základě provést nebo
neprovést nějakou operaci (např. skok na jiné místo programu). Tyto flagy jsou:
X, N, Z, V, C.
Každý flag je nastavován za jiných podmínek a znamená něco jiného.
- "Z" (zero) je příznak který je nastavován v případě, když výsledek předchozí
operace byl roven nule. Bude to asi váš nejvíce používaný příznak:.
- "N" (negative) je nastaven, pokud nejvyšší bit výsledku předchozí operace je
roven 1. Pokud se tedy na onen výsledek díváme jako na číslo se znaménkem, "N"
je nastaven, byl-li tento výsledek záporný (tj. menší než 0).
- "C" (carry) je nastaven, pokud došlo při minulé operaci k "přetečení"
výsledku. To se například může stát, když k BAJTU, (ed. BAJT je BYTE - OK? Vše
jasné? Nebudu to přeci všude opravovat...) který má hodnotu 255 ($FF) přičtete
1. 255+1 = 256, ($FF+$01=$100). Hodnota 256 je už příliš velká, aby se vešla do
8 bitů BAJTU, a proto bude nejvyšší bit výsledku ztracen. Nejlépe je to vidět na
šestnáctkovém zápisu této operace: $FF+$01=$100, ale v bajte zůstanou jen dvě
poslední číslice výsledku. Devátý bit (který je navíc) je přenesen do příznaku
"C". U odečítání je tomu podobně - když dojde k přetečení, příznak je nastaven.
Tento případ se vztahuje k HODNOTÁM BEZ ZNAMÉNKA. Příznak "C" se nastavuje i
jinými operacemi, více o tom při popisu těchto operací.
- "V" (overflow) se používá v případě, když výsledek je hodnota SE ZNAMÉNKEM.
Jeho funkce je obdobná jako u příznaku "C", ten však byl pro hodnoty bez
znaménka. Protože procesor neví, jestli na výsledek hledíme jako na číslo se
znaménkem nebo bez znaménka (a v podstatě je mu to jedno), nastavují se podle
operace jak "C" tak i "V" a je na nás, který z nich nás zajímá (protože my víme,
je-li to hodnota se znaménkem nebo bez). Rozdíl je v tom, že přenos "carry"
nastává jindy než přenos "overflow". Nejlépe to ozřejmí příklad: Mějme BYTE SE
ZNAMÉNKEM (A) a BYTE BEZ ZNAMÉNKA (B). Jak víte, rozsah (A) je od -128 do +127,
rozsah (B) od 0 do 255. Jak (A) tak i (B) budou mít hodnotu 126 ($7E). Co se
stane, když k (A) i (B) přičteme 3? V případě (A) dostaneme
126($7E)+3=129($81),což je mimo rozsah. Bude tedy nastaven příznak přenosu
(overflow) a výsledná hodnota (A) bude po operaci -127($81). V případě (B)
dostaneme 126($7E)+3 = 129($81), což je v platném rozsahu, takže příznak přenosu
(carry) nastaven nebude. Všimněte si, že v obou případech je šestnáctková
reprezentace čísel stejná, rozdíl je pouze ve způsobu, jakým tyto hodnoty
interpretujeme.
- "X" je v podstatě místo na přebývající bit při přetečení při sčítání a
odčítání a jiných operacích. Tento bit je ovlivňován mnohem menším okruhem
operací než "C" nebo "V", což je výhodné, protože hodnota tohoto příznaku nemusí
být nikam ukládána než se použije. Více při popisu operací ovlivňujících tento
příznak.
Popisy významů které jsem uvedl jsou samozřejmě jen ty nejpoužívanější -
existují výjimky... více o tom v popisu jednotlivých operací .
Adresové registry
Adresové registry A0-A7 jsou všechny 32 bitové. Používají se (jak už sám
jejich název napovídá) k ukládání ADRES. Adresa, jak bylo už řečeno minule,
jednoznačně identifikuje místo v paměti, se kterým chceme pracovat. Více o tom v
části zabývající se adresovacími módy. Registr A7 (nazývaný také SP nebo USP) se
používá jako ukazatel zásobníku. Tento zásobník se používá na ukládání
návratových adres při skocích do podprogramů, na ukládání obsahu registrů
procesoru když víme, že je budeme za chvilku ještě potřebovat, případně se na
zásobníku vyhrazuje místo na dočasné proměnné, například v rámci jednoho
podprogramu. Zvláštností adresových registrů je, že při operacích s nimi
většinou NEJSOU podle výsledků nastavovány příznaky v registru SR. To většinou
ušetří ukládání příznaků v případě, kdy třeba po testovací operaci (která
nastaví příznaky) potřebujeme ještě načíst nějakou adresu do adresového
registru. Na rozdíl od datových registrů nelze s adresovými registry pracovat
jako s BAJTY nebo WORDY. Nic nám však nebrání v jejich využití třeba k dočasnému
uložení obsahu některého datového registru, když se nám datových registrů
nedostává.
Co s registry?
Procesor umožňuje všechny registry (tím myslím datové a adresové) navzájem
vyměňovat a kopírovat data z jednoho do druhého. S datovými registry lze
provádět spoustu různých operací, jak si později ukážeme. S adresovými registry
lze provádět o něco méně operací, je to však dáno jejich určením.
Paměť, taktéž obecně
Co se týče paměti, jejím účelem je uchovávat informace pro procesor,
případně pro jiné čipy, které do ní mají přístup. Ze strany procesoru se paměť
jeví jako hromada očíslovaných políček, ze kterých může procesor číst data nebo
do nich data zapisovat. Každé toto políčko je velké 1 BYTE. Každý byte má svoji
ADRESU. Je to číslo, kterým se procesor odkazuje na tento určitý byte paměti. U
MC68000 může toto číslo být velké 24 bitů, u vyšších procesorů je to 32 bitů.
Celý rozsah všech možných adres se nazývá ADRESNÍM PROSTOREM PROCESORU. U
MC68000 je to 16 megabajtů, u vyšších procesorů dokonce 4 gigabajty. Je to tedy
víc než dostatečný rozsah, který, jak zcela jistě tušíte, není zcela využit.
Celý adresní prostor je u Amigy rozdělen na jakési "oblasti". V některých těchto
oblastech buď není VŮBEC NIC, nebo tam může být paměť, případně speciální
registry ostatních čipů Amigy, prostřednictvím kterých je procesor ovládá. Tyto
registry se procesoru v podstatě jeví jako normální paměť. Některé tyto registry
se dají jenom číst, do jiných lze jen zapisovat a ještě jiné lze číst i
zapisovat. Rozdíl mezi těmito řídícími registry a obyčejnou pamětí je v tom, že
v paměti se jen ukládá to, co tam procesor naposledy zapsal, kdežto když
procesor něco zapíše do řídícího registru některého čipu, tento čip se to
okamžitě dozví, přečte si to a podle toho provede nějakou operaci. Například
když zapíšete nějaký bajt do registru obvodu CIA, který má na starosti paralelní
port. Data která tam procesor zapsal se ihned objeví v podobě elektronických
signálů na konektoru paralelního portu a navíc se ještě generuje impuls, který
uvědomí dejme tomu tiskárnu, která je na paralelním portu připojena, že si má
převzít nová data. O ovládání hardware prostřednictvím těchto registrů si povíme
ve zvláštní kapitole.
Ještě k paměti. Existují v podstatě dva základní druhy paměti - RAM a ROM. Paměť
RAM slouží k uchovávání informací po dobu, kdy je počítač zapnutý. Po vypnutí
napájení je její obsah nenávratně ztracen. Procesor do ní může data zapisovat i
z ní data číst. Oproti tomu paměť ROM byla při její výrobě napevno naplněna
daty, která tam zůstávají i po odpojení napájecího napětí. Paměť ROM je možno
pouze číst. Musím vás ještě upozornit na organizaci paměti. Jak už víte,
procesor umí pracovat s daty (čísly) širokými 8 (BYTE), 16 (WORD) nebo 32 (LONG)
bitů. Je třeba si uvědomit, že paměť jako taková se skládá z BAJTŮ jenom
LOGICKY. Ve skutečnosti procesor MC68000 vzhledem ke své 16-bitové vnější
architektuře může k paměti přistupovat jen po CELÝCH WORDECH. Vypadá to asi
takhle:
- 16 bitů = 2 bajty -
( adresa 0 ) ( adresa 1)
( adresa 2 ) ( adresa 3 )
( adresa 4 ) ( adresa 5 )
.. atd ...
Vnitřek závorky představuje 1 BAJT. Procesor načítá z paměti vždycky celý WORD
ze SUDÉ ADRESY. Pokud načítáme BAJTY, nic se neděje. Když třeba chce procesor
načíst bajt z adresy 3, přečte prostě celý WORD z adresy 2, který v sobě
obsahuje bajt z adresy 2 i bajt z adresy 3. Na bajt z adresy 2 se procesor
prostě vykašle a nechá si jenom bajt z adresy 3. Horší situace nastane, čteme-li
WORD nebo LONG. Pokud čteme WORD ze SUDÉ ADRESY (např. z adresy 4), všechno je
OK, procesor ho načte celý najednou. Katastrofa ovšem nastává, pokud se pokusíme
načíst WORD z LICHÉ ADRESY (třeba 3). Jak víte, word jsou v podstatě 2 bajty.
JENŽE: První bajt kýženého wordu je součástí wordu paměti na adrese 2, kdežto
druhý byte našeho wordu je umístěn ve wordu paměti na adrese 4!!! S tímto faktem
se MC68000 neumí vypořádat, a přejde tudíž do chybového stavu, jehož výsledkem
je zhroucení vašeho programu. LONG načítá MC68000 jako dva WORDY za sebou, tudíž
je tu stejný problém. Co s tím? Na to je jednoduchá odpověd` prostě nebudeme
dávat žádné WORDY ani LONGY na liché adresy Tomuto opatření se říká ALIGNMENT,
čili česky řekněme ZAROVNÁVÁNÍ. V assembleru existují prostředky, které nám
alignment umožňují. Chtěl bych ještě upozornit, že samotné INSTRUKCE PROCESORU
se skládají z WORDŮ. Na to pozor, ani samotný program nesmí být na liché
adrese!!! U procesorů MC68020 a lepších byl tento problém odstraněn tím, že se
čtení prostě provede dvakrát a načtená data se složí dohromady. Vzhledem k tomu,
že přístup do paměti je ta nejpomalejší věc, co může procesor dělat, je pořád
výhodné zarovnávat data na násobky 2. NAVÍC: MC68020+ procesory mají 32-bitovou
vnější architekturu, takže jejich přístup do paměti probíhá dokonce po celých
LONGách (lonzích? longs? Sakra, pokud jde o odborné výrazy, čeština nám moc
nepomůže... Takže: Pokud to ještě neumíte, začněte se UČIT ANGLICKY!!! To myslím
zcela vážně, protože ďábelský programátor se bez dobré znalosti angličtiny
prostě neobejde! Angličtina je tradičně jediným univerzálním počítačovým
jazykem. Programátory, co udělají geniální program, ale jenom ve svahilštině, u
nás v Kansas City věšíme!!!). Takže zpět k tématu. Větší šířka datové sběrnice
(32 bitů) přispívá samozřejmě k vyšší rychlosti, protože třeba celý LONG je
možné načíst najednou. Ale zase - JEN Z ADRESY, KTERÁ JE NÁSOBKEM 4! Vypadá to
zase nějak takhle:
32 bitů = 4 bajty
(adresa 0) (adresa 1) (adresa 2) (adresa 3)
(adresa 4) (adresa 5) (adresa 6) (adresa 7)
(adresa 8) ..... atd .........
Obecně, tedy z pohledu programátora který chce aby jeho geniální programy
fungovaly maximálně, budeme tedy pokud možno všechny LONGY zarovnávat na adresy
o násobcích 4, a všechny WORDY na adresy o násobcích 2 (tedy sudé). To pokud jde
o data. Co se týče začátku programu, doporučuji zarovnávat ho na násobky 4, aby
se zbytečně nečetl word těsně před programem...
Program v assembleru a assembler
Aby se mi lépe vysvětlovala adresace, naučíme se něco o tom, jak vlastně
vypadá program v assembleru, abychom si mohli zkoušet malé příkládky. Program v
assembleru je v podstatě textový soubor, obsahující popis operací procesoru v
textové formě, který je dobře čitelný pro člověka. Pro procesor však není
čitelná ani trochu, je potřeba tento textový soubor PŘELOŽIT do strojového kódu,
kterému procesor rozumí (ale zase člověk ani trochu). K tomuto překladu slouží
program nazývaný ASSEMBLER. Tady je vidět, jak se směšují různé pojmy -
assembler znamená jak PROGRAM, kterým přeložíme zdrojový textový soubor do
spustitelného binárního souboru (tzv. executable, čili v hantýrce "exáče"), tak
i samotný symbolický jazyk, ve kterém je tento textový soubor napsán. Tento
executable soubor je pak při jeho spuštění načten do paměti RAM a spuštěn.
Samotný běh programu vypadá tak, že procesor postupně od začátku programu vybírá
z paměti instrukce tak jak jdou za sebou a ihned je vykonává. Existují různé
typy instrukcí - přesuny dat, matematické a logické operace, různé skoky, v
programu. Umění programátorovo spočívá tedy v umění rozložit nějaký složitý
program na tyto jednotlivé kroky, aby procesor při jejich vykonávání dělal
přesně to, co po něm chceme. Pokud chcete vidět nějaký executable soubor, stačí
se kouknout do adresáře "C" vašeho Workbenche. Spouštění vašich programů je na
Amize možné v podstatě dvěma způsoby - z CLI napsáním jména vašeho programu a z
Workbenche dvojím nakliknutím ikony vašeho programu. Než si povíme něco víc o
multitaskingu a systému, budeme používat pouze první způsob - CLI (tedy spíš
Shell, ne? Nemyslím že by byl dobrý nápad matlat se s programováním pod OS 1.3!
Kdo máte starou A500 a myslíte to s programováním vážně, doporučuji prodat A500
nějakému balíkovi na hraní a zakoupit fungl novou A1200, pokud možno s
harddiskem alespoň 60 MB, jako mám já. Tedy - úplně nejraději si ji nechte
přivézt z Německa, protože některé firmy u nás prodávají bez uzardění počítače
nakoupené jakožto VADNÉ jako NOVÉ!!! Jeden můj kamarád byl vracet novou A1200
ČTYŘIKRÁT, pokaždé mu ji vyměnili, pokaždé mu dali jinak vadnou, a počtvrté
dostal tu co mu dali poprvé... (prostě Zkopaná Amiga) byl z toho tak zblblej, že
si tu čtvrtou NECHAL i přes vadný floppy drive a bootuje přes externí mechaniku
- TAKŽE POZOR!!! Zpět k assemblerům. Existují v podstatě dva typy assemblerů:
První jsou programy spouštěné z Shellu podobně jako příkazy AmigaDOSu, které
jako parametr dostanou jméno textového souboru a vygenerují z něj executable.
Druhým typem jsou assemblery s vestavěným textovým editorem, jako je například
AsmOne/TRASHM One, doporučovaný vám mým předchůdcem. Já osobně tento program
považuji za značně NEVHODNÝ pro naše účely, a to ze dvou důvodů:
1) Je STARÝ a umí jen instrukce MC68000 neumí novější procesory (viděl jsem sice
verzi která je umět měla, ale byla natolik nestabilní, že k jejímu zhroucení
stačil pouhý stisk klávesy RETURN v editoru - fuj!
2) AsmOne má sice hezké prostředíčko, jenže neexistuje v něm způsob, jak LEGÁLNĚ
SPUSTIT PROGRAM - tj. jakoby z CLI nebo z Workbenche. Pokud program lze spustit
v ASMONE, nelze ho spustit z Workbenche a obráceně - nakonec vám nezbude než
program dost nepohodlně uložit na disk a spustit ho z CLI. Tahle vlastnost
degraduje AsmOne/TRASHM One na prostředek na psaní a zkoušení krátkých rutinek
pro MC68000. Ze začátku by se nám mohl docela hodit, ale není to nic na psaní
větších systémových programů (ed. většina skvělých dem je však napsaná v
Trashovi).
Já osobně preferuji assemblery prvního druhu, protože v kombinaci s vhodným
textovým editorem se vyrovnají druhému druhu, toto spojení je však lehce
upravitelné a univerzálnější. Navíc se s ním lépe vytváří větší programy (s
pomocí linkeru a knihoven...) Asi nejlepší assembler, co jsem zatím viděl, je
podle mne DEVPAC verze 3.04, protože obsahuje jak integrované prostředí, ve
kterém je možné pracovat jako v AsmOne, ale bez výše uvedených nedostatků, tak i
assembler který je možné používat z CLI. Navíc balík obsahuje i debugger. Devpac
je však komerční produkt a u nás ho těžko seženeme, takže se budeme muset
poohlédnout v oblasti shareware. Odtud bych doporučil PhxAss V4.00, který by
snad mohl být k dispozici na PD discích od Atlantidy. Našel jsem ho na Aminetu v
síti Internet. Protože se různé assemblery v detailech liší, pokusím se všechny
příklady koncipovat tak, aby fungovaly pokud možno všude.
Způsob zápisu programu v Assembleru
Jak jsem se už zmínil, program v assembleru je textový soubor. Tento textový
soubor je organizován po řádcích. Na každém řádku programu může být maximálně
jedna instrukce nebo pseudoinstrukce. Instrukce je textové vyjádření nějaké
operace procesoru, která má být na tomto místě programu. Pseudoinstrukce je také
instrukce, ale ne pro procesor, ale pro ASSEMBLER který tento program překládá.
Právě v pseudoinstrukcích bývají největší rozdíly mezi různými assemblery,
protože narozdíl od instrukcí procesoru pseudoinstrukce nebyly nijak
standardizovány. Jeden řádek programu v assembleru by mohl vypadat například
takto:
Start MOVE.L #123456,D0 ;d0=123456
Na tomto řádku vidíme několik věcí:
- "Start" na začátku řádku je takzvaný LABEL [lejbl] (česky návěstí). Je to
jakási značka, odkazující na určité místo v programu. Pokud bychom chtěli
provést v programu skok právě na tento řádek, odkázali bychom se na něj právě
pomocí návěstí "Start".
- "MOVE.L" je takzvaný OPCODE ("MOVE") následovaný příponou ".L". Opcode je
jakýmsi kódem označujícím požadovanou operaci procesoru. V tomto případě je to
"move", což je kód pro přesun (kopírování) dat ze zdrojového operandu do
cílového operandu. Přípona za tečkou udává, jaký typ nebo velikost mají
kopírovaná data - zdali je to BYTE, WORD nebo LONG. Zcela neočekávaně první
písmena názvů souhlasí s příponami. Teď už tedy víme, že tato instrukce bude
přesouvat jeden LONG odněkud někam.
- "#123456,D0" jsou parametry čili operandy pro daný opcode. V podstatě určují,
s čím bude daná operace prováděna. V našem případě je to zdrojový operand
"#123456" a cílový operand "D0", oddělené čárkou. Zdrojový operand je vždy
uveden VLEVO, cílový VPRAVO (podle vzoru CO,KAM). "#123456" tady znamená
KONSTANTU 123456. "D0" je označení REGISTRU D0. Protože u opcode byla přípona
".L", bude výsledkem celé instrukce zkopírování konstanty 123456 (32 bitů-LONG)
do registru D0, čili nastavení D0 na hodnotu 123456. Jasný?
- ";d0=123456" je komentář, stručně vysvětlující instrukci. Komentáře jsou vždy
za instrukcí a začínají středníkem. Komentářem je vše co je na řádku za
středníkem až do konce řádku. Existuje ještě jeden druh komentáře, a to řádek
začínající hvězdičkou. Tady si ale nejsem jist jestli to funguje pro všechny
assemblery.
Když to tedy shrnu, je řádek v podstatě rozdělen na několik polí:
<návěstí> <opcode> <operandy> <komentář>
Návěstí musí začínat vždy bezprostředně na začátku řádku. Samozřejmě návěstí je
jen na těch řádcích, na které se chceme odněkud odkazovat. Samozřejmě nemohou
být dvě návěstí na jednom řádku. Pokud bychom z nějakého důvodu chtěli mít na
nějakém místě programu dvě návěstí, uděláme to takto:
<návěstí1> <návěstí2> <zbytek řádky....>
Na řádku nemusí být opcode, potom jsme pořád jakoby na stejném místě programu.
Operandy se různí podle opcode (žádný, jeden, dva...)
Prográmek na závěr
Abyste měli nějakou představu, jak program v assembleru vypadá, a abyste
viděli už konečně něco, co "něco dělá", tak tady je malinký prográmek, který
existuje snad ve všech programovacích jazycích. Opište ho do textového souboru
jménem "Hello.asm" a přeložte... pro PhxAss by překlad vypadal asi takto:
1> PhxAss Hello.asm
PhxAss MC680x0/68851/6888x Macro Assembler V4.00 Written by F.Wille (Herford,
GERMANY) in 1991-94 Pass 1 Pass 2 00 No error.
44 lines in 0.07 sec = 37714 lines/min.
Global symbols: 12
Local symbols: 2
Bytes gained by optimization: 4
Code: 1 section(s) 87 bytes
Data: none
BSS: none
1> hello
Nazdar mamlasos!
1>
;=========================
;Hello.asm - malý testík
;=========================
;exec.library:
_LVOOpenLibrary = -552
_LVOCloseLibrary = -414
;dos.library:
_LVOOutput = -60
_LVOWrite = -48
section prg,code
START move.l 4.w,a6 ; báze exec do a6
lea dosname(pc),a1 ; jméno dos.library
moveq #0,d0 ; jakákoli verze
jsr _LVOOpenLibrary(a6) ; otevřít
tst.l d0 ; mám dos.library?
beq .fuj1 ; ne->padám
move.l d0,a6 ; jo->do a6 s ní
jsr LVOOutput(a6) ; zjistit výstup
move.l d0,d1 ; mám ho v D1?
beq .fuj2 ; ne->padám
move.l #text,d2 ; adresu textu do d2
move.l #textlen,d3 ; délku textu do d3
jsr _LVOWrite(a6) ; Vypsat
.fuj2 move.l a6,a1 ; dosbase do a1
move.l 4.w,a6 ; execbase do a6
jsr LVOCloseLibrary(a6) ; zavřít dos
.fuj1 moveq #0,d0 ; normální kód
rts ; skončit
dosname dc.b "dos.library",0 ; jméno dosu
text dc.b "Nazdar mamlasos!",10 ; text,<LF>
textlen equ *-text ; výpočet délky textu Vytlačiť článok
Pozn.: články boli naskenované ako text a preto obsahujú aj zopár chýb. Taktiež neručíme za zdrojové kódy (Asm, C, Arexx, AmigaGuide, Html) a odkazy na web. Dúfame, že napriek tomu vám táto databáza dobre poslúži.
Žiadna časť nesmie byť reprodukovaná alebo inak šírená bez písomného povolenia vydavatela © ATLANTIDA Publishing
none
|