Moi
Ongelmana assembly muuttuja.
Kohdat
inc
cmp
mov
aiheuttavat errorin:
laskuri.asm:9: error: invalid combination of opcode and operands
Eli siis kaipaan vinkkiä kuinka tämä pitäis tehdä.
[org 100h] ;Dos call laskurinollaksi ;nollataan laskuri jotta päälooppi toimii oikein call paalooppi ;avataan päälooppi paalooppi: inc laskuri ;kasvatetaan laskuria cmp laskuri, 360 ;verrataan joko on kierretty ympytä ja laskurinollaksi ;jos on nollataan call paalooppi ;aloitetaan alusta laskurinollaksi: mov laskuri, 0 ;nollataan laskuri ret ;palataan takaisin kutsukohdan alle laskuri: db 360
Sain ratkaisut ongelmiin:
laskuri on vain osoite. [laskuri] on muuttujan sisältö.
tämän jälkeen tuli koko ongelma:
Kääntäjä ei tiedä kuinka suurta osaa käytetään mm. vertailussa
korjaus
cmp word [laskuri], 360
ja vielä viimeinen ongelma oli laskurimuuttujan koko (yksi tavu) johon mahtuu numero 255 asti joten päästäksemme 360 tarvittiin sana:
laskuri dw 360
Kiitos avuista, Viznut ja Lumpio- irkin puolella
Et mainitse mitä assembleria käytät, syntakseissa on eroja.
Pieniä huomioita: Kannattaisi ehkä miettiä ohjelman logiikka uusiksi, nyt toimii hassusti... Kannattaa karsia turhat kutsut pois, minimoida hypyt ja järjestellä siten, että yleisimmässä tilanteessa "pudotaan läpi" eikä hypätä. Miksi kutsut pääloopin lopussa päälooppia etkä vain hyppää sinne? ja alussa turha kutsua sitä, jos ohjelman suoritus jatkuu siitä muutenkin.
Kannattaa panostaa koodin luettavuuteen, mikä assemblerin kanssa touhutessa voi olla paljon parempi, kuin C++:lla ja muilla korkean tason kielillä.
Alla esimerkki:
; ; Simppeli testiohjelma DOSsille, mikä muuntaa ja kirjoitttaa ruudulle ; luvun 123 heksamuotoisena (=0x7B) ; .model small .stack 1024 .data luku db 123 etuliite db '0x' heksaluku dw ? db "$" .code main: mov, ax, _DATA mov ds, ax muunna: mov al, [luku] aam 16 @digit2: add al, 090h daa adc al, 040h daa @digit1: xchg al, ah add al, 090h daa adc al, 040h daa @talteen: mov [heksaluku], ax ruudulle: mov dx, offset etuliite mov ah, 09h int 21h exit: mov ax,4c00h int 21h end main
Toinen vanha testi, mistä voisi olla iloa harjoitellessa: http://www.tip9ug.jp/who/jalih/asm_anim.zip
jalski kirjoitti:
Et mainitse mitä assembleria käytät, syntakseissa on eroja.
Pieniä huomioita: Kannattaisi ehkä miettiä ohjelman logiikka uusiksi, nyt toimii hassusti... Kannattaa karsia turhat kutsut pois, minimoida hypyt ja järjestellä siten, että yleisimmässä tilanteessa "pudotaan läpi" eikä hypätä. Miksi kutsut pääloopin lopussa päälooppia etkä vain hyppää sinne? ja alussa turha kutsua sitä, jos ohjelman suoritus jatkuu siitä muutenkin.
Kannattaa panostaa koodin luettavuuteen, mikä assemblerin kanssa touhutessa voi olla paljon parempi, kuin C++:lla ja muilla korkean tason kielillä.
Alla esimerkki:
; ; Simppeli testiohjelma DOSsille, mikä muuntaa ja kirjoitttaa ruudulle ; luvun 123 heksamuotoisena (=0x7B) ; - -Toinen vanha testi, mistä voisi olla iloa harjoitellessa: http://www.tip9ug.jp/who/jalih/asm_anim.zip
Kiitos avuista. "monimutkaisuus"/epäloogisuus johtuvat siitä, että koodi on alunperin pidempi ja monitahoisempi, tässä olivain tiivistettynä ongelma. Assemblerinä käytän NASMia.
Ja sainkin jo huomautusta call käyttämisestä jmp paikalla. Onko ne niin että jmp hyppää koodissa sille riville, josta nimiö löytyy ja call lataa kyseisen nimiön siihen kohtaan?
Käsittääkseni ero on lähinnä siinä, että jmp hyppää kohtaan (ja siinä se), kun taas call hyppää ko. kohtaan ja lisäksi laittaa alkuperäisen kohdan osoitteen pinoon, että siihen voidaan palata return (tms) -komennolla.
Grez on aivan oikeassa. Tässä on vielä koodi, joka toivottavasti selventää asiaa:
toinen_paikka: ; ret ottaa eip-rekisteriin arvon pinosta, ; jolloin suoritus jatkuu jatkokohdasta ret funktio: ; call laittaa pinoon osoitteen .jatkokohta ja hyppää call toinen_paikka .jatkokohta: ; saman voisi tehdä pushilla ja hyppykäskyllä push .jatkokohta2 jmp toinen_paikka .jatkokohta2: ret
Ja ailtä varalta, että jollekin jäi epäselväksi, niin siinä siis käy hyvinkin huonosti, jos hyppyjen sijasta käyttää callia. Kun callia ei seuraakaan koskaan ret, niin stacki paisuu koko ajan. Riippuu sitten laiteympäristöstä, milloin se täyttyy, ja mitä silloin tapahtuu. Esim. 6502:ssa SP on 8-bittinen, eli pinoon menee vain 256 tavua dataa.
Onko kukaan täällä muuten koodannut sellaisille prossuille, mitä nykyään käytetään kodinkoneissa ja muissa vaatimatonta tietojenkäsittelyä vaativissa kohteissa? Millaisia mahtavat olla, ja onko joku prossu peräisin niiltä ajoilta, kun sellaiset olivat huippuvehkeitä.
No ei siinä välttämättä huonosti käy (koska monissa prossuissa callstack saa pyörähtää ympäri), mutta siinä oppii huonoille tavoille. Eli mainloopissa se ei välttämättä haittaa (koska kaikki oikeat call-returnit tulee sen sisällä). Mutta jos callilla kutsutussa rutiinissa olisi looppi, joka toteutettaisiin callilla, niin return kosahtaisi totaalisesti, kun se palaisikin loopin loppuun, eikä sinne mistä alirutiinia kutsuttiin.
Noissa kodinkoneissa on nykyisin milloin mitäkin. Joissakin on mikrokontrollereita (ARM, AVR, PIC, yms.), joissakin jotain vanhoja prossuja (tyyliin jossain oli 68000) ja joissakin ihan custom rautaa (eli ns. Asic).
Itsehän olen koodaillut 68000:lle silloin kun se oli vielä kova luu eli Amigan alkuaikoina ja sitten myöskin näille nykyisille mikrokontrollereille.
Juu ei haittaa kaikissa tapauksissa tietenkään, mutta yleisessä tapauksessa ehdottomasti. Esim. 6502:ssa SP vaan nollautuu, kun menee yli, eikä se muistaakseni aiheuta mitään keskeytystä, mutta kun pinoa käytetään yleensä myös push-pop operaatioilla (siinä prossussa sama pino), niin ei sieltä koskaan tule oikeaa dataa ulos, kun on hypitty callilla. Eikä aliohjelmasta paluu onnistu missään laitteistossa, jos kutsun jälkeen on käytetty callia hyppykäskynä. Ja jos laitteessa pyörii joku käyttöjärjestelmä, niin kyllä se hermostuu pinoalueen ylityksestä.
Aihe on jo aika vanha, joten et voi enää vastata siihen.