;**************************************************************************** ;*** prog1.asm *** ;*** Det första programmet: *** ;*** Att skriva ut ett *** ;*** meddelande på skärmen *** ;*** i ASSEMBLER!!! *** ;****************************************************************************
DOSSEG ;Dela upp minnet i segment precis som dos gör
.MODEL SMALL ;välj vilken minnesmodell programmet ska ha
.STACK 100h ;definiera en stack på 256 bytes (100 hex)
.DATA ;Här börjar datasegmentet ;(deklarera variabler, strängar m.m.)message db 'Denna text kommer från ett assemblerprogram!',13,10 db 'Känns det lika skönt för dej som för mej?',13,10 db 'Moralisk stödperson:',13,10 db '*** Abeman babebeard ***',13,10 db 'e-mail: dat94avi@idt.mdh.se',13,10,'$'
.CODE ;kod segment
START: ;start är en label som markerar en plats i minnet
------------------------------- KLIPP HÄR -----------------------------------
Ok låt oss nu börja från början och gå igenom programmet steg för steg. Allting efter ett semikolon betyder kommentar och ignoreras av assemblatorn. Det första som står i själva programmet är alltså:
DOSSEG
DOSSEG sorterar segmenten efter DOS standard, vad det betyder behöver man
inte bry sig om. Skriv bara DOSSEG överst i programmet.
Nästa rad är:
.MODEL SMALL
Detta anger vilken minnesmodell som skall användas.
Följande minnesmodeller finns att välja på:
TINY: Code + Data < 64K SMALL: Code < 64K Data < 64K MEDIUM: Code > 64K Data < 64K COMPACT:Code < 64K Data > 64K LARGE: Code > 64K Data > 64K maximal arraystorlek < 64K HUGE: Code > 64K Data > 64K maximal arraystorlek > 64KMaximal arraystorlek spelar endast roll när man länkar ihop assemblerprogrammet med ett c-program.
.STACK 200h
Sätter upp en stack på 200 hex (512 bytes) vid exekveringen men påverkar inte storleken på exe-filen. På stacken kan man lagra data med PUSH instruktionen och hämta tillbaka data med POP. OBS!!! stacken arbetar enligt principen sist in först ut, vilket innebär att man måste poppa data i omvänd ordning mot när man pushade dem.
EX PUSH AX PUSH BX PUSH CX . . . POP CX POP BX POP AXOm man hade poppat i samma ordning som man pushade skulle AX och CX bytt värden. Stacken används också till att lagra återhoppsadresser vid subrutiner så att programmet vet var det ska fortsätta efter en subrutin.
.DATA
Säger åt assemblatorn att datasegmentet börjar här. I datasegmentet lagrar man sina variabler, strängar, sinuslistor, palletter och alla andra data man kan tänkas behöva.
MESSAGE DB 'Bla Bla Bla',13,10 DB 'Bla Bla Bla','$'
MESSAGE är ett strängnamn ungefär som om man hade skrivit char MESSAGE[25]; i C. DB betyder Declare Byte vilket betyder att det reserveras en byte för varje tecken eller tal som kommer efter på raden. ' tecknen betyder att assemblatorn ska lagra ascii-koden för tecknen, stora B har tex ascii-koden 66. 13,10 är ascii-koderna för ny rad och återvänd till början på rad (motsvaras av \n i printf-kommandot i C). $ tecknet är strängavlutnings-tecknet som används av utskriftsrutinen längre ner (int 21h funktion nummer 9).
Observera att strängen fortsätter ända till '$' tecknet (även fast man börjar på ny rad med db 'Bla Bla' osv), om man glömmer '$' kommer det skrivas ut en massa konstiga tecken på skärmen tills datorn hittar ett $-tecken någonstans i minnet (efter message).
Man kan ändra i strängen under körningen av programmet. Om man skriver t.ex MOV [MESSAGE],'A' kommer första bokstaven i strängen bytas ut mot ett A.
.CODE
Här börjar Kod segmentet, det är här man skriver själva programmet.
START:
Start är bara en label. En label kan ha vilket namn som helst och följs av ett : (kolon). Lablar används för att referera till olika platser i programmet. Lablarna byts ut av assemblatorn till relativa adresser vid assembleringen. Om man skriver JMP START kommer datorn hoppa till den positionen i programmet, ungefär som om man skrivit 'GOTO START' i BASIC.
MOV AX,@DATA MOV DS,AX
Flyttar datasegmentets adress till segmentregister DS, Vilket är en bra idé eftersom DS brukar användas just till att peka ut datasegmentet. OBS! det går inte att skriva mov ds,@data direkt, någon sådan instruktion existerar inte i PC assembler (mov segmentregister, värde).
MOV AH,09 ;flytta talet 9 till ah MOV DX,offset message ;flytta message's offset till dx INT 21h ;anropa int 21h, funktion nummer 9
INT n anropar avbrottsrutin nummer n (det finns massor att välja på). En avbrottsrutin är som ett underprogram, ungefär som en funktion i C.
Int 21h är en samling DOS funktioner som hanterar bl.a inmatningar från
tangentbordet och utskrift till skärmen. För att välja vilken funktion man
vill anropa lägger man funktionsnumret i ah, och anropar funktionen med
int 21h.
Funktion nummer 9 i int 21h skriver ut en sträng på skärmen. Innan man
anropar int 21h lägger man talet 9 i ah och adressen till det som ska skrivas
ut i ds:dx.
En minnesadress är (som jag sagt tidigare) indelad i segment och offset. Det
fungerar så att:
adressen = segment*4 + offset
och skrivs som:
segment:offset.
int21h funk # 9 vill alltså ha adressen till strängen så att segmentet är i
ds och offseten i dx (ds:dx).
Strängen skall avslutas med ett '$' tecken, annars blir det tivoli.
mov ax,4c00h ;ah = 4ch, al = 0 int 21h
Ännu en int 21h funktion. Funktion # 4ch Lämnar tillbaka kontrollen till DOS. Om man inte utför int 21h funktion #4ch kommer programmet att hänga sig, datorn dyker, vilket för övrigt inte är särskilt ovanligt när man programmerar assembler (om man inte heter Abe förstås :-)). Det finns massor av andra int funktioner att läsa om i olika interruptlistor. Där brukar det stå ganska bra beskrivet hur man väljer funktion o.s.v.
END START
Detta säger åt assemblatorn att programmet är slut och att programmet ska börja köras vid labeln start.
Det var det hela! Om du tycker att det ser komplicerat ut i början, oroa dig inte för det. Man kommer in i tankebanorna efter ett tag, speciellt när man sett några olika program, likheterna och skillnaderna. Så gott som hela det här programmet, utom message och utskriften i mitten, kommer igen i vartenda assemblerprogram. Man kan använda det här programmet som en mall, klippa och klistra in början och slutet som alltid ser likadant ut.
Det går förstås att skriva ut en text på skärmen utan interrupt 21h. Vad man gör är att skriva direkt i skärmminnet, som dessutom går mycket snabbare än int 21h. Exakt hur detta går till beror på vilket grafikläge man befinner sig i. Jag tänker gå igenom olika grafiklägen litet närmare i program 2.
snailmail: Albert Veli spisringsg. 9 724 76 VÄSTERÅSmail:dat94avi@bilbo.mdh.se.