View Full Version : [assembly]disegnare un rettangolo
Ciao a tutti!!!
ho proprio bisogno di una mano con assembly...qualcuno può darmi una mano???
Devo scrivere un programma in assembly 8086 che prenda in ingresso da tastiera le coordinate di 2 punti, e disegnare il rettangolo che ha come diagonale quei 2 punti....
Sono riuscita a fare la lettura dei dati, ho tentato di spostare il cursore in corrispondenza del primo spigolo con questa procedura: ( "ord" e "asc" contengono i valori di ingresso)
SPOSTACURSORE PROC NEAR
MOV DH,[ORD1]
MOV DL,[ASC1]
MOV BH,00h
MOV AH,02h
INT 10h
RET
SPOSTACURSORE ENDP
..e di stampare un * in quella posizione....ma provando il programma vedo che l'* viene stampato sempre nella stessa posizione indipendentemente dai valori di input....
qualcuno sa dirmi dove sbaglio???? :muro:
Ah, uso tasm come assembler
grazie mille!!!!!
La
qualcuno sa dirmi dove sbaglio???? :muro: La procedura che hai scritto mi sembra ok. Credo che il problema sia altrove. Senza vedere l'intero sorgente risulta difficile (almeno per me) capire dove sta l'errore.
Paco De Luciaaaaa
08-07-2006, 23:47
Ciao a tutti!!!
ho proprio bisogno di una mano con assembly...qualcuno può darmi una mano???
Devo scrivere un programma in assembly 8086 che prenda in ingresso da tastiera le coordinate di 2 punti, e disegnare il rettangolo che ha come diagonale quei 2 punti....
Sono riuscita a fare la lettura dei dati, ho tentato di spostare il cursore in corrispondenza del primo spigolo con questa procedura: ( "ord" e "asc" contengono i valori di ingresso)
SPOSTACURSORE PROC NEAR
MOV DH,[ORD1]
MOV DL,[ASC1]
MOV BH,00h
MOV AH,02h
INT 10h
RET
SPOSTACURSORE ENDP
..e di stampare un * in quella posizione....ma provando il programma vedo che l'* viene stampato sempre nella stessa posizione indipendentemente dai valori di input....
qualcuno sa dirmi dove sbaglio???? :muro:
Ah, uso tasm come assembler
grazie mille!!!!!
La
Beh se richiami quella procedura stessa la seconda volta è ovvio che stampi sepre lì l'"*", perchè andrà sempre a prendere il contenuto delle celle di memoria ORD1 e ASC1... secondo me le soluzioni sono:
- o fai una seconda procedura con ORD2 e ASC2 ( molto brutta come soluzione)
- fai una seconda procedura che modifica le 2 celle di memoria ORD1 e ASC1 (ancora bruttina)
- crei una procedura che prenda i parametri direttamente dallo stack previa averglieli pushati nel programma principale (la migliore soluzione secondo me perchè la procedura la puoi usare quanto ti pare con qualsiasi punto)
Ciao :)
Allora intanto ringrazio sia Paco che Andbin per la disponibilità!!!!
comincio a pensare che l'errore sia nella lettura dei dati in input... :cry:
Andbin: Io posto tutto il codice che ho scritto: se hai un pò di tempo da perdere..... :D
solo una raccomandazione: Non ho fatto per ora nessun controllo, e non mi sono preoccupata molto dello "stile"..per ora mi interessava far funzionare il programma senza guardare troppo la forma quindi...non spaventarti!!!!
....secondo i miei calcoli il mio codice dovrebbe stampare 2 '*' in corrispondenza dei 2 spigoli di quello che in futuro diventerà il mio rettangolo!!!
....ma qualsiasi numero metto in ingresso me li stampa sempre nella stessa posizione, e per di più attaccati!!!
per Paco: Forse ho capito male, ma io per ora nn volevo stampare tutto il rettangolo (x ora) ma solo stampare '*' in corrispondenza dei punti che mandavo in ingresso....il mio problema è che eseguendo il programma più volte inserendo dati sempre diversi il risultato è sempre lo stesso!!! :cry: :cry:
....insomma, l'invito vale anche per te...
ecco il mio codice!!!
DSEG SEGMENT PARA PUBLIC 'DATA'
CR EQU 0Dh
LF EQU 0Ah
ASC1 DB ?
ASC2 DB ?
ORD1 DB ?
ORD2 DB ?
TITOLO DB 'ESAME DI CALCOLATORI ELETTRONICI$'
INPUT1 DB CR,LF,'Introdurre ascissa angolo alto/sinistra:$'
INPUT2 DB CR,LF,'Introdurre ordinata angolo alto/sinistra:$'
INPUT3 DB CR,LF,'Introdurre ascissa angolo basso/destra:$'
INPUT4 DB CR,LF,'introdurre ordinata angolo basso/destra:$'
OR1 DB ?
SIZE1 DW ?
DSEG ENDS
STACKM SEGMENT PARA STACK 'STACK'
DB 64 DUP('123456789')
STACKM ENDS
ASSUME CS:CSEG,DS:DSEG,SS:STACKM
CSEG SEGMENT PARA PUBLIC 'CODE'
MAIN PROC FAR
PUSH DS
MOV AX,00h
PUSH AX
CALL INIZIALIZZAZIONE
CALL LEGGIASC1
CALL LEGGIORD1
CALL LEGGIASC2
CALL LEGGIORD2
MOV AH,00h
MOV AL,03h
INT 10h
MOV DH,[ORD1] ;metto le coordinate del primo punto
MOV DL,[ASC1] ;in DX
CALL SPOSTACURSORE ;e sposto il cursore in quella posiz.
MOV AL,'*'
CALL STAMPACHAR ;stampo '*' in quella posizione
MOV DH,[ORD2] ;faccio la stessa cosa col secondo
MOV DL,[ASC2] ;punto
CALL STAMPACHAR
RET
MAIN ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; Pulisce lo scermo e stampa il titolo ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INIZIALIZZAZIONE PROC NEAR
MOV AX,SEG DSEG
MOV DS,AX
MOV AH,00h
MOV AL,03h
INT 10h
MOV DX,OFFSET TITOLO
CALL STAMPASTRINGA
RET
INIZIALIZZAZIONE ENDP
;-----------------------------------------------------;
; leggo 4 interi da tastiera che corrispondono ;
; all'ascissa e all'ordinata dei due punti ;
;-----------------------------------------------------;
LEGGIASC1 PROC NEAR
MOV DX,OFFSET INPUT1
CALL STAMPASTRINGA
CICLO1: CALL LEGGICHAR
CMP AL,CR
JE FINELETTURA1
MOV [ASC1+BX],AL
INC BX
JMP CICLO1
FINELETTURA1: MOV SIZE1,BX
RET
LEGGIASC1 ENDP
LEGGIORD1 PROC NEAR
MOV DX,OFFSET INPUT2
CALL STAMPASTRINGA
CICLO2: CALL LEGGICHAR
CMP AL,CR
JE FINELETTURA2
MOV [ORD1+BX],AL
INC BX
JMP CICLO2
FINELETTURA2: MOV SIZE1,BX
RET
LEGGIORD1 ENDP
LEGGIASC2 PROC NEAR
MOV DX,OFFSET INPUT3
CALL STAMPASTRINGA
CICLO3: CALL LEGGICHAR
CMP AL,CR
JE FINELETTURA3
MOV [ASC2+BX],AL
INC BX
JMP CICLO3
FINELETTURA3: MOV SIZE1,BX
RET
LEGGIASC2 ENDP
LEGGIORD2 PROC NEAR
MOV DX,OFFSET INPUT4
CALL STAMPASTRINGA
CICLO4: CALL LEGGICHAR
CMP AL,CR
JE FINELETTURA4
MOV [ORD2+BX],AL
INC BX
JMP CICLO2
FINELETTURA4: MOV SIZE1,BX
RET
LEGGIORD2 ENDP
;-------------------------------------------------------;
; sposto il cursore nella posizione salvata nel ;
; DX ;
;-------------------------------------------------------;
SPOSTACURSORE PROC NEAR
MOV BH,00h
MOV AH,02h
INT 10h
RET
SPOSTACURSORE ENDP
STAMPACHAR PROC NEAR
MOV BH,00h
MOV AH,0Eh
INT 10h
RET
STAMPACHAR ENDP
STAMPASTRINGA PROC NEAR
MOV AH,09h
INT 21h
RET
STAMPASTRINGA ENDP
LEGGICHAR PROC NEAR
MOV AH,01h
INT 21h
RET
LEGGICHAR ENDP
CSEG ENDS
END MAIN
vi ringrazio gia da ora!!!!! (mi basta qualche suggerimento1!!) :D
a presto,
La
Scusatemi, nel codice che ho appena postato manca una chiamata alla procedura "spostacursore" prima di stampare il secondo '*'(ecco perchè li stampava vicini!!!! :) )...in ogni caso anche ora mi sembra che stampi asterischi a caso.... :mc:
spero che qualcuno sappia darmi qualche consiglio...
a presto
La
Ciao, ho letto bene il codice. Purtroppo devo dirti che la gestione dell'input delle coordinate è molto sbagliata, sopratutto a livello concettuale!
Partiamo dall'inizio: dopo aver completato l'input dei dati tu dovresti avere 4 valori numerici che (a coppie) rappresentano le 2 coordinate dei due angoli del rettangolo da disegnare.
Tu dichiari:
ASC1 DB ?
ASC2 DB ?
ORD1 DB ?
ORD2 DB ?Fin qui tutto ok. Lavorando con la console, non puoi certamente avere valori molto grossi delle coordinate (max 79x24 ;) ) e quindi 1 byte è più che sufficiente.
La questione fondamentale è che l'input viene fatto digit per digit. Questo vuol dire che per inserire il valore numerico 12 devi inserire i caratteri '1' (49 / 31h) e '2' (50 / 32h). Ma tu alla fine devi avere il valore 12 / 0Ch!!!!
Devi quindi effettuare dei test per verificare se il singolo carattere digitato è compreso tra '0' e '9' e poi effettuare dei (semplici) calcoli matematici per ottenere il valore numerico del tuo input.
Visto che devi prendere in input 4 numeri, potrei consigliarti di realizzare una sola procedure che gestisce l'input di al massimo 2 digit e alla fine restituisce in un registro (es. AX) il valore numerico corrispondente.
Una descrizione del flusso di questa procedure potrebbe essere:
1) Imposta numdigit=0 e valore=0
2) Se numdigit=2, vai al punto 8
3) Input di un carattere (senza echo)
4) Se il carattere inserito è fuori dal range '0'..'9', passa al punto 3
5) Stampa carattere (echo)
6) Sottrai '0' dal valore del carattere e calcola: valore = valore*10 + digit
7) Incrementa numdigit e passa al punto 2
8) Esce con il valore
Chiedo scusa se questa descrizione del flusso non fosse molto chiara ... non sono abituato a scrivere diagrammi di flusso, pseudo-codice o qualunque altra cosa che non sia codice "reale". ;) :p
Per il momento spero di averti dato le dritte giuste.
repne scasb
09-07-2006, 22:08
Vari errori:
1) Le quantita ASC1/ASC2/ORD1/ORD2 non sono byte ma array di byte in quanto conterranno stringhe. Poiche' in tali routine viene incrementato il registro BX tale incremento (a meno di modifiche di LEGGICHAR) sovrascrivera' il segmento dati con dati incoerenti e corrotti.
2) Nella routine LEGGICHAR non viene salvaguardato il registro BX.
3) Nelle routine LEGGIASC1/LEGGIORD1/LEGGIASC2/LEGGIORD2 manca completamente il controllo dell'input (2 caratteri e soltanto numerici.
4) Manca una routine che converta le stringhe ASC1/ASC2/ORD1/ORD2 valori numerici.
5) Manca un controllo a valle delle routine LEGGIASC1/LEGGIORD1/LEGGIASC2/LEGGIORD2 per verificare che il valore numerico inserito sia coerente (compresto per mode 3h tra 0 e 79 (x) e tra 0 e 24 (y)).
6) La routine STAMPACHAR non salvaguarda il registro AX, in questo modo nella seconda chiamata a STAMPACHAR non si puo' essere sicuri che AL='*'.
7) Non e' chiaro a cosa servano i push a inizio codice. Il codice MAIN si deve chiudere o con un int 20h o con un func 4F00h int 21h.
Non ho fatto un analisi piu' completa per mancanza di tempo, ma potrebbero esserci altri problemi/mancanze varie.
grazie mille, sei stato veramente gentile!!!!!
da domattina reimposto la lettura dei dati seguendo i tuoi consigli.
spero di riuscire a cavarmela da sola!!!
buona serata
La
Grazie anche a repne scasb!!!
...per i controlli mancanti...quelli li lascio sempre alla fine!! :D
...per i casini con i registri....domattina cercherò di fare + attenzione!!!!
scusatemi, ma è la prima volta che programmo in assembly, e devo ancora capire bene i meccanismi di base....
grazie mille per la disponibilità!!!!!
La
7) Non e' chiaro a cosa servano i push a inizio codice. Il codice MAIN si deve chiudere o con un int 20h o con un func 4F00h int 21h.Anche a me non era chiaro subito il motivo delle 2 push ma poi .... mi sono ricordato! (è tanti anni che non lavoro più in DOS ... sono un po' arruginito, eh? :D ).
Le due push spingono sullo stack l'indirizzo DS:0000h e a quel indirizzo è presente il PSP (Program Segment Prefix) i cui primi due byte formano l'istruzione INT 20h. Quindi con la RET "far" salta a quel indirizzo ed esegue INT 20h.
Molto macchinoso, lo so .... consiglio vivamente di usare la funzione AH=4Ch del INT 21h.
repne scasb
10-07-2006, 00:29
L'istruzione INT 20h presente nei primi due byte del PSP (0CDh, 20h), e' disponibile ed utilizzabile solo per software scritti com modello di memoria tiny (.COM), con SS/DS/CS puntanti allo stesso segmento. In questo caso trattandosi di un .EXE con SS/DS/CS non nello stesso segmento, nonostante con il retf finale CS punti correttamente al PSP, non e' detto che l'istruzione INT 20h sia in grado di deallocare correttamente il software, e restituire il controllo a COMMAND.COM.
A questo si aggiunge che il contenuto del registro DS in un .EXE, ad inizio codice, permane "indefinito" (se si utilizzano interpreti di comandi "diversi" da COMMAND.COM DS non punta affatto al PSP), tante' che esistono le funzioni Set/Get PSP (int 21h Func. 50h/51h), percui il retf finale puo' andare a puntare ovunque.
Quoto quanto detto da repne scasb e suggerisco nuovamente a Label84 di usare la funzione 4Ch di int 21h per terminare un programma .exe.
Comunque ho trovato questo documento: How to Use Int 20h to Terminate an .EXE Program (http://support.microsoft.com/default.aspx?scid=kb%3Ben-us%3B72848)
@repne scasb:
Dalle specifiche che ho io, per un .exe, DS e ES puntano inizialmente al PSP. Se poi con altri interpreti diversi dal COMMAND.COM questo non è vero .... non lo so, io ho sempre usato il classico DOS e quindi COMMAND.COM. ;)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.