UL/FRI/UNI-RI/ARS2/Vaje/ARM

Iz E-študij, proste zakladnice študentskega znanja

< UL | FRI | UNI-RI | ARS2 | Vaje
Skoči na: navigacija, iskanje

winIDEA, asmprojekt, ki ga dobiš na laps.fri, kodo pišemo v start.s, razdelek /*main program*/, konstante navajamo pri /*constants*/, morebitni halt izvedemo kot "label: b label". ..

Oglej si GNU ARM referenco in uporabljaj ARMv4t referenco ter ARM dokumentacijo. Vse je tam. :)

Vsebina

[uredi] 1. Naloga

Seštejte dve 64-bitni števili: spr1 = spr1 + spr2, kjer je spr1= 0x00000001F0000000 in spr2=0x0000000010000000. Pomagajte si z zastavico C. Opozorilo: ukazi spreminjajo stanje zastavic le, če to zahtevamo (s). Spremenljivki naj bosta v pomnilniku takoj za konstantami. Naslov spremenljivke dobimo v register s pomočjo psevdoukaza adr. Program naj okvirno zgleda tako:

          adr r0, spr1
          ldr r1, [r0]
          ldr r2, [r0, #4]
          ...
          ...
  _Lforever:
          b _Lforever
          ...
  .global _vars
  _vars:
  spr1:   .word 0x00000001, 0xF0000000
  spr2:   ...
  .end 

Opozorilo: s pomočjo adr lahko v register naložimo naslov spremenljivke le, če je ta dovolj blizu trenutnemu pc. Če temu ni tako, uporabimo ldr r0, =spr1. ldr je v tem primeru psevdoukaz! Preverite, v kakšen ukaz se prevede!

 /* main program */
   adr r0,spr1
   ldr r1,[r0]
   ldr r2,[r0,#4]
   ldr r3,[r0,#8]
   ldr r4,[r0,#12]
   adds r6,r2,r4
   adc r5,r1,r3
l: b l
 /* constants */
   spr1: .word 0x00000001,0xF0000000
   spr2: .word 0x00000000,0x10000000

[uredi] 2. Naloga

Napišite program, ki ustreza naslednjemu programu v c-ju:

if(r0 != 5) {
    r1=r1+r0-r2;
}

Uporabite cmp in pogojno izvajanje ukazov. Pomagajte si s prosojnicami.

 /* main program */
   adr r3,spr1
   ldr r0,[r3]
   ldr r2,[r3,#4]
   cmp r0,#5
   addne r1,r1,r0
   subne r1,r1,r2 
l: b l
 /* constants */
   spr1: .word 4,5

[uredi] 3. Naloga

Napišite program, ki ustreza naslednjemu programu v c-ju:

if(r0 > r1){
    r0 = r0 - r1;
}else{
    r1 = r1 - r0;
}

Nato napišite program za iskanje največjega skupnega delitelja s pomočjo Evklidovega algoritma, ki je podan tako:

while(r0 != r1) {
    if(r0 > r1) {
        r0 = r0 - r1;
    }else{
        r1 = r1 - r0;
    }
}

Algoritem preizkusite z majhnimi števili (da je konstanto mogoče naložiti v register s pomočjo ukaza mov).

/* main program */
 mov r0,#39
 mov r1,#35
 cmp r0,r1
 subhi r0,r0,r1    /* SKOK SEM */
 sublo r1,r1,r0
 cmp r0,r1
 subne pc,pc,#24 /* pc===r15; skočit mormo nazaj na cmp r0,r1 - torej mormo odštet 24 od pc-ja*/ 

EDIT: mogoče bi bilo boljše če dodamo pred cmp oznako WHILE, in PC povečamo tako: adr r15, WHILE

Alt. rešitev

_main:

mov r0, #35
mov r1, #7

while: cmp r0,r1
 beq _wait_for_ever
 subgt r0,r0,r1
 sublt r1,r1,r0
 b while
 
_wait_for_ever:
 b _wait_for_ever

[uredi] 4. Naloga

Napišite program, ki kopira elemente iz ene tabele v drugo. V tabelah naj bo po 5 32-bitnih števil. Tabeli naj bosta takoj za konstantami (kot v nalogi 1).

 /* main program */
 adr r1,tab1
 adr r2,tab2
 mov r5,#5
 
 /* POSREDNO *
 mov r0,r5
 ldr r3,[r1]  /*SKOK SEM*/
 str r3,[r2]
 add r1,r1,#4
 add r2,r2,#4
 subs r0,r0,#1
 subne r15,r15,#28
 /*          */
 
 /* POSREDNO POST-INCREMENT */ 
 mov r0,r5
 ldr r3,[r1],#4 /*SEM*/
 str r3,[r2],#4
 subs r0,r0,#1
 subne r15,r15,#20
 /*          */
 
 /* POSREDNO Z REGISTRSKIM ODMIKOM *
 mov r0,#0
 ldr r3,[r1,r0, lsl #2]
 str r3,[r2,r0, lsl #2]
 add r0,r0,#1
 cmp r0,#5
 subne r15,r15,#24
 /*          */
 
 /* LOAD MULTIPLE - 5 REGISTROV */
 ldmia r1,{r6-r10}
 stmia r2,{r6-r10}
 /*          */
 
l: b l
 
 /* constants */
 tab1: .word 1,2,3,4,0x00000005
 tab2: .word 0,0,0,0,0

[uredi] 5. Naloga

Napišite podprogram, ki vrne število negativnih števil v tabeli. Podprogram sprejme dva parametra: v r0 je naslov tabele (kazalec na tabelo), v r1 pa število elementov v tabeli. Po koncu podprograma naj bo rezultat v r0. Podprogram naj na začetku na sklad (r13, sklad je že inicializiran) shrani vse delovne registre in povratni naslov (r14). Pred vrnitvijo naj delovne registre obnovi. Vstopna in izstopna točka (vključno z vračanjem v glavni program) sta pri optimalnem programiranju dolgi le po en ukaz! Sklad naj bo podoben tistemu, ki smo ga uporabljali pri programiranju HIP-a. Na skladu so 32 bitne vrednosti, r13 naj kaže na prosto mesto, sklad naj se širi proti nižjim naslovom (Empty Descending).

 /* main program */
   adr r0,tab1
   mov r1,#8
   bl podprogram
   b l
podprogram:  
   stmed sp,{r1-r3,r14} /* sp (stack pointer) === r13 */
   mov r3,#0

   ldr r2,[r0],#4
   cmp r2,#0
   addlt r3,r3,#1
   subs r1,r1,#1
   subne r15,r15,#24 

   add r0,r3,#0
   ldmed r13,{r1-r3,r14}
   bx r14

l: b l 
 /* constants */
tab1: .word 1,2,-3,4,0x00000005,0xF0000000,-17,2457


Alt. rešitev

_main:

 ldr r0, =spr1
 mov r1, #4
 bl pp

_wait_for_ever:
  b _wait_for_ever

pp:
stmed r13!,{r2-r12}
mov r2, #0
mov r3, #0

loop:
 ldr r4,[r0,r3]
 cmp r4,#0
 addlt r2,r2, #1
 add r3,r3, #4
 subs r1,r1,#1
 bne loop
 
 mov r0,r2
 ldmed r13!,{r2-r12}
 mov pc,r14

/* end user code */

/* constants */

.global _vars
_vars:
spr1: .word 5, -3, -2, 3

[uredi] 6. Naloga

Psevdoukaza ldr in adr, ponovitev. Napišite program, ki ustreza programu v c-ju: a = b + c; a, b in c so 32-bitne spremenljivke, ki naj bodo v pomnilniku tik za programom. Najprej proučite naslednjo obliko psevdoukaza ldr: ldr r0, b. Napišite ustrezen program v zbirnem jeziku. V kakšen ukaz se prevede ldr r0, b? Kateri pogoj mora biti izpolnjen, da lahko uporabljamo tako obliko ldr? Namig: odmik. Nato program napišite še z uporabo psevdoukazov oblike ldr r0, =b. V kakšen ukaz se prevede ldr te oblike? Zakaj so lahko sedaj spremenljivke kjerkoli v naslovnem prostoru? Kdaj lahko ldr r0, =b nadomestimo za adr r0, b in zakaj je to smiselno?

/* main program */  
   ldr r0,b  /* ldr r0,[pc,0020] */
   ldr r1,=b /* ldr r0,[pc,0028] - nalozi se naslov*/
   adr r2,b  /* add r2,pc,#18 - naslov */
 
   ldr r0,b
   ldr r1,c
   add r0,r0,r1
   str r0,a
           
l: b l  
/* constants */
a: .word 0
b: .word 1
c: .word 2

[uredi] 7. Naloga

Napišite program v zbirnem jeziku, ki ustreza naslednjemu programu za množenje dveh števil s pomočjo seštevanja v c-ju:

int multiplicand, multiplier;
int product;
if (multiplier > 255)
    product = -1; /* Error condition */
else if (multiplier < 0)
    product = -1; /* Error condition */
else {
    product = 0;
    while (multiplier > 0) {
        product = product + multiplicand;
        multiplier = multiplier - 1;
    }
}
/* main program */
 mov r1,#2    /* 2 */
 mov r2,#3    /* 3 */
 cmp r1,#0xFF
 movhi r0,#-1
 bhi end
 cmp r1,#0
 movlt r0,#-1
 blt end
 mov r0,#0
 addne r0,r0,r2  /* =6 */
 subnes r1,r1,#1
 subne r15,r15,#16
end:  
 b end

[uredi] 8. Naloga

Napišite program v zbirnem jeziku, ki ustreza izboljšanemu programu za množenje dveh števil v c-ju:

void main(void){
    int multiplicand, int multiplier;
    int product;
    if (multiplier > 255)
        product = -1; /* Error condition */
    else if (multiplier < 0)
        product = -1; /* Error condition */
    else {
        product = 0;
        if (multiplier >= 128) {
            product = product + (multiplicand << 7);
            multiplier = multiplier - 128;
        }
        if (multiplier >= 64) {
            product = product + (multiplicand << 6);
            multiplier = multiplier - 64;
        }
        if (multiplier >= 32) {
            product = product + (multiplicand << 5);
            multiplier = multiplier - 32;
        }
        if (multiplier >= 16) {
            product = product + (multiplicand << 4);
            multiplier = multiplier - 16;
        }
        if (multiplier >= 8) {
            product = product + (multiplicand << 3);
            multiplier = multiplier - 8;
        }
        if (multiplier >= 4) {
            product = product + (multiplicand << 2);
            multiplier = multiplier - 4;
        }
        if (multiplier >= 2) {
            product = product + (multiplicand << 1);
            multiplier = multiplier - 2;
        }
        if (multiplier >= 1) {
            product = product + multiplicand;
            multiplier = multiplier - 1;
        }
    }
}

Predpostavite, da sta na začetku množenec in množitelj v registrih r0 in r1. Na koncu naj bo produkt v r0. Za množenje s potencami števila 2 uporabite hitri pomikalnik (drugi operand pri add). Z uporabo pogojnega izvajanja ukazov dobite elegantno rešitev.

glej 9.

[uredi] 9. Naloga

Program iz prejšnje naloge dodajte v projekt v c-ju (pomagajte si s projektom cpr1). Program preuredite v podprogram z imenom produkt8:

.global produkt8
.global _produkt8
produkt8:
produkt8:
...
mov pc, r14

Podprogram sme spremeniti vrednost registrom r0 – r3. Če uporablja še druge registre, jih shranite na sklad in na koncu obnovite. V datoteki main.c dodajte vrstico:

extern int produkt8(int a, int b);

sedaj lahko iz funkcije main() pokličete funkcijo produkt8.

datoteka: produkt8.s:

.global produkt8
.global _produkt8
produkt8:
produkt8:
 str r4,[r13]
 cmp r0,#0xFF
 movhi r2,#-1
 bhi end
 cmp r0,#0
 movlt r2,#-1
 blt end
 mov r2,#0
 mov r3,#7
 mov r4,#1
 cmp r0,r4, lsl r3
 addhs r2,r2,r1, lsl r3
 subhs r0,r0,r4, lsl r3
 sub r3,r3,#1
 cmp r3,#-1
 subne r15,r15,#28
 mov r0,r2
 ldr r4,[r13]
end:
 bx r14 /* RETURN */

datoteka: main.c

#include "Main.h"
extern  int produkt8(int,int); /* lepo dela tudi brez tega */
int main(void){ 
    int a = produkt8(111,3);
    while (1);      
}

[uredi] 10. Naloga

Vklopite oranžno LED diodo na FRI-SMS. Dioda je priključena na priključek PIO_PC1. Orientirajte ga izhodno. Nato izhod postavite v stanje 0. Pomagajte si s prosojnicami...

/* main program */
 .equ PIOC_BASE, 0xFFFFF800 /* Zacetek registrov za PIOC */
 .equ PIO_PER, 0x00	     /* Odmiki... */
 .equ PIO_OER, 0x10
 .equ PIO_SODR, 0x30        /* .equ je neke vrste #define */
 .equ PIO_CODR, 0x34
 
 ldr r0, =PIOC_BASE
 mov r1, #1 << 1
 str r1, [r0, #PIO_PER]	/* Prikljucek C1 krmili PIO */
 str r1, [r0, #PIO_OER]	/* Omogoci izhod - dioda sveti */

 /*str r1, [r0, #PIO_SODR]	/* Na prikljucek C1 zapisi stanje 1 - dioda ne sveti */
 str r1, [r0, #PIO_CODR]	/* Na prikljucek C1 zapisi stanje 0 - dioda sveti */

[uredi] 11. Naloga

S pomocjo programske zanke realizirajte podprogram za zakasnitev cca. 0,5 sekunde. Izracunajte koliko ciklov traja en obhod zanke (upoštevajte kontrolne nevarnosti pri skoku). Frekvenca ure je 192 MHz. Nato v zanki klicite podprogram in vklapljajte/izklapljajte oranžno LED diodo (0,5 s vklopljena, 0,5 s izklopljena, itd…).

 /* main program */
 
 ldr r0, =PIOC_BASE
 mov r1, #0x02
 str r1, [r0, #PIO_PER]	/* Priključek C15 krmili PIO */
 str r1, [r0, #PIO_OER]	/* Omogoci izhod */
 
 mov r6,#500                   /* naloži število ponavljanj prižiganja/ugašanja - seveda lahko naredite tudi neskončno zanko */
 it:
   str r1, [r0, #PIO_SODR]	/* ugasni LED */
    bl zanka                   /* skoči v podprogram, ki se izvaja 0.5 sekunde */
   str r1, [r0, #PIO_CODR]	/* prižgi LED  */
    bl zanka                   /*  skoči v podprogram, ki se (spet) izvaja 0.5 sekunde */
   subs r6,r6,#1               /* zmanjšaj število iteracij za 1 */
 bne it                        /* če smo iterirali 
 b _Lforever                   /* skok na konec programa */
 
 zanka:                        /* podprogram zanka */
  ldr r5,=24000000             /* 192MHz=192*10^6 / 4 * 0.5 = 24*10^6  */
   yanka:                      /* v zanki odštevamo do 0 */
     subs r5,r5,#1
   bne yanka
 mov r15,r14                   /* skočimo iz podprograma */



Ali je ta zanka in število ponovitev prav ?

Ziher ni. Frekvenca namreč ni 96 MHz ampak 196 MHz.

--> Če pomnite, se je workspace med potekom vaj spreminjal, zraven pa tudi sama frekvenca...

[uredi] 12. Naloga

Predelajte podprogram za zakasnitev iz prejšnje naloge. Uporabite časovnik TC0. Izberite ustrezno uro, da bo mogoče doseči podobno dolgo zakasnitev - časovnik naj šteje do vrednosti 0xffff. V zanki berite statusni register časovnika in preverjajte ustrezno zastavico. Zanka naj teče dokler se zastavica ne postavi na 1. Frekvenca periferne ure MCK je 48 MHz.

Pred kopiranjem si obvezno poberite najnovejši workspace iz arsove strani: [1] Potem ni več potrebno definirati /*define*/ polja, ker je že definirano vse potrebno na začetku datoteke.

     /* define */
    .equ TC0_BASE, 0xFFFA0000
    .equ PIOC_BASE, 0xFFFFF800
    .equ TC_CMR, 0x04
    .equ TC_CCR, 0x00
    .equ PIO_PER, 0x00	/* Odmiki... */
    .equ PIO_OER, 0x10
    .equ PIO_SODR, 0x30
    .equ PIO_CODR, 0x34
    .equ TC_SR, 0x20
 /* main program */
 /* user code here */
 
 _main:
 
 ldr r2, =PMC_PCER            /* vklopi uro za ID17 -> 17. bit*/
 mov r3, #0x20000             /* 2^17 -> hex -> 0x20000 */
 str r3, [r2]
 
 ldr r2,=TC0_BASE             /* naslov za posredno naslavljanje*/
 
 mov r3, #4                   /* izberi uro */
 str r3, [r2,#TC_CMR] 
 
 mov r3, #1                   /* omogoči uro...*/ 
 str r3, [r2,#TC_CCR]   
 
 mov r3, #4                   /*... & omogoči števec */
 str r3, [r2,#TC_CCR]  	
 
 ldr r0, =PIOC_BASE           /* vklopi LED diodo */
 mov r1, #0x02
 str r1, [r0, #PIO_PER]	/* Priključek C15 krmili PIO */
 str r1, [r0, #PIO_OER]	/* Omogoci izhod */
 
 streq r1, [r0, #PIO_CODR]	/* ugasni diodo */
 
 add r5,r5,#0                  /* v r5 spremenljivka za preverjanje sodosti/lihosti */

zanka:     
  ldr r4,[r2,#TC_SR]            /* preberi statusni register*/
  tst r4,#1                     /* poglej, če je zastavica COVFS enaka #1 */ 
  beq zanka                     /* če zastavica NI 1 (poglej TST ukaz!), ponovi zanko */ 
                                                                 
  tst r5,#1                    /* preveri samo prvi bit -> 2^n + 1 == liho število */
  streq r1, [r0, #PIO_SODR]	/* ugasni diodo, če je sod */
  strne r1, [r0, #PIO_CODR]	/* prižgi diodo, če lih */     
  add r5,r5,#1                 /* povečaj spremenljivko za 1 */
b zanka


a ta je kul?? jaz tule vidim več napak:

 ldr r2, =PMC_PCER   a ni PMC_PCSR? -> v dokumentaciji piše [Peripheral Clock Enable Register PMC _PCER]. Tako da pomoje je PCER ok.

Iz PMC_PCSR lahko le bereš, ker je to statusni register tako da ga ne moreš spreminjati!


potem še define

.equ PMC_PCER, 0x0018

popraviti je treba vrstici:

 mov r3, #1                   /* omogoči uro...*/ 
 str r3, [r2,#TC_CCR]   
 
 mov r3, #4                   /*... & omogoči števec */
 str r3, [r2,#TC_CCR]

ker v tem primeru ti drugi zapis v TC_CCR prvega pobriše. Zato narediš:

   mov r3, #5 /* 5 (101) = 4(100) (omogoci uro) + 1(001) omogoci stevec */  
   str r3, [r2,#TC_CCR]

Že res, ampak tako boš ostale nastavitve povozil Bulic pravi, da je pravilno prebrat & ANDat in potem storat nazaj. Ti registri nimajo onih parov, da bi lahko bit po bit popravljal.

Zakaj pa stvar deluje tudi če zgornjih komentarjev ne upoštevam ?

[uredi] 13. Naloga

Rešitev prejšnje naloge predelajte tako, da bo frekvenca utripanja LED natančno 1 Hz. Uporabite števec TC0, ki naj šteje do vrednosti, določene z RC. Pol sekunde naj bo LED prižgana, pol sekunde pa ugasnjena. Glejte prosojnice in tovarniško listino! Navodilo: LED prižigajte in ugašajte v podprogramu. Ta naj uporablja spremenljivko, kateri vsakič poveča vrednost za 1. Če je vrednost spremenljivke soda, naj LED ugasne, če je liha, naj LED prižge. Podprogram kličite v zanki vsake pol sekunde…

/* definiramo naslove registrov, ki jih bomo potrbovali */
   .equ TC0_BASE, 0xFFFA0000
   .equ PIOC_BASE, 0xFFFFF800
   .equ PMC_PCER, 0x10    /* Peripheral Clock Enable Register */ 
   .equ TC_CMR, 0x04
   .equ TC_CCR, 0x00
   .equ PIO_PER, 0x00
   .equ PIO_OER, 0x10
   .equ PIO_SODR, 0x30
   .equ PIO_CODR, 0x34
   .equ TC_SR, 0x20
   .equ TC_RC, 0x1C			/* TC0 Register C */
   ldr r1, =PMC_BASE   /* ID_TC0 = 17; bit 17 potrebno postavit 1 */
   mov r2, #0x20000
   str r2, [r1,#PMC_PCER]
   
   ldr r1, =TC0_BASE   /* nastavimo r1 na TC0_ BASE */
   
   mov r3, #4    /* izberemo uro TC0  */
   str r3, [r1, #TC_CMR]
   
   ldr r6, [r1, #TC_CMR]
   orr r3, r6, #6 << 13      /* 15bit 1, 14 bit 1 */
   str r3, [r1, #TC_CMR]
   
   adr r9, zakasnitev
   ldr r3, [r9]  
   str r3, [r1, #TC_RC]
   
   mov r3, #1    /* omogocimo uro  */
   str r3, [r1, #TC_CCR]
   
   mov r3, #4    /* sprozi stevec */
   str r3, [r1, #TC_CCR]
   
   ldr r0, =PIOC_BASE
   mov r6, #2
   str r6, [r0, #PIO_PER]	/* Priključek C15 krmili PIO */
   str r6, [r0, #PIO_OER]	/* Omogoci izhod, vklopi LED */
   
   mov r5, #0  /* stevec za vklapljanje in vgasanje ledice */
 LOOP: 
   ldr r4, [r1, #TC_SR]
   tst r4, #0x10    /* and bit0(r4) in 0..10000 */
   beq LOOP      /* ce bit0(r4) != 1 ponovimo */
   
   tst r5, #1    /* preverjamo samo prvi bit, if bit==0 je sodo */
   streq r6, [r0, #PIO_SODR]
   strne r6, [r0, #PIO_CODR]
   add r5, r5, #1
   b LOOP
   
 _Lforever:
 b _Lforever                              
 /* constants */
 
   zakasnitev: .word 32768

[uredi] 14. Naloga

Namesto čakanja na postavitev CPCS v zanki, konfiguirajte TC0 tako, da bo CPCS predstavljala prekinitveno zahtevo. Nato ustrezno konfigurirajte prekinitveni krmilnik (AIC). V grobem je potrebno narediti naslednje: V AIC_SMR17 vpišite primerno prioriteto, npr. 4. (0 – najnižja, 7 – najvišja); PERIPHERAL_ID TC0 je 17. V AIC_SVR17 vpišite naslov vašega PSP. Z vpisom 1 v bit 17 AIC_ECR omogočite prekinitve za TC0. Ne pozabite pobrisati bita I v CPSR. Vse to morate narediti pred preklopom v uporabniški režim. Pred izhodom iz PSP morate pisati (karkoli) v AIC_EOICR. PSP naj se kliče vsake pol sekunde, iz PSP pokličite podprogram za prižiganje/ugašanje LED iz prejšnje naloge. Glejte prosojnice in tovarniško listino!

/* nekam na vrh */
.equ AIC_BASE, 	0xFFFFF000 	/* Zacetek AIC */
.equ AIC_SMR17, 	0x44 		/* odmiki */
.equ AIC_SVR17, 	0xC4
.equ AIC_IVR,  	0x100
.equ AIC_IECR, 	0x120
.equ AIC_EOICR, 	0x130
ldr r0, =AIC_BASE
mov r1,#4
str r1,[r0, #AIC_SMR17]
ldr r1, =PrekinitvenoServisniProgram
str r1,[r0,#AIC_SVR17]
mov r1, #1 << 17
str r1,[r0,#AIC_IECR] 
/* user code here */
 /* naloži vse naslove, odmike, nato: */

 ldr r0, =PIOC_BASE
 mov r1, #2
 str r1, [r0, #PIO_PER]	/* Prikljucek C1 krmili PIO */
 str r1, [r0, #PIO_OER]	/* Omogoci izhod */

 ldr r0, =PMC_PCER
 mov r1, #1 << 17
 str r1, [r0]     /* vklopili power management za uro - timer 0 */
 
 ldr r2, =TC0_BASE
 ldr r1,=16500
 str r1, [r2, #TC0_RC]
 ldr r1, =0xC004   /* wave, wavesel(triger on CR), timer 4 = SLCK */
 str r1, [r2, #TC0_CMR]
 mov r1, #5             
 str r1, [r2, #TC0_CCR]
 mov r1, #16
 str r1, [r2, #TC0_IER] 

zanka:
 bal zanka
PrekinitvenoServisniProgram:
 sub lr,lr,#4
 stmfd sp!,{r0,r1,lr} 

 mrs r0, cpsr
 and r0,r0,#127  /* Omogoci prekinitve */
 msr cpsr_c,r0

 ldr r0,=PIOC_BASE
 ldr r1,[r0,#PIO_ODSR]
 tst r1,#2
 mov r1,#2

 strne r1, [r0, #PIO_CODR]
 streq r1, [r0, #PIO_SODR]

 ldr r0,=TC0_BASE
 ldr r1,[r0, #TC0_SR]

 mrs r0, cpsr
 orr r0,r0,#128  /* Onemogoci prekinitve */
 msr cpsr_c,r0

 ldr r1,=0xFFFFF130 /* AIC_BASE + AIC_EOICR */
 str r1,[r1]

 ldmfd sp!,{r0,r1}
 ldmfd sp!,{pc}^ /* ^ kopira spsr v cpsr */

[uredi] 15. Naloga

V tovarniški listini poiščite opis enote 'debug unit'. Uporabite serijski vmesnik te enote – ta je preko serijskega kabla povezan s serijskim vmesnikom na računalniku PC. Z vpisom primernih vrednosti v ustrezne registre naredite naslednje:

Za preizkus serijskega vmesnika napišite dva podprograma.

Podprograma preizkusite tako, da računalniku PC vračate znake, ki jih od njega sprejmete (echo) – podprograma izmenično kličete.

/* main program */
_main:
 ldr r0,=DBGU_BASE
 mov r1,#80          /* TX enable && RX enable */
 str r1,[r0,#DBGU_CR]
 mov r1,#2048       /* No Parity */
 str r1,[r0,#DBGU_MR]
 mov r1,#26          /* 48MHz / 16 / 26 == 115384 */
 str r1,[r0,#DBGU_BRGR]

loop:
 bl BERI
 bl PISI
 b loop

BERI:
 ldr r1,[r0,#DBGU_SR]
 ands r1,r1,#1
 beq BERI
 ldrne r1,[r0,#DBGU_RHR]
 movne r2,r1 
 bxne lr

PISI:
 ldr r1,[r0,#DBGU_SR]
 ands r1,r1,#2
 beq PISI
 strne r2,[r0,#DBGU_THR] 
 bxne lr

bal:bal bal

[uredi] 16. Naloga

Razhroščevalno enoto ('debug unit') nastavite tako, da bo znake sprejemala s pomočjo prekinitveno servisnega programa in oddajala s pomočjo DMA prenosov. Ostale nastavitve ostanejo enake tistim iz naloge 15. Pri tem napišite naslednje podprograme:

Ploščico priključite na PC še preko RS232 kabla in v WinIDEA-i odprite okno Terminal (lahko zaženete tudi Windows program Hyperterminal). Ob pravilnem delovanju glavnega programa in vseh podprogramov boste v terminalskem oknu za vsak vtipkan niz znakov dobili izpisana dva niza: izvorni in niz z obrnjenimi velikimi in malimi črkami.

.global _start
_start:

 ldr r0, =AIC_BASE
 mov r1,#4          /* Priority */
 str r1,[r0, #AIC_SMR1]
 ldr r1, =RX_PSP    /* RX Ready Interrupt Handler */
 str r1,[r0,#AIC_SVR1]
 mov r1, #2         /* Enable SYS Interrupts */
 str r1,[r0,#AIC_IECR]
/* main program */
_main:
 ldr r0, =PIOC_BASE  /* Enable LED */
 mov r1, #2
 str r1, [r0, #PIO_PER]	
 str r1, [r0, #PIO_OER]	
 
 ldr r0,=DBGU_BASE
 mov r1,#2048        /* No Parity */
 str r1,[r0,#DBGU_MR]
 mov r1,#26          /* 48MHz / 16 / 26 == 115384 */
 str r1,[r0,#DBGU_BRGR]
 mov r1,#0x50        /* TX enable && RX enable */
 str r1,[r0,#DBGU_CR]
 mov r1,#1           /* Enable RX ready interrupt */
 str r1,[r0,#DBGU_IER]
 
 ldr r3,=CHECK80
 ldr r4,=STR_PTR
 ldr r5,=STRING
 ldr r6,=STR_REP

zanka:
 ldr r0,[r3]
 cmp r0,#0
 beq zanka
 
 mov r0,r5
 bl REPLACE
 ldr r0,[r3]
 bl START_DMA
 mov r0,#0
 str r0,[r4]
 str r0,[r3]
 
 b zanka
RX_PSP:
 sub lr,lr,#4
 stmfd sp!,{r0-r2,lr}
 
 ldr r0,=DBGU_BASE   /* Received Char */
 ldr r0,[r0,#DBGU_RHR]
 
 bl PARITY                        

 ldr r2,=STR_PTR
 ldr r1,[r2],#4      /* Position in STRING */
 cmp r1,#81
 bhs end_psp
 cmp r0,#10          /* is character <Enter> key? (LF) */
 streqb r0,[r2,r1]
 addeq r1,r1,#1
 subeq r2,r2,#4
 streq r1,[r2,#-4]   /* Signal full array with CHECK80 != 0 */
 beq end_psp
 
 strb r0,[r2, r1]    /* Store character in correct position */
 add r1,r1,#1
  
 cmp r1,#80          /* is STRING full (length == 80) */
 moveq r0,#10        /* LF */
 streqb r0,[r2,r1]
 addeq r1,r1,#1
 str r1,[r2,#-4]!    /* Store new STR_PTR */
 streq r1,[r2,#-4]   /* Signal full array with CHECK80 != 0 */

end_psp:  
 ldr r1,=0xFFFFF130  /* End Interrupt */
 str r1,[r1]
 ldmfd sp!,{r0-r2,pc}^
REPLACE:
 stmfd sp!,{r0-r2,lr}
 ldr r1,=STR_REP

loop:  
 ldrb r2,[r0],#1
 cmp r2,#65
 blo endloop
 cmp r2,#90
 addls r2,r2,#32
 bls endloop
 cmp r2,#97
 blo endloop
 cmp r2,#122
 subls r2,r2,#32
endloop:
 strb r2,[r1],#1
 cmp r2,#10          /* Compare with LF instead of 0x0 */
 bne loop
 
 ldmfd sp!,{r0-r2,pc}
START_DMA:            /* gets length in r0 */
 stmfd sp!,{r1,r2,lr}
 ldr r1,=DBGU_BASE   /* DBGU_Status_Register */
l:ldr r2,[r1,#DBGU_SR]
 tst r2,#0x10
 beq l

 mov r2,#0x200       /* Disable DMA Transmition */
 str r2,[r1,#DBGU_PTCR]
 
 str r0,[r1,#DBGU_TCR]
 str r0,[r1,#DBGU_TNCR]
 
 ldr r2,=STR_REP
 add r2,r2,#0x200000
 str r2,[r1,#DBGU_TNPR]
 ldr r2,=STRING
 add r2,r2,#0x200000
 str r2,[r1,#DBGU_TPR]
 
 mov r2,#0x100       /* Enable DMA Transmition */
 str r2,[r1,#DBGU_PTCR]
  
 ldmfd sp!,{r1,r2,pc}
PARITY:
 stmfd sp!,{r1,r2,lr}
 mov r1,#0
 
 tst r0,#1
 eorne r1,r1,#1      /* XORED BITS 0 TO ...             */
 tst r0,#2
 eorne r1,r1,#1
 tst r0,#4
 eorne r1,r1,#1
 tst r0,#8
 eorne r1,r1,#1
 tst r0,#16          /*             . . .               */
 eorne r1,r1,#1
 tst r0,#32
 eorne r1,r1,#1
 tst r0,#64
 eorne r1,r1,#1
 tst r0,#128
 eorne r1,r1,#1      /* ... 7                           */
 eors r1,r1,#1       /* Final Negation */

 ldr r2,=PIOC_BASE
 mov r1,#2
  
 streq r1, [r2, #PIO_SODR]
 strne r1, [r2, #PIO_CODR]

 ldmfd sp!,{r1,r2,pc}
/* constants */
CHECK80: .word 0
STR_PTR: .word 0
STRING:  .space 82
STR_REP: .space 82 

Prirejeno na lepše.

Osebna orodja
Imenski prostori
Različice
Dejanja
navigacija
oglas
Tiskanje/izvoz
orodja