Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Assembly: opcode and operand -virhe

Sivun loppuun

tkok [29.05.2009 13:53:01]

#

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

tkok [29.05.2009 15:26:58]

#

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

jalski [29.05.2009 19:38:03]

#

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

tkok [30.05.2009 10:34:52]

#

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?

Grez [30.05.2009 10:53:22]

#

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.

Metabolix [30.05.2009 12:27:48]

#

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

hk [31.05.2009 21:52:01]

#

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ä.

Grez [31.05.2009 23:34:10]

#

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.

hk [01.06.2009 00:09:51]

#

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ä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta