Search
První část - Význam a použití základních instrukcí
Bližší popis instrukcí:
Druhá část - Seznámení se s vývojovým a simulačním prostředím (programy MipsIt a Mips) a simulace vykonávání jednoduchého programu
Pro psaní vlastního programu v asembleru a následné generování výstupního souboru pro simulátor Mips lze použít oblíbený textový editor (například Geany) a nástroj make.
Make je nástroj pro automatickou kompilaci zdrojových kódů, potřebná konfigurace je uložena v souboru Makefile.
Makefile šablona:
ARCH=mips-elf CC=$(ARCH)-gcc AS=$(ARCH)-as LD=$(ARCH)-ld OBJCOPY=$(ARCH)-objcopy CFLAGS += -ggdb -O1 AFLAGS += -ggdb LDFLAGS += -ggdb LDFLAGS += -nostdlib -nodefaultlibs -nostartfiles LDFLAGS += -Wl,-Ttext,0x80020000 all:default .PHONY:clean %.srec:% $(OBJCOPY) -O srec $< $@ %.out:% $(OBJCOPY) -O ecoff-bigmips $< $@ %.o:%.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -c $< -o $@ %.s:%.c $(CC) $(CFLAGS) $(CPPFLAGS) -S $< -o $@ %.o:%.c $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ # default output default:change_me.srec # executable file:object file.o change_me:change_me.o $(CC) $(LDFLAGS) $^ -o $@ # all generated that would be cleaned clean: rm -f change_me change_me.o change_me.out change_me.srec
Zdrojový kód napsaný v asembleru se dle konvence ukládá do souboru s koncovkou .S, pro vlastní program lze použít následující šablonu:
#define t0 $8 #define t1 $9 #define t2 $10 #define s0 $16 #define s1 $17 #define s2 $18 .globl start .set noat .ent start start: // Zde je místo pro Váš vlastní kód... nop .end start
Pro ukázku si můžete zkusit napstat krátký program, který sečte dvě čísla uložená v registrech s0 a s1, a výsledek uloží do registru s2.
addi s0, $0, 0x15 addi s1, $0, 0x45 add s2, s0, s1
Kompilace probíhá příkazem make (příkaz make je nutné zadávat v adresáři, ve kterém je upravený Makefile a zdrojový kód programu). Make vygeneruje několik souborů, z nichž pro import do simulačního prostředí Mips použijeme ten s koncovkou .srec.
Tento program budeme používat pro psaní vlastního programu v asembleru a následné generování výstupního souboru pro simulátor Mips, MipsPipeS a MipsPipeXL (dnes budeme používat jenom simulátor Mips).
Letní semestr 2018: V nabídce
Applications -> Development vybereme MipsIt
Applications -> Development vybereme MipsIt-MIPS
—–
Letní semestr 2017:
/opt/wine/bin/wine /opt/mipsit/bin/MipsIt.exe
/opt/wine/bin/wine /opt/mipsit/bin/Mips.exe
V prostředí učebny KNE:328 (letní semestr 2016): Na instalaci Ubuntu APO se prostředí a ikonky na desktopu nastaví příkazem
mipsit-setup
V případě, že již je prostředí nastavené, tak lze provést jeho kompletní reset. POZOR příkaz způsobí smazání veškerých dat ve složce ~/.wine. To zahrnuje i veškeré projekty v prostředí MipsIT, pokud jsou ukládané do standardní/nezměněné složky
mipsit-setup force
Úvodní obrazovka po spuštění programu:
Postupujeme v těchto krocích: File → New → karta Project, kde vybereme Assembler, vyplníme jméno vytvářeného projektu a zvolíme umístění Dále pak: File → New → karta File, kde vybereme Assembler, vyplníme jméno souboru a zkontrolujeme zda máme zaškrtnuto “Add to project”
Do nově otevřeného okna (s příponou *.s) pak píšeme vlastní program: K tomuto účelu můžeme využít připravenou šablonu:
Projekt přeložíme výběrem v menu: Build → Build xx, kde xx je jméno Vašeho projektu. Alternativou je klávesa F7. Vygenerují se tři soubory s příponou *.o, *.out a *.sreg umístěné v podadresáři Objects aktuálního pracovního adresáře projektu. Při správném postupu by měla být obrazovka programu (výpis v okně “Output”) nasledující:
Důležitá poznámka: Nikde v cestě nesmí být mezera. Pokud nefunguje překlad projektu je zapotřebí zkontrolovat cestu k projektu (a/nebo také: File → Options → karta Directories, a zde cesty pro: Executable files, Include files a Library files.
Tento program budeme používat pro simulaci vykonávání napsaného programu - sledování (krokování) vykonávání programu a ověření jeho funkčnosti.
Soubor vygenerovaný programem MipsIt (s příponou *.srec nebo *.out) načteme cez: File → Open. Dále pak zobrazíme pracovní registry procesoru (View → Register) a paměť programu (View → Memory).
Po vykonání výše uvedeného postupu a odkrokování programu (Cpu → Step nebo klikáním na ikonu ) dostaneme:
Upozornění: Před opakovaným načtením souboru *.out nebo *.sreg je zapotřebí nejdřív zresetovat procesor: Cpu → Reset. Po každém zresetováni procesoru je zapotřebí soubor *.out nebo *.sreg načíst znovu. Okno pro vykreslování paměti (to žluté) má problémy s překreslováním - pokud se obsah paměti modifikuje instrukcemi sw nemusí být zápis vidět. Postačí jej na chvíli překrýt jiným oknem.
Pokud je již některý ze simulátorů Mips.exe, MipsPipeS.exe nebo MipsPipeXL.exe spuštěný, lze kód do simulátoru načíst z prostředí MipsIT.exe aktivací položky
Build -> Upload -> To Simulator (F5)
Volba zároveň provede inicializaci CPU do počátečního stavu.
Třetí část cvičení
V praktických aplikacích se častokrát setkáváme s použitím mediánového filtru. Ten nám pomáhá odstranit ze signálu (nebo obrazu) zcela zjevné výkmity (nebo poškozené pixely). Narozdíl od průměrovacího filtru, který spočítá aritmetický průměr nejakého okolí a stávající hodnotu signálu nahradí vypočteným průměrem, mediánový filtr ji nahradí prostřední hodnotou (mediánem) tohoto okolí. Pro realizaci mediánového filtru je potřebné nejdříve seřadit všechny hodnoty a pak z nich vybrat onu prostřední. Klíčovou roli zde sehrává řazení. Mějme následující problém. V datové paměti nech je uloženo N celých čísel (1 < N < 21) počínaje od nějaké adresy (například 0x00), přičemž jedno číslo v paměti zabírá velikost jednoho slova. Našim úkolem je uvedená čísla vzestupně seřadit. Nejsnažší způsob jak tento problém řešit je použít bublinkové řazení. Princip tohoto algoritmu spočívá v tom, že se postupně a opakovaně prochází seřazované pole, přičemž se porovnávají každé dva sousedící prvky, a pokud nejsou ve správném pořadí, prohodí se. Hodnotu N si zvolte sami.
int pole[5]={5,3,4,1,2}; int main() { int N = 5,i,j,tmp; for(i=0; i<N; i++) for(j=0; j<N-1-i; j++) if(pole[j+1]<pole[j]) { tmp = pole[j+1]; pole[j+1] = pole[j]; pole[j] = tmp; } return 0; }
Přepište výše uvedený program z jazyka C do asembleru. Vykonávání programu oveřte v simulátoru Mips. Tento program budete potřebovat na příštím cvičení - to co nestihnete na cvičeních bude nutno dodělat doma..
Můžete využít předpripravenou šablonu k tomuto úkolu:
#define t0 $8 #define t1 $9 #define t2 $10 #define t3 $11 #define t4 $12 #define s0 $16 #define s1 $17 #define s2 $18 #define s3 $19 .globl pole .data .align 2 pole: .word 5,3,4,1,2 .text .globl start .ent start start: // Zde muzete psat Vas program nop .end start
if (i ==j) f = g + h; f = f – i;
// s0=f, s1=g, s2=h, s3=i, s4=j bne s3, s4, L1 // Pokud i!=j, skoč na L1 add s0, s1, s2 // if blok: f=g+h L1: sub s0, s0, s3 // f = f-i
if (i ==j) f = g + h; else f = f – i;
// s0=f, s1=g, s2=h, s3=i, s4=j bne s3, s4, else // Když i!=j, skoč na else add s0, s1, s2 // if blok: f=g+h j L2 // přeskoč blok else else: sub s0, s0, s3 // blok else: f = f-i L2:
int pow = 1; int x = 0; while(pow != 128) { pow = pow*2; x = x + 1; }
// s0=pow, s1=x addi s0, $0, 1 // pow = 1 addi s1, $0, 0 // x = 0 addi t0, $0, 128 // t0 = 128 pro porovnávání while: beq s0, t0, done // Když pow==128, ukončení cyklu while sll s0, s0, 1 // pow = pow*2 addi s1, s1, 1 // x = x+1 j while done:
int sum = 0; for(int i=0; i!=10; i++) { sum = sum + i; }
//Ekvivalentní k následujícímu cyklu while: int sum = 0; int i = 0; while(i!=10){ sum = sum + i; i++; }
// Jenom pro účely ukázky... int a, *pa=0x80020040; int b, *pb=0x80020044; int c, *pc=0x00001234; a = *pa; b = *pb; c = *pc;
// s0=pa (bazova adresa), s1=a, s2=b, s3=c lui s0, 0x8002 // pa = 0x80020000; lw s1, 0x40(s0) // a = *pa; lw s2, 0x44(s0) // b = *pb; addi s0, $0, 0x1234 // pc = 0x00001234; lw s3, 0x0(s0) // c = *pc;
int pole[4] = { 7, 2, 3, 5 }; int main() { int i,tmp; for(i=0; i<4; i++) { tmp = pole[i]; tmp += 1; pole[i] = tmp; } return 0; }
#define s0 $16 #define s1 $17 #define s2 $18 #define s3 $19 .globl pole // nazev "pole" bude globalni (viditelny ze vsech souboru projektu) .data // direktiva oznacujici zacatek datove casti .align 2 // zarovnani dat po slovech (4 Bytech) pole: // pojmenovani mista v pameti .word 7, 2, 3, 5 // inicializace pole... .text // zacatek textove casti / programu .globl start .ent start start: la s0, pole // ulozeni adresy pocatku pole do registru s0 (pseudoinstrukce) addi s1, $0, 0 // inicializacni prikaz cyklu for: i=0, kde i=s1 addi s2, $0, 4 // nastaveni horni meze cyklu for: beq s1, s2, done // kdyz s1==s2 ukonceni cyklu skokem na navesti done lw s3, 0x0(s0) // nacteni polozky pole do registru s3 addi s3, s3, 0x1 // inkrementace registru s3 sw s3, 0x0(s0) // prepsani (ulozeni) hodnoty registru s3 do pole addi s0, s0, 0x4 // posun na dasli polozku pole addi s1, s1, 0x1 // inkrementace pocitadla poctu pruchodu cyklem (i++) j for // nepodmineny skok na navesti for done: nop .end start
gcc -E assembler.S -o predzpracovany-pro-mips.s