Upload
mcrae
View
214
Download
1
Embed Size (px)
DESCRIPTION
programsAVR.2
Citation preview
Ε)ΠΡΟΓΡΑΜΜΑΤΑ ΜΕΤΑΤΡΟΠΗΣ ΚΩΔΙΚΑ
Ε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:Πολύ απλό πρόγραμμα για να δοθούν γενικής φύσης κρίσιμα σημεία ελέγχου.
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
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
Κώδικας της προτεινόμενης υλοποίησης:
;-------------------- 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)
(2) Τέτοιες υπορουτίνες αποτελούν κλασικές περιπτώσεις υπορουτινών βιβλιοθήκης. Καλό είναι να χρησιμοποιούνται κατά το δυνατό ελάχιστοι καταχωρητές και να μην αλλοιώνεται το περιεχόμενο των καταχωρητών που περιέχουν τις παραμέτρους εισόδου.
Ε2) Conversion of ASCII Hex to Binary
Αντικείμενο : η Μετατροπή ενός δεκαεξαδικού αριθμού αποτελούμενου από 2 ASCII bytes (msaschex:lsaschex) σε δυαδικό αριθμό (1-byte, binary_num).
Κρίσιμα σημεία ελέγχου κατά το debugging:Χρειάζεται προσοχή στα όρια με τα οποία γίνονται οι συγκρίσεις σε συνδυασμό με τις εντολές υπό συνθήκη άλματος.
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
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
Κώδικας της προτεινόμενης υλοποίησης:
;-------------------- 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
inel_hex_digit:setret
;----- End of subroutine CONV_AHEX_BIN -----.undef lsaschex.undef msaschex.undef binary_num
Σχόλια σχετικά με την ανάπτυξη του κώδικα:Απλό πρόγραμμα με πολλαπλούς ελέγχους ορίων, που προσφέρει εξοικείωση με την αναπαράσταση των χαρακτήρων σε ASCII μορφή.
Ε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:Πολύ απλό πρόγραμμα για να δοθούν γενικής φύσης κρίσιμα σημεία ελέγχου.
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
Start
Z := led7_table << 1Z := Z + bcd_digitled7_code := [Z]
bcd_digit < 10?
No
End
Yes
led7_code := $30
Κώδικας της προτεινόμενης υλοποίησης:
;-------------------- 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
Σχόλια σχετικά με την ανάπτυξη του κώδικα:
Χρειάζεται καλή περιγραφή της αντιστοίχισης των led με κάθε bit στα σχόλια, προκειμένου να διευκολυνθεί η χρήση της υπορουτίνας από τρίτους ή μελλοντικά
ΣΤ) ΠΡΟΓΡΑΜΜΑΤΑ ΕΠΕΞΕΡΓΑΣΙΑΣ ΣΥΜΒΟΛΟΣΕΙΡΑΣ
ΣΤ1) String concatenation
Αντικείμενο : η Συνένωση δύο συμβολοσειρών, τοποθετώντας την δεύτερη αμέσως μετά την πρώτη. Δίνεται ακόμη μέγιστο επιτρεπτό μήκος για τη νέα συμβολοσειρά (concat_len). Το μήκος κάθε συμβολοσειράς αποθηκεύεται στο πρώτο byte της.
Στην υλοποίηση που ακολουθεί χρησιμοποιήθηκαν ακόμη οι τοπικές μεταβλητές:- temp1: προσωρινή αποθήκευση του μήκους της δεύτερης συμβολοσειράς, του μήκους της
νέας συμβολοσειράς και του αριθμού των χαρακτήρων που υπολείπονται προς αντιγραφή (θα μπορούσαν να χρησιμοποιηθούν τρεις διαφορετικές μεταβλητές – καταχωρητές, όμως έχει γίνει προσπάθεια εξοικονόμησης κατά το δυνατό)
- temp2: προσωρινή αποθήκευση του αρχικού μήκους της πρώτης συμβολοσειράς και του χαρακτήρα που τελεί υπό αντιγραφή
- temp_ad: προσωρινή διεύθυνση όπου αποθηκεύονται οι χαρακτήρες κατά την αντιγραφή
Κρίσιμα σημεία ελέγχου κατά το debugging:(i) Ποιες είναι οι περιπτώσεις που δεν θα προστεθεί τίποτα στο τέλος της πρώτης συμβολοσειράς?(ii) Ποιοι έλεγχοι υποδεικνύουν ότι θα προστεθεί τμήμα μόνο της δεύτερης συμβολοσειράς στο
τέλος της πρώτης? (όλα τα μήκη δίνονται από 1-byte αριθμό)(iii) Κατά την πρώτη αντιγραφή χαρακτήρα, από ποια διεύθυνση θα διαβαστεί το byte και σε
ποια θα αποθηκευτεί? (το μήκος της συμβολοσειράς είναι ενσωματωμένο σε αυτήν)(iv)Ποιο είναι το μήκος της νέας συμβολοσειράς? (δεν είναι πάντα το ίδιο)
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
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)
Κώδικας της προτεινόμενης υλοποίησης:
;-------------------- 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)
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)
ΣΤ2) DESIGN NOTE #043 (www.avrfreaks.net)
ΣΤ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) Όταν το μήκος της κύριας συμβολοσειράς είναι ίσο με το μήκος της υπο-συμβολοσειράς
θα εκτελεστεί ο εσωτερικός βρόχος? (πρέπει να γίνει έλεγχος αφού οι δύο συμβολοσειρές μπορεί να είναι ταυτόσημες)
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
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
Κώδικας της προτεινόμενης υλοποίησης :
;------------------ 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)
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)
(3) Η αρχική τιμή του counter1 ισούται με τη διαφορά των χαρακτήρων των δύο συμβολοσειρών επαυξημένης κατά ένα.
Ζ) ΠΡΟΓΡΑΜΜΑΤΑ ΕΠΕΞΕΡΓΑΣΙΑς ΣΤΟΙΧΕΙΩΝ ΠΙΝΑΚΑ
Ζ1) AVR102 :BLOCK COPY ROUTINES (Site Atmel)
Ζ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) Χρειάζεται προσοχή στις σταθερές και την σειρά των ορισμάτων που χρησιμοποιούνται
στις συγκρίσεις (σε συνδυασμό και με τις εντολές υπό συνθήκη άλματος). Μερικές φορές εξυπηρετεί καλύτερα η αύξηση ή μείωση κατά ένα της σταθεράς ή αντιμετάθεση των ορισμάτων.
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
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
Κώδικας της προτεινόμενης υλοποίησης :
;-------------------- 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α)
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)
.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 στις αρχικές τους τιμές. Πιο συνετό ίσως θα ήταν να γίνει η μεταφορά του συμπαγούς τμήματος από το τέλος προς την αρχή (γεγονός που απαιτεί και αλλαγή της συνθήκης επικάλυψης). Χρήσιμο θα ήταν να αναπτυχθεί αυτή η εναλλακτική προσέγγιση και να συγκριθούν οι δύο υλοποιήσεις.
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:Ποιες είναι οι περιπτώσεις λάθους? Είναι δυνατός ο έλεγχος όλων των περιπτώσεων στην αρχή της υπορουτίνας?
Διάγραμμα ροής της προτεινόμενης υλοποίησης:
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
Κώδικας της προτεινόμενης υλοποίησης :
;-------------------- 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)
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) Για την βελτιστοποίηση του κώδικα παίζει σημαντικό ρόλο η σωστή εκλογή των εντολών υπό συνθήκη άλματος (σε συνδυασμό με τις σταθερές με τις οποίες έγιναν οι συγκρίσεις) αλλά και της σειράς με την οποία χρησιμοποιούνται.