37
Ε)ΠΡΟΓΡΑΜΜΑΤΑ ΜΕΤΑΤΡΟΠΗΣ ΚΩΔΙΚΑ Ε1) Conversion of Double BCD to Binary Αντικείμενο : η Μετατροπή ενός Double BCD αριθμού (1-byte, dbcd_num) σε δυαδικό αριθμό (1-byte, binary_num). (Double BCD είναι ένα byte που περιέχει BCD αριθμούς και στα δύο nibbles του). Στην υλοποίηση που ακολουθεί χρησιμοποιήθηκαν ακόμη οι τοπικές μεταβλητές: - uppernibble: προσωρινή αποθήκευση του ψηφίου που βρίσκεται στο υψηλότερο nibble Επίσης γίνεται χρήση των καταχωρητών R1:R0 για αποθήκευση του γινομένου του πολλαπλασιασμού. Κρίσιμα σημεία ελέγχου κατά το debugging: Πολύ απλό πρόγραμμα για να δοθούν γενικής φύσης κρίσιμα σημεία ελέγχου.

programsAVR.2

  • Upload
    mcrae

  • View
    214

  • Download
    1

Embed Size (px)

DESCRIPTION

programsAVR.2

Citation preview

Page 1: programsAVR.2

Ε)ΠΡΟΓΡΑΜΜΑΤΑ ΜΕΤΑΤΡΟΠΗΣ ΚΩΔΙΚΑ

Ε1) Conversion of Double BCD to Binary

Αντικείμενο : η Μετατροπή ενός Double BCD αριθμού (1-byte, dbcd_num) σε δυαδικό αριθμό (1-byte, binary_num). (Double BCD είναι ένα byte που περιέχει BCD αριθμούς και στα δύο nibbles του).

Στην υλοποίηση που ακολουθεί χρησιμοποιήθηκαν ακόμη οι τοπικές μεταβλητές:- uppernibble: προσωρινή αποθήκευση του ψηφίου που βρίσκεται στο υψηλότερο nibble

Επίσης γίνεται χρήση των καταχωρητών R1:R0 για αποθήκευση του γινομένου του πολλαπλασιασμού.

Κρίσιμα σημεία ελέγχου κατά το debugging:Πολύ απλό πρόγραμμα για να δοθούν γενικής φύσης κρίσιμα σημεία ελέγχου.

Page 2: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

Start

uppernibble := uppernibble * 10binary_num := dbcd_num & $0F

uppernibble < 10?

No

No

Yes

binary_num := binary_num + uppernibble

End

Yes

binary_num < 10?

uppernibble := dbcd_num & $F0uppernibble >> 4

Page 3: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης:

;-------------------- Double BCD to Binary --------------------;Title: CONV_DBCD_BIN;Purpose: Conversion of a 1-byte double BCD number (a byte containing BCD digits in; both its nibbles) to a 1-byte Binary number;Input Parameters: ; dbcd_num: 1-byte double BCD number (a byte containing BCD digits in both its; nibbles) to be converted - stored in R16;Other variables:; binary_num: 1-byte Binary number resulting from conversion (output parameter); stored in R17; uppernibble: temp storage of upper nibble's binary equivalent - stored in R18;"Special purpose" Registers used: R1:R0 for the multiplication result;Exit: "binary_num" holds the binary equivalent of "dbcd_num";Errors: one of the BCD digits has ineligible value (is >1001) --> sets T flag;Comments: -;--------------------.def dbcd_num=R16 .def binary_num=R17 .def uppernibble=R18;----------CONV_DBCD_BIN:

mov uppernibble, dbcd_numcbr uppernibble, $0Fswap uppernibblecpi uppernibble, 10brsh inel_bcd_digitldi binary_num, 10mul uppernibble, binary_num ; upper nibble's binary equivalent is stored in R0mov binary_num, dbcd_numcbr binary_num, $F0cpi binary_num, 10brsh inel_bcd_digitadd binary_num, R0cltret

inel_bcd_digit:setret

;----- End of subroutine CONV_DBCD_BIN -----.undef dbcd_num.undef binary_num.undef uppernibble

Σχόλια σχετικά με την ανάπτυξη του κώδικα:(1) Η εντολή αυτή θα μπορούσε σε επίπεδο assembly να αντικατασταθεί με την “andi uppernibble,

$F0” (η μόνη διαφορά είναι ότι οι σταθερές στις δύο εντολές είναι η μία το συμπλήρωμα ως προς ένα της άλλης). Η λειτουργία που εκτελείται και στις δύο περιπτώσεις στο εσωτερικό του AVR είναι η ίδια, αφού ο συμβολομεταφραστής παράγει τον ίδιο κώδικα σε γλώσσα μηχανής και για τις δύο. Χαρακτηριστική περίπτωση εμπλουτισμού του λεξιλογίου της assembly (προς διευκόλυνση του προγραμματιστή) χωρίς αντίκτυπο στην σχεδίαση του επεξεργαστή.

(1)

(2)

Page 4: programsAVR.2

(2) Τέτοιες υπορουτίνες αποτελούν κλασικές περιπτώσεις υπορουτινών βιβλιοθήκης. Καλό είναι να χρησιμοποιούνται κατά το δυνατό ελάχιστοι καταχωρητές και να μην αλλοιώνεται το περιεχόμενο των καταχωρητών που περιέχουν τις παραμέτρους εισόδου.

Page 5: programsAVR.2

Ε2) Conversion of ASCII Hex to Binary

Αντικείμενο : η Μετατροπή ενός δεκαεξαδικού αριθμού αποτελούμενου από 2 ASCII bytes (msaschex:lsaschex) σε δυαδικό αριθμό (1-byte, binary_num).

Κρίσιμα σημεία ελέγχου κατά το debugging:Χρειάζεται προσοχή στα όρια με τα οποία γίνονται οι συγκρίσεις σε συνδυασμό με τις εντολές υπό συνθήκη άλματος.

Page 6: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

Start

msaschex := msaschex - $30

Is msaschex >$2F and <$3A?

No No

Yes

End

Yes

Is lsaschex >$2F and <$3A?

Is msaschex >$40 and <$47

msaschex := msaschex - $37

Is lsaschex >$40 and <$47

NoNo

Yes Yes

lsaschex := lsaschex - $30 lsaschex := lsaschex - $37

msaschex << 4binary_num := msaschex & lsaschex

Page 7: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης:

;-------------------- ASCII Hex to Binary --------------------;Title: CONV_AHEX_BIN;Purpose: Conversion of a 2 ASCII bytes Hexadecimal number to a 1-byte Binary number;Input Parameters: ; lsaschex: ASCII representation of the least significant Hexadecimal digit; stored in R16 - altered; msaschex: ASCII representation of the most significant Hexadecimal digit; stored in R17 - altered;Other variables:; binary_num: 1-byte Binary number resulting from conversion (output parameter); stored in R16;Exit: "binary_num" holds the binary equivalent of $"msaschex:lsaschex";Errors: one of the Hexadecimal digits has ineligible value --> sets T flag; (eligible values are: $30-$39 AND $41-$46) ;Comments: ; - Since the original value of "lsaschex" is altered, the Register that holds it; is also used for the "binary_num" variable;--------------------.def lsaschex=R16 .def msaschex=R17 .def binary_num=R16;----------CONV_AHEX_BIN:

cpi msaschex, $30brlo inel_hex_digitcpi msaschex, $3Abrsh tenorbigger_1 subi msaschex, $30rjmp check_lsdigit

tenorbigger_1:cpi msaschex, $41brlo inel_hex_digitcpi msaschex, $47brsh inel_hex_digitsubi msaschex, $37

check_lsdigit:cpi lsaschex, $30brlo inel_hex_digitcpi lsaschex, $3Abrsh tenorbigger_2 subi lsaschex, $30rjmp combine

tenorbigger_2:cpi lsaschex, $41brlo inel_hex_digitcpi lsaschex, $47brsh inel_hex_digitsubi lsaschex, $37

combine:swap msaschexor binary_num, msaschex ; either OR or ADD have the same resultcltret

Page 8: programsAVR.2

inel_hex_digit:setret

;----- End of subroutine CONV_AHEX_BIN -----.undef lsaschex.undef msaschex.undef binary_num

Σχόλια σχετικά με την ανάπτυξη του κώδικα:Απλό πρόγραμμα με πολλαπλούς ελέγχους ορίων, που προσφέρει εξοικείωση με την αναπαράσταση των χαρακτήρων σε ASCII μορφή.

Page 9: programsAVR.2

Ε3) Conversion of BCD to 7 segment LED display

Αντικείμενο : η Μετατροπή ενός ψηφίου BCD αριθμού (1-byte, dbcd_digit) σε μορφή που μπορεί να εξαχθεί προς απεικόνιση σε μία «7 τμημάτων διάταξη LED» (1-byte, led7_code). Όταν η τιμή του BCD ψηφίου δεν είναι μεταξύ 0 και 9, τότε εξάγεται προς απεικόνιση το “E”. Τα LED ενεργοποιούνται όταν το αντίστοιχο pin της θύρας εξόδου έχει τιμή 0.

Γίνεται χρήση των καταχωρητών R31:R30 για προσπέλαση της Μνήμης προγράμματος.

Κρίσιμα σημεία ελέγχου κατά το debugging:Πολύ απλό πρόγραμμα για να δοθούν γενικής φύσης κρίσιμα σημεία ελέγχου.

Page 10: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

Start

Z := led7_table << 1Z := Z + bcd_digitled7_code := [Z]

bcd_digit < 10?

No

End

Yes

led7_code := $30

Page 11: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης:

;-------------------- BCD to 7 segment LED display --------------------;Title: CONV_BCD_LED7;Purpose: Conversion of a 1-byte BCD digit to values that may be outputted to a 7; segment LED display for the BCD digit's depiction;Input Parameters: ; bcd_digit: 1-byte BCD digit to be depicted - stored in R16;Other variables:; led7_code: the corresponding to "bcd_digit" value that may be outputted to a 7; segment LED display (output parameter) - stored in R17;"Special purpose" Registers used: R31:R30 (Z) for reading from Program Memory;Exit: "led7_code" holds the 7 segment LED display equivalent of "dbcd_digit";Errors: ; - "dbcd_digit" has ineligible value (is >$09) --> "led7_code"=$30 (depicts 'E');Comments: ; - LED segments are emitting light when the corresponding output pin's value is 0; - 7 segment LED code uses 7 bits (the MSb is not used - considered to be 0 in; the table's values) ordered in a byte as "_ABCDEFG", connected as following:; - A: the upper horizontal segment _____; - B: the right upper segment | A |; - C: the right lower segment F| |B; - D: the lower horizontal segment | |; - E: the left lower segment | G |; - F: the left upper segment E| |C; - G: the middle horizontal segment | |;-------------------- D.def bcd_digit=R16 .def led7_code=R17led7_table:

.DB $01, $4F, $12, $06, $4C, $24, $60, $0F, $00, $0C;----------CONV_BCD_LED7:

cpi bcd_digit, $10brsh inel_bcd_byteldi ZL, LOW(led7_table)ldi ZH, HIGH(led7_table)lsl ZLrol ZHadd ZL, bcd_digitbrcc no_carryinc ZH

no_carry:lpm led7_code, Zret

inel_bcd_byte:ldi led7_code, $30ret

;----- End of subroutine CONV_BCD_LED7 -----.undef bcd_digit.undef led7_code

Σχόλια σχετικά με την ανάπτυξη του κώδικα:

Page 12: programsAVR.2

Χρειάζεται καλή περιγραφή της αντιστοίχισης των led με κάθε bit στα σχόλια, προκειμένου να διευκολυνθεί η χρήση της υπορουτίνας από τρίτους ή μελλοντικά

Page 13: programsAVR.2

ΣΤ) ΠΡΟΓΡΑΜΜΑΤΑ ΕΠΕΞΕΡΓΑΣΙΑΣ ΣΥΜΒΟΛΟΣΕΙΡΑΣ

ΣΤ1) String concatenation

Αντικείμενο : η Συνένωση δύο συμβολοσειρών, τοποθετώντας την δεύτερη αμέσως μετά την πρώτη. Δίνεται ακόμη μέγιστο επιτρεπτό μήκος για τη νέα συμβολοσειρά (concat_len). Το μήκος κάθε συμβολοσειράς αποθηκεύεται στο πρώτο byte της.

Στην υλοποίηση που ακολουθεί χρησιμοποιήθηκαν ακόμη οι τοπικές μεταβλητές:- temp1: προσωρινή αποθήκευση του μήκους της δεύτερης συμβολοσειράς, του μήκους της

νέας συμβολοσειράς και του αριθμού των χαρακτήρων που υπολείπονται προς αντιγραφή (θα μπορούσαν να χρησιμοποιηθούν τρεις διαφορετικές μεταβλητές – καταχωρητές, όμως έχει γίνει προσπάθεια εξοικονόμησης κατά το δυνατό)

- temp2: προσωρινή αποθήκευση του αρχικού μήκους της πρώτης συμβολοσειράς και του χαρακτήρα που τελεί υπό αντιγραφή

- temp_ad: προσωρινή διεύθυνση όπου αποθηκεύονται οι χαρακτήρες κατά την αντιγραφή

Κρίσιμα σημεία ελέγχου κατά το debugging:(i) Ποιες είναι οι περιπτώσεις που δεν θα προστεθεί τίποτα στο τέλος της πρώτης συμβολοσειράς?(ii) Ποιοι έλεγχοι υποδεικνύουν ότι θα προστεθεί τμήμα μόνο της δεύτερης συμβολοσειράς στο

τέλος της πρώτης? (όλα τα μήκη δίνονται από 1-byte αριθμό)(iii) Κατά την πρώτη αντιγραφή χαρακτήρα, από ποια διεύθυνση θα διαβαστεί το byte και σε

ποια θα αποθηκευτεί? (το μήκος της συμβολοσειράς είναι ενσωματωμένο σε αυτήν)(iv)Ποιο είναι το μήκος της νέας συμβολοσειράς? (δεν είναι πάντα το ίδιο)

Page 14: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

new_length := str1_length + str2_length

Start

counter := new_length - str1_lengthstr2_ad := str2_ad + 1

temp_ad := str1_ad + str1_length + 1

new_length > concat_length ?

temp_char := [str2_ad][temp_ad] := temp_charcounter := counter - 1

counter = 0?

No

Yes

Endstr2_length = 0 or

str1_length >= concat_length Yes

No

(i)

(ii)

No

new_length := concat_lengthT := 1

End

Yes

(iii)(iv)

Page 15: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης:

;-------------------- String concatenation --------------------;Title: STR_CONCAT;Purpose: Concatenation of two strings, by adding the one at the end of the other,; up to a given maximum concatenated string length - the first byte of strings; stores its length --> maximum string length=255;Input Parameters: ; concat_len: maximum length of the concatenated string - stored in R16; str1_stad: starting address of string 1 - stored in R27:R26 (X) ; str2_stad: starting address of string 2 - stored in R29:R28 (Y) - altered;Other variables:; temp1: temporary storage of str2_len, of str1_len after concatenation, and of ; num of chars to be added - stored in R17; temp2: temporary storage of original str1_len and of char currently transferred; stored in R18; temp_ad: temporary address to which the copied chars as stored ; (not necessary, it is employed in order to avoid altering "str1_stad") ; stored in R31:R30 (Z);Exit: - (string 2 or part of it has been added at the end of string 1);Errors: ; ErrorA: string1_length>=concat_length OR string2_length=0 (no changes); --> sets both T and V flags; (inappropriate block bounds either for the old or the new location); ErrorB: string1_length+string2_length>concat_length (only a part of string 2 is; added at the end of string 1) --> sets T flag, clears V flag;Comments: ; - There are no checks for "eligible" bounds of the strings with regard to the ; allowable (in mega128, data should be stored between $100 and ($1100-a)); a: SRAM used locations (for the Stack or other data); - "str2_stad" has been altered at the end of subroutine's code. If it needs to; remain unchanged, the "num of chars to be added" before starting adding them; (stored at "temp1" at that point) should be stored in an other Register; before; subroutine's end, the stored value incremented by 1 should be subtracted from; the modified "str2_stad".;--------------------.def concat_len=R16.def str1_stad_L=R26 ; XL.def str1_stad_H=R27 ; XH.def str2_stad_L=R28 ; YL.def str2_stad_H=R29 ; YH.def temp1=R17.def temp2=R18.def temp_ad_L=R30 ; ZL.def temp_ad_H=R31 ; ZH;----------STR_CONCAT:

ld temp1, Υtst temp1breq no_concatld temp2, Χcp temp2, concat_lenbrsh no_concatclt ; in order to remember if errorB occured or notadd temp1, temp2

(i)

(i)

(iv)

Page 16: programsAVR.2

brcs partial_concat ; string1_length+string2_length>255 --> >concat_lencp concat_len, temp1brsh str1newlen_ok

partial_concat:set ; mark ErrorBmov temp1, concat_len

str1newlen_ok:st X, temp1sub temp1, temp2 ; temp1 holds the num of chars to be addedmovw temp_ad_L, str1_stad_Ladiw temp_ad_L, 1 ; increment by one in order to skip the length's byteadiw str2_stad_L, 1add temp_ad_L, temp2 ; move temp_ad at the end of string 1brcc add_charinc temp_ad_H

add_char:ld temp2, Y+st Z+, temp2dec temp1brne add_charclvret

no_concat:setsevret

;----- End of subroutine STR_CONCAT -----.undef concat_len.undef str1_stad_L.undef str1_stad_H.undef str2_stad_L.undef str2_stad_H.undef temp1.undef temp2.undef temp_ad_L.undef temp_ad_H

Σχόλια σχετικά με την ανάπτυξη του κώδικα:(1) Αν μετά την πρόσθεση των μηκών των δύο συμβολοσειρών έχουμε κρατούμενο (C=1) τότε

εξυπακούεται ότι θα προστεθεί τμήμα μόνο της δεύτερης συμβολοσειράς στο τέλος της πρώτης.(2) Δεν χρειάζεται να γραφεί διαφορετικός κώδικας για την αντιγραφή όλης ή μέρους της δεύτερης

συμβολοσειράς. Αρκεί να δοθεί η σωστή τιμή στο temp1 και να ενεργοποιηθεί η σημαία Τ. Ο υπόλοιπος κώδικας είναι κοινός.

(3) Η αρχική διεύθυνση της πρώτης συμβολοσειράς αντιγράφεται στον καταχωρητή Ζ προκειμένου να μείνει αναλλοίωτη. Αν δεν θέλουμε να γίνει χρήση του Ζ, μπορούμε να αλλοιώσουμε την αρχική διεύθυνση και να την επαναφέρουμε στην σωστή τιμή χρησιμοποιώντας το μήκος της νέας συμβολοσειράς. Θα πρέπει όμως να αποθηκευτεί κάπου αυτό το μήκος (σε τυχαίο καταχωρητή ή σε αυτόν που ήταν αποθηκευμένο το μέγιστο επιτρεπτό μήκος) και μετά να αφαιρεθεί από 16-bit μεταβλητή, γεγονός που επιβαρύνει λίγο τον κώδικα. Ο προγραμματιστής πρέπει να επιλέξει ανάμεσα στις δύο λύσεις ανάλογα με τις συγκεκριμένες περιστάσεις.

(1)

(2)

(3)

(iii)

(ii)

(ii)

(iv)

Page 17: programsAVR.2

ΣΤ2) DESIGN NOTE #043 (www.avrfreaks.net)

Page 18: programsAVR.2

ΣΤ3) Find the position of a substring in a string

Αντικείμενο : η Αναζήτηση της πρώτης εμφάνισης μιας υπο-συμβολοσειράς (substring) μέσα σε μια κύρια συμβολοσειρά και επιστροφή δείκτη (index) στη θέση όπου αρχίζει. Αν δεν βρεθεί η υπο-συμβολοσειρά, η τιμή του δείκτη είναι 0. Το μήκος κάθε συμβολοσειράς αποθηκεύεται στο πρώτο byte της.

Στην υλοποίηση που ακολουθεί χρησιμοποιήθηκαν ακόμη οι τοπικές μεταβλητές:- counter1: μετρητής των θέσεων που απομένει να ελεγχθεί αν αποτελούν την αρχή της υπο-

συμβολοσειράς (ελέγχει τον εξωτερικό βρόχο)- counter2: μετρητής των χαρακτήρων που απομένει να ελεγχθούν προκειμένου να ξεκινάει η

υπο-συμβολοσειρά από την τρέχουσα πιθανή αρχή της (ελέγχει τον εσωτερικό βρόχο)- temp1_char: ο τρέχων χαρακτήρας της κύριας συμβολοσειράς- temp2_char: ο τρέχων χαρακτήρας της υπο-συμβολοσειράς- temp_ad1: προσωρινή διεύθυνση του τρέχοντος χαρακτήρα της κύριας συμβολοσειράς- temp_ad2: προσωρινή διεύθυνση του τρέχοντος χαρακτήρα της υπο-συμβολοσειράς

Κρίσιμα σημεία ελέγχου κατά το debugging:(i) Πόσες είναι οι θέσεις που μπορεί να αποτελούν την αρχή της υπο-συμβολοσειράς? (σχετικά

δείτε το τρίτο από τα σχόλια που δίνονται επιπρόσθετα μετά τον κώδικα)(ii) Ποιες περιπτώσεις θεωρείται ότι αποτελούν λάθος?(iii) Όταν το μήκος της κύριας συμβολοσειράς είναι ίσο με το μήκος της υπο-συμβολοσειράς

θα εκτελεστεί ο εσωτερικός βρόχος? (πρέπει να γίνει έλεγχος αφού οι δύο συμβολοσειρές μπορεί να είναι ταυτόσημες)

Page 19: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

counter1 := str1_length - str2_lengthcounter2 := str2_length

index := 1temp1_ad := str1_ad + 1temp2_ad := str2_ad + 1

Start

temp1_char := [temp1_ad]temp2_char := [temp2_ad]

temp1_char = temp2_char ?

counter2 := counter2 - 1

counter2 = 0?

No

Yes

Endstr1_length = 0 or

str1_length < str2_length or str2_length = 0

Yes

No

(ii)

Notemp1_ad := temp1_ad + 1temp2_ad := temp2_ad +1

End

Yes

(iii)

counter1 := counter1 - 1

counter1 < 0?

(i)

index := index + 1temp1_ad := str1_ad + index

temp2_ad := str2_ad + 1counter2 := str2_length

No

Yes

Page 20: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης :

;------------------ Find the position of a substring in a string ------------------;Title: SUBSTR_POS;Purpose: Search for the first occurrence of a substring within a string and return ; its starting index ; ! the first byte of strings stores its length --> maximum string length=255;Input Parameters: ; str1_stad: starting address of string - stored in R17:R16; str2_stad: starting address of substring - stored in R19:R18;Other variables:; index: starting index of the first occurrence of the substring within the string; (output parameter) - stored in R20; counter1: counter of remaining "substring starts" within string - stored in R21; (outer loop counter, reduced by one each time the check starting address is; incremented by one); counter2: counter of the chars remaining to be matched - stored in R22; (inner loop counter, set to substring_length each time the check starting; address is incremented by 1 --- when equal to 0 --> successful match) ; temp1_char: char in string currently processed - stored in R23; temp2_char: char in substring currently processed - stored in R24; temp_ad1: address of the currently processes string's char ; stored in R29:R28 (Y); temp_ad2: address of the currently processes substring's char; stored in R31:R30 (Z);Exit: If the substring is found within the string, "index" holds the starting index; of the first occurrence of the substring within the string. Else "index"=0.;Errors: string_length=0 OR substring_length=0 OR substring_length>string_length; --> sets T flag (inappropriate string length);Comments: ; - There are no checks for "eligible" bounds of the strings with regard to the ; allowable (in mega128, data should be stored between $100 and ($1100-a)); a: SRAM used locations (for the Stack or other data);--------------------.def str1_stad_L=R16 .def str1_stad_H=R17 .def str2_stad_L=R18.def str2_stad_H=R19.def index=R20.def counter1=R21.def counter2=R22.def temp1_char=R23.def temp2_char=R24.def temp_ad1_L=R28 ; YL.def temp_ad1_H=R29 ; YH.def temp_ad2_L=R30 ; ZL.def temp_ad2_H=R31 ; ZH;----------SUBSTR_POS:

movw temp_ad1_L, str1_stad_Lmovw temp_ad2_L, str2_stad_Lld counter1, Y+tst counter1breq er_str_lenld counter2, Z+

(1)

(1)(ii)

Page 21: programsAVR.2

tst counter2breq er_str_lensub counter1, counter2brlo er_str_lencltldi index, 1inc counter1

char_comp:ld temp1_char, Y+ld temp2_char, Z+cp temp1_char, temp2_charbrne inc_check_staddec counter2brne char_compret

inc_check_stad:subi counter1, 1brcs not_foundinc indexmovw temp_ad1_L, str1_stad_Ladd temp_ad1_L, indexbrcc contin1inc temp_ad1_H

contin1:movw temp_ad2_L, str2_stad_Lld counter2, Z+rjmp char_comp

not_found:clr indexret

er_str_len:setret

;----- End of subroutine SUBSTR_POS -----.undef str1_stad_L.undef str1_stad_H.undef str2_stad_L.undef str2_stad_H.undef index.undef counter1.undef counter2.undef temp1_char.undef temp2_char.undef temp_ad1_L.undef temp_ad1_H.undef temp_ad2_L.undef temp_ad2_H

Σχόλια σχετικά με την ανάπτυξη του κώδικα:(1) Έλεγχος για μηδενικό μήκος με ταυτόχρονη αύξηση της διεύθυνσης ώστε να δείχνει στον

πρώτο χαρακτήρα (μετά το μήκος).(2) Η μεταβλητή index παίρνει την τιμή που ενδεχομένως αποδειχθεί σωστή πριν το άλμα στον

εσωτερικό βρόχο με τον οποίο θα ελεγχθεί αν βρέθηκε η υπο-συμβολοσειρά.

(iii)

(i)(2)

(3)

(i)(ii)

(ii)

Page 22: programsAVR.2

(3) Η αρχική τιμή του counter1 ισούται με τη διαφορά των χαρακτήρων των δύο συμβολοσειρών επαυξημένης κατά ένα.

Page 23: programsAVR.2

Ζ) ΠΡΟΓΡΑΜΜΑΤΑ ΕΠΕΞΕΡΓΑΣΙΑς ΣΤΟΙΧΕΙΩΝ ΠΙΝΑΚΑ

Ζ1) AVR102 :BLOCK COPY ROUTINES (Site Atmel)

Page 24: programsAVR.2

Ζ2) Move a block of data to a new location

Αντικείμενο : η Μετακίνηση ενός συμπαγούς τμήματος δεδομένων (συνεχόμενες θέσεις στην SRAM) σε νέα θέση. Δίνονται ο αριθμός των bytes που θα μετακινηθούν (2-byte, block_len), η αρχική διεύθυνση από όπου ξεκινάει το συμπαγές τμήμα δεδομένων (orig_stad) και η νέα διεύθυνση από την οποία ζητείται να ξεκινάει (new_stad).

Στην υλοποίηση που ακολουθεί χρησιμοποιήθηκαν ακόμη οι τοπικές μεταβλητές:- temp_stor: προσωρινή αποθήκευση του υπό μεταφορά byte- temp_stor2: χρησιμοποιείται σε συνδυασμό με το temp_stor για τον σχηματισμό 16-bit

διεύθυνσης κατά τον έλεγχο για λάθη στα όρια (παλιά και νέα) του συμπαγούς τμήματος δεδομένων

Θεωρείται ότι η SRAM αποτελείται από 4 Kbytes (=$1000 bytes) (όση η εσωτερική SRAM του ATmega128) και ότι δεν υπάρχουν άλλα δεδομένα στην Στοίβα (δείτε σχετικά το τρίτο από τα σχόλια που δίνονται επιπρόσθετα μετά τον κώδικα)

Κρίσιμα σημεία ελέγχου κατά το debugging:(i) Σε ποιες περιπτώσεις έχουμε σφάλμα? (σχετικά δείτε το δεύτερο από τα σχόλια που δίνονται

επιπρόσθετα μετά τον κώδικα)(ii) Από την συνύπαρξη ποιων συνθηκών φανερώνεται ότι γίνεται αποθήκευση σε διευθύνσεις με

χρήσιμα δεδομένα πριν αυτά αντιγραφούν στις νέες διευθύνσεις τους? (iii) Χρειάζεται προσοχή στις σταθερές και την σειρά των ορισμάτων που χρησιμοποιούνται

στις συγκρίσεις (σε συνδυασμό και με τις εντολές υπό συνθήκη άλματος). Μερικές φορές εξυπηρετεί καλύτερα η αύξηση ή μείωση κατά ένα της σταθεράς ή αντιμετάθεση των ορισμάτων.

Page 25: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

Start

orig_stad <$100 ororig_stad > $10FE ornew_stad < $100 ornew_stad > $10FE

temp_stor := [orig_stad][new_stad] := temp_stor

orig_stad := orig_stad + 1new_stad := new_stad + 1block_len := block_len - 1

No

orig_stad < new_stad AND

orig_stad + block_len > new_stad

No

Yes

EndYes

block_len = 0?

Yes

No

(i)

(i) (ii)

block_len = 0?

End

Yes

No

Page 26: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης :

;-------------------- Move a block of data to a new location --------------------;Title: MOV_BLOCK;Purpose: Move a block of data to a new SRAM location, given a new starting address; ! max size of block (potentially=65535) is limited by the type of the memory; ! used for storing the data. Assuming use of internal SRAM (4KB =$1000 bytes),; ! for both the initial and the final data storing, ; ! max size = $1000-2-d-a, when orig_stad>new_stad; ! max size = ($1000-2-a)/2, when orig_stad<new_stad (in order not to overwrite); 2: Stack places used for the return address of the subroutine; d: absolute distance (in bytes) of transference; a: other possible SRAM used places;Input Parameters: ; block_len: number of bytes in the block - stored in R25:R24 - altered; orig_stad: original starting address of the block - stored in R27:R26 (X); new_stad: new starting address of the block - stored in R29:R28 (Y);Other variables:; temp_stor: temporary storage of the currently transferred byte - stored in R16; temp_stor2: register used coupled with "temp_stor" in order to check for the ; errors - stored in R17;Exit: - (the block has been transferred to a new location);Errors: ; ErrorA: orig_stad<$100 OR orig_stad+block_len>RAMEND-2 OR new_stad<$100 OR; new_stad+block_len>RAMEND-2 --> sets T flag, clears V flag; (inappropriate block bounds either for the old or the new location); ErrorB: orig_stad<new_stad AND orig_stad+block_len>new_stad ; --> sets both T and V flags; (overwriting part of the data before transferred); Empty block : T=V=0;Comments: -;--------------------.def block_len_L=R24.def block_len_H=R25.def orig_stad_L=R26 ; XL.def orig_stad_H=R27 ; XH.def new_stad_L=R28 ; YL.def new_stad_H=R29 ; YH.def temp_stor=R16.def temp_stor2=R17;----------MOV_BLOCK:

tst block_len_Lbrne check_AAtst block_len_Hbreq skip_all ; block_len=0, nothing to move

check_AA:tst orig_stad_Hbreq inconsA ; orig_stad<$100tst new_stad_Hbreq inconsA ; new_stad<$100movw temp_stor, new_stad_Ladd temp_stor, block_len_Ladc temp_stor2, block_len_Hcpi temp_stor2, $10 ; if temp_stor2:temp_stor>$10FE --> ErrorA

(2α)

(2α)

Page 27: programsAVR.2

brlo new_ad_eligible ; temp_stor2<$10 --> no ErrorA for this checkbrne inconsA ; temp_stor2>$10 --> ErrorAcpi temp_stor, $FEbrsh inconsA

new_ad_eligible:movw temp_stor, orig_stad_Ladd temp_stor, block_len_Ladc temp_stor2, block_len_Hcpi temp_stor2, $10 ; if temp_stor2:temp_stor>$10FE --> ErrorAbrlo eligible ; temp_stor2<$10 --> no ErrorA for this checkbrne inconsA ; temp_stor2>$10 --> ErrorAcpi temp_stor, $FEbrsh inconsA

eligible:cp temp_stor2, new_stad_H ; checking if orig_stad+block_len>new_stadbrlo error_freebrne check_BBcp new_stad_L, temp_storbrsh error_free

check_BB:cp new_stad_H, orig_stad_H ; checking if orig_stad<new_stadbrlo error_freebrne inconsBcp new_stad_L, orig_stad_Lbrsh inconsB ; it covers also the case when new_stad=orig_stad, which

; could be considered as a separate error, since there is no; meaning to write the data at the same address it is read from,

; but it doesn't create any unpleasant consequences. There is no; check if new_stad=orig_stad when orig_stad+block_len<=new_stad

error_free:ld temp_stor, X+st Y+, temp_storsbiw block_len_L, 1tst block_len_Lbrne error_freetst block_len_Hbrne error_freecltsevret

skip_all:cltclvret

inconsB:setsevret

inconsA:setclvret

;----- End of subroutine MOV_BLOCK -----.undef block_len_L.undef block_len_H

(3)

(2α)

(2α)

(2α)

(2α)

(2β)

(2β)

(3)

(ii)

(ii)

Page 28: programsAVR.2

.undef orig_stad_L

.undef orig_stad_H

.undef new_stad_L

.undef new_stad_H

.undef temp_stor

.undef temp_stor2

Σχόλια σχετικά με την ανάπτυξη του κώδικα:(1) Το μέγιστο μήκος του συμπαγούς τμήματος δεδομένων δεν περιορίζεται από την 16-bit

μεταβλητή του πλήθους των bytes (θα μπορούσε να φτάσει τα 65535), αλλά από την συνολική ποσότητα της SRAM. Έτσι θεωρώντας ότι υπάρχουν 4 KB SRAM, το μέγιστο μήκος του συμπαγούς τμήματος δεδομένων είναι:- $1000-2-d-a, όταν orig_stad>new_stad- ($1000-2-a)/2, όταν orig_stad<new_stad (ώστε να μην υπάρξει αποθήκευση σε διευθύνσεις

με χρήσιμα δεδομένα πριν αυτά αντιγραφούν στις νέες διευθύνσεις τους), όπου:2: χώρος στην Στοίβα για την διεύθυνση επιστροφής της υπορουτίναςd: απόλυτη απόσταση (σε bytes) της παλιάς και νέας διεύθυνσης από την οποία ξεκινάει το συμπαγές τμήμα δεδομένωνa: χώρος στην SRAM που καταλαμβάνεται από άλλα δεδομένα

(2) Υπάρχουν δύο περιπτώσεις λάθους. Στην μία τα όρια (παλιά ή νέα) του συμπαγούς τμήματος δεδομένων βρίσκονται εκτός του επιτρεπτού (ErrorA) και στην άλλη έχουμε αποθήκευση σε διευθύνσεις με χρήσιμα δεδομένα πριν αυτά αντιγραφούν στις νέες διευθύνσεις τους (ErrorB). Αν επιλεγεί να αρχίσει η αντιγραφή των στοιχείων από το τελευταίο προς το πρώτο, η δεύτερη περίπτωση συναντάται με αντιστραμμένη στην συνθήκη για τον έλεγχο την θέση των orig_stad και new_stad.

(3) Η τιμή $10FE χρησιμοποιείται καταχρηστικά, θεωρώντας ότι στην Στοίβα υπάρχει μόνο η διεύθυνση επιστροφής της υπορουτίνας. Θεωρητικά θα μπορούσε να γίνει σύγκριση με την τρέχουσα τιμή του Δείκτη Στοίβας (SP), αλλά και αυτό δεν αποτελεί ουσιαστική λύση αφού σε μια γενική εφαρμογή που τυχόν αξιοποιηθεί η υπορουτίνα θα επιτρέπονται οι διακοπές. Έτσι αν και κατά τον έλεγχο με τον SP μπορεί να μην υπάρχει λάθος, αν αμέσως μετά συμβεί διακοπή ο SP θα μεταβληθεί περαιτέρω (το πόσο εξαρτάται από τον κώδικα της ISR). Κανονικά θα πρέπει ο προγραμματιστής να έχει πρόβλεψη του μέγιστου πιθανού όγκου της Στοίβας και να θεωρήσει λάθος την επικάλυψη του συμπαγούς τμήματος δεδομένων με την Στοίβα όταν αυτή έχει μέγιστο όγκο.

(4) Οι τιμές των orig_stad και new_stad έχουν αλλοιωθεί (δείχνουν μετά και το τελευταίο byte του συμπαγούς τμήματος), όπως και το block_len. Συνεπώς δεν υπάρχει πρόβλεψη για επιστροφή των orig_stad και new_stad στις αρχικές τους τιμές. Πιο συνετό ίσως θα ήταν να γίνει η μεταφορά του συμπαγούς τμήματος από το τέλος προς την αρχή (γεγονός που απαιτεί και αλλαγή της συνθήκης επικάλυψης). Χρήσιμο θα ήταν να αναπτυχθεί αυτή η εναλλακτική προσέγγιση και να συγκριθούν οι δύο υλοποιήσεις.

Page 29: programsAVR.2

Z3) Pointer to element in 2 Dimensional Array

Αντικείμενο : ο Υπολογισμός της διεύθυνσης ενός στοιχείου δισδιάστατου πίνακα 1-byte στοιχείων (elem_ad). Δίνονται η γραμμή (elem_row) και η στήλη (elem_col) του συγκεκριμένου στοιχείου, ο αριθμός στηλών του πίνακα (numof_cols) και η αρχική διεύθυνση του πίνακα (arst_ad). Ο πίνακας είναι αποθηκευμένος κατά αύξουσα γραμμή (row major order, πρώτα αποθηκεύονται όλα τα στοιχεία της πρώτης γραμμής, μετά της δεύτερης, κ.ο.κ.), η πρώτη γραμμή και η πρώτη στήλη δεικτοδοτούνται με το μηδέν και μέγιστος αριθμός γραμμών και στηλών είναι το 256.Επίσης γίνεται χρήση των καταχωρητών R1:R0 για αποθήκευση του γινομένου του πολλαπλασιασμού.

Κρίσιμα σημεία ελέγχου κατά το debugging:Ποιες είναι οι περιπτώσεις λάθους? Είναι δυνατός ο έλεγχος όλων των περιπτώσεων στην αρχή της υπορουτίνας?

Page 30: programsAVR.2

Διάγραμμα ροής της προτεινόμενης υλοποίησης:

Start

elem_ad = elem_row * numof_colselem_ad = elem_ad + elem_col

arst_ad < $100?

No

elem_ad < RAMEND - a?

No

Yes

Flag correct result

EndYes

(i)

numof_cols = 0?

Yes

No

(i)

(i)

End

Page 31: programsAVR.2

Κώδικας της προτεινόμενης υλοποίησης :

;-------------------- Pointer to element in 2 Dimensional Array --------------------;Title: POINT_2D_AR;Purpose: Calculation of the pointer to an element in an two-dimensional array of ; one-byte elements, given the element's row and column number; ! array is stored in row major order (first is stored all the elements of the ; ! first row, then the second's and so on; ! only the number of array's columns is required; the maximum num of array ; ! elements is undefined (since the number of rows is unknown);Input Parameters: ; arst_ad: array's starting address - stored in R19:R18 - unaltered; elem_row: element's row number - stored in R16 - unaltered; ( 0 <= elem_row < numof_rows); elem_col: element's column number - stored in R17 - unaltered; ( 0 <= elem_col < numof_cols); numof_cols: the number of columns in the array - stored in R20 - unaltered;Other variables:; elem_ad: address of the specific element (output parameter) - stored in R29:R28;"Special purpose" Registers used: R1, R0;Exit: "elem_ad" holds a pointer to the specific element;Errors: ; ErrorA: numof_cols = 0 --> sets T flag, clears V flag; (it must be at least 1, in case we consider an 1-dimensional array); ErrorB: arst_ad<$100 OR elem_ad>RAMEND-2 --> sets both T and V flags; (ineligible array starting address (too low) or ineligible element's address; (the array is too long to be stored in the SRAM, resulting in overwriting of; Stack and possibly SRAM pointer overrunning RAMEND);Comments: ; - elem_ad = arst_ad+(elem_row*numof_cols+elem_col);--------------------.def arst_ad_L=R18.def arst_ad_H=R19.def elem_row=R16.def elem_col=R17.def numof_cols=R20.def elem_ad_L=R28 ; YL.def elem_ad_H=R29 ; YH;----------POINT_2D_AR:

tst numof_colsbreq incons_A ; ErrorAtst arst_ad_Hbreq incons_B ; ErrorB: ineligible array_starting_address (too low)mul elem_row, numof_colsmovw elem_ad_L, R0 add elem_ad_L, elem_colbrcc no_incrinc elem_ad_H

no_incr:add elem_ad_L, arst_ad_Ladc elem_ad_H, arst_ad_Hcpi elem_ad_H, $10 ; if elem_ad>=$10FE --> ErrorBbrlo accept_result ; elem_ad_H<$10 --> no ErrorBbrne incons_B ; elem_ad_H>$10 --> ErrorB

(1)

(2)

(2)

(3)(i)

(i)

(i)

Page 32: programsAVR.2

cpi elem_ad_L, $FE ; since test_ad_H=$10 check also elem_ad_Lbrlo accept_result

incons_B:setsevret

incons_A:setclvret

accept_result:cltclvret

;----- End of subroutine POINT_2D_AR -----.undef arst_ad_L.undef arst_ad_H.undef elem_row.undef elem_col.undef numof_cols.undef elem_ad_L.undef elem_ad_H

Σχόλια σχετικά με την ανάπτυξη του κώδικα:(1) Για μονοδιάστατο πίνακα θα είχαμε numof_cols = 1.(2) Γίνεται έλεγχος μόνο για το κάτω όριο του πίνακα, δεδομένου ότι η διεύθυνση του τελευταίου

του στοιχείου είναι άγνωστο που βρίσκεται (για τον προγραμματιστή της υπορουτίνας) και ούτως ή άλλως δεν αφορά τη συγκεκριμένη υπορουτίνα. Γίνεται όμως μετέπειτα έλεγχος αν είναι επιτρεπτή η διεύθυνση του στοιχείου που υπολογίστηκε από την υπορουτίνα.

(3) Για την βελτιστοποίηση του κώδικα παίζει σημαντικό ρόλο η σωστή εκλογή των εντολών υπό συνθήκη άλματος (σε συνδυασμό με τις σταθερές με τις οποίες έγιναν οι συγκρίσεις) αλλά και της σειράς με την οποία χρησιμοποιούνται.