sâmbătă, 17 noiembrie 2012

Acces indirect la memoria SRAM. Tablouri. Prelucrarea tablourilor

Tablouri

    Un tablou este o succesiune de variabile accesibile printr-un nume unic. În limbajul ASM nu putem vorbi despre un tip sepecial de date. Oricare structură de date simplă sau complexă este reprezentată de o zona de memorie alocată acestei structuri. Acest lucru este valid şi pentru tablouri, adică se va rezerva o zonă de memorie accesibilă prin numele de referinţă a lui.

 Exemplu:
    .EQU TAB_SIZE = 10     ; declaratie constanta
    .DSEG                  ; tablourile vor fi declarate in
                           ; segmentul de date
    tab: .byte TAB_SIZE    ; utilizare constanta in 
                           ; declaratie tablou

    Din acest exemplu nu putem spune câte locaţii are tabloul, însă presupunând că elementele tabloului sunt de tip byte adică ocupă un singur byte în memorie, vom afirma ca tab este un tablou de 10 elemente de tip byte.

    Dacă vom dori să alocăm memorie pentru un tablou (să declarăm un tablou), cu elemente de o mărime mai mare de un byte atunci mărimea memorie alocate va fi un produs dintre mărimea unui element a tabloului şi numărul de elemente dorite pentru tablou.

 Exemplu:
    .EQU ITEM_SIZE = 2
    .EQU TAB_SIZE = 10 * ITEM_SIZE
    .DSEG
    tab: .byte TAB_SIZE

    Accesul la elementele tabloului nu este altceva decât accesul la adresa acestuia în memorie. Adică de exemplu dacă am dori să citim valoarea elementului 4 din dintr-un tablou de byte: R16 = tab[4], vom avea:
  
    .EQU TAB_SIZE = 10
    .DSEG
    tab: .byte TAB_SIZE
    
    .CSEG
        lds r16, tab+4





Accesul indirect la memorie 

    Metoda de mai sus este una de acces direct la memorie, care este utilă în cazul în care avem un nevoie de un acces la un element fix în memorie. Însă este inacceptabilă cînd avem nevoie de un acces mai flexibil, cum ar fi iterarea printr-un tablou. Într-un acces care presupune iterarea prin tablou sau un acces dinamic la elementele tabloului este mai comed de utilizat accesul indirect la memorie, care presupune că adresa de acces la locaţia de memorie dorită se află într-un registru indirect. Microcontrollerul din seria AVR are un set de trei perechi de regiştri, din regiştrii de uz genral, pentru accesul indirect la memorie.

    R27:R26  X  XH:XL  
    R29:R28  Y  YH:YL  
    R31:R30  Z  ZH:ZL  


    Pentru acces indirect avem următoarele comenzi:
      a) încărcare indirectă    b) stocare indirectă
    ld R, X          st X, R
    ld R, Y          st Y, R
    ld R, Z          st Z, R


încă o dată menţionam că în caz de acces la o locație din RAM unul dintre registrii X,Y,Z va trebui să conţină adresa locaţiei date. Respectiv va trebui sa efectăum o iniţializare a registrului indirect utilizat înainte de a accesa locaţia dorită.

        .DSEG
        a: .byte 1

        .CSEG
            ...
            ; a →X
            ldi XL, LOW(a)
            ldi XH, HIGH(a)
            ld R16, X
            ...


Acces indirect relativ la memorie (cu deplasament)

     Acest tip de acces permite accesul la memorie cu un deplasament fix q. Deoarece q este reprezentat în comanda de 6 biți respectiv accesul indirect relativ este posibil într-o zonă de 64 de adrese din apropierea registrului.


    ldd R, Y+q    std Y+q, R
    ldd R, Z+q    std Z+q, R
    
    


       Deoarece alocarea memoriei pentru variabile se face la o adresă concretă, constantă, diferenţa dintre adrese este la fel una constantă, care poate servi drept deplasament pentru accesul celei de a doua variabile, în cazul când registrul indirect indică către prima.

Exemplu:
    .dseg
    a: .byte 1
    b: .byte 1
    .cseg
        ...     ;a = b
        ldi YH, HIGH(a)
        ldi YL, LOW(a)
        ld R16, Y
        std Y+(b-a), R16    ; q=(b-a)
        ... 


Acces indirect iterativ


    Accesul indirect, presupunînd că adresa de acces se află într-un registru, permite accesul dinamic într-o zonă de memorie, modificând registrul indirect, de fapt modificăm adresa de acces la memorie.
    De foarte multe ori modificarea adresei de acces este una iterativă, permiţând parcurgerea tablourilor directă şi inversă.

 Acces indirect cu pre-decrementare

    Presupune că regiștrul de acces indirect de acces X,Y,Z este decrementat înainte de a accesa o locație

    ld R, -X          st -X, R
    ld R, -Y          st -Y, R
    ld R, -Z          st -Z, R



    Un asemenea acces este utilizat la prelucrări iterative a unei  zone de memorie in directie inversa.

Exemplu de umplere a unui tablou cu zerouri, stergere tablou:

    .dseg
    tab: .byte 100
   
    .cseg
        ...     ;clear tab
        ldi XL, LOW(tab+100)
        ldi XH, HIGH(tab+100)
        clr R15       ;R15 = 0
        ldi R17, 100
    loop:
        st -X, R15
        dec, R17
        (cpi R17, 0)
        brne  loop
        ...
 Accesul indirect cu post-încrementare
  
     Presupune accesul la locația dorită urmat de incrementare a registrului de acces indirect. Acest tip de acces este utilizat în operații iterative de prelucrare a memoriei în direcţia de la primul element spre ultimul. 


    ld R, X+          st X+, R
    ld R, Y+          st Y+, R
    ld R, Z+          st Z+, R




Exemplu de copiere a conţinutului unui tablou în altul:

    .dseg
    tabA: .byte 100
    tabB: .byte 100

    .cseg
        ...
    ;tabA = tabB (copy)
        ldi XL, LOW(tabA)
        ldi XH, HIGH(tabA)
        ldi YL, LOW(tabB)
        ldi YH, HIGH(tabB)
        ldi R17, 100
    loop:
        ld R16, X+
        st Y+, R16
        dec R17
        brne loop
        ...


Tablouri în calitate de parametri de intrare în subrutine.

    Din cîte cunoaştem despre transmiterea parametrilor către subrutine in ASM, va trebui să se iniţializeze un set de regiştri în acest scop. Numărul de regiştri utilzaţi va depinde în mare măsură de numărul de parametri şi de mărimea lor. Însă această metodă nu prea convine pentru transmiterea tablourilor, în special din cauza volumului de memorie pe care o poate ocupa, de cele mai multe ori mai mare decât numărul de regiştri existenţi. Pentru a transmite un tablou unei subrutine, se va transmite doar referinţa către acest tablou prin încărcarea adresei acesteia într-o pereche de regiştri. În cazul în care perechea de regiştri va fi unul din regiştrii indirecţi X, Y sau Z, va fi posibilă prelucrarea iterativă a tabloului fără iniţialzarea unui registru indirect în cadrul subrutinei. Pentru a transmite informaţia despre mărimea tabloului se poate recurge la transmiterea acesteia printr-un registru ca parametru suplimentar.

    Exemplu:



    .EQU N = 100
    .dseg
    tab: .byte N

    .cseg
        ...
        ldi XL, LOW(tab)
        ldi XH, HIGH(tab)
        ldi R16, N
        rcall ClearTab
        ...
        ...

    ClearTab:
        push r17
        clr r17
    loop:
        st X+, R17
        dec R16
        brne loop
        pop r17
        ret