Sistemski softver/Projekat
Projekat na predmetu Sistemski softver je obavezan i sastoji se od 3 programa koji čine skup alata za razvoj softvera na apstraktnom računarskom sistemu. Ovaj vodič teži da bude nezavisan od postavke, koja se neznatno menja iz godine u godinu.
Podela po celinama
Zbog svog velikog obima, preporučuje se detaljna razrada zahteva na lako razumljive celine i korake. Preporučuje se sledeći redosled zadataka:
- Tabelarno predstavljanje mašinskih instrukcija i adresiranja u sklopu simboličkog mašinskog jezika asemblera i samog mašinskog koda. Pre nego što se krene sa implementacijom leksera i parsera neophodno je detaljno pregledati tražene zahteve u jeziku.
- Izrada modela simboličkog mašinskog jezika u softveru. Ovde se može primeniti objektno orijentisani pristup modelovanju, ili strukturni pristup nalik izlaznom formatu.
- Razvoj leksera i parsera koristeći generatore flex i bison ili pisanjem svog leksera i parsera.
- Izrada modela izlaznih podataka asemblera. Ovo uključuje sekcije, relokacije, simbole i sve što nije bilo pokriveno modelovanjem jezika.
- Implementacija samog asembliranja. Prolazi se kroz izlaz parsera i popunjava izlazni model.
- Opciono tekstualno/grafičko predstavljanje izlaznih podataka nalik readelf i objdump olakšava debagovanje.
- Testiranje asemblera.
- Modelovanje i implementacija izlaznog binarnog formata asemblera
- Model ulaznih podataka linkera. Mogu se koristiti i strukture iz asemblera, ali nije preporučljivo jer su neophodni podaci za rad linkera i asemblera znatno različiti - sve postojeće enkapsulacije i interfejsi verovatno nisu dovoljno univerzalni ili su ograničavajući.
- Implementacija linkera
- Implementacija ispisa radne memorije u tekstualni fajl, kao i ispisa u prethodno osmišljeni objektni format, za šta kod ne bi trebalo da se znatno razlikuje.
- Testiranje linkera.
- Modelovanje memorije u emulatoru. Učitavanje memorije iz fajla.
- Modelovanje procesora, registara, obrade prekida.
- Implementacija emuliranja instrukcija. Sa naglaskom na pažljivo pisanje koda i razumevanje postavke.
- Implementacija periferije terminal. Postavka preporučuje termios biblioteku.
- Implementacija periferije tajmer.
- Testiranje emulatora.
Ne treba zaboraviti pisanje make skripte za pravljenje projekta pri samom početku izrade, zato što se znatno ubrzava vreme prevođenja. Prezentacija koja objašnjava kako koristiti GNU make se nalazi u odeljku Vežbe 2.
Subjektivno gledano, delovi projekta koji najviše oduzimaju vremena su: leksička analiza (vreme učenja alata ili pisanje svojih), format izlaznog fajla (neophodno je naći balans između lakog generisanja i lakog čitanja) i testiranje emulatora (male greške u ponašanju instrukcija).
Asembler
Tabelarno predstavljanje mašinskih instrukcija i adresiranja
Postavka projekta sadrži mnogo informacija koje nisu naročito kvalitetno organizovane i predstavljene. Tabelarna reorganizacija projekta pomaže pri izradi i zato se preporučuje. Dat je primer za projekat iz 2022. godine. Primetiti da je u ovoj postavci podatak u instrukciji big endian, a podatak u memoriji little endian. Podebljana slova označavaju polja koja se zamenjuju pri generisanju mašinskog koda. Značenja su: D - odredišni registar S - izvorni registar.
Instrukcija | Dužina u bajtovima | InstrDescr | RegsDescr | AddrMode | DataHigh | DataLow |
---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | 4 | ||
HALT | 1 | 00 | ||||
IRET | 1 | 20 | ||||
RET | 1 | 40 | ||||
INT | 2 | 10 | DF | |||
PUSH | 3 | B0 | 6S | 12 | ||
POP | 3 | A0 | D6 | 42 | ||
NOT | 2 | 80 | D0 | |||
XCHG | 2 | 60 | DS | |||
ADD | 2 | 70 | DS | |||
SUB | 2 | 71 | DS | |||
MUL | 2 | 72 | DS | |||
DIV | 2 | 73 | DS | |||
CMP | 2 | 74 | DS | |||
AND | 2 | 81 | DS | |||
OR | 2 | 82 | DS | |||
XOR | 2 | 83 | DS | |||
TEST | 2 | 84 | DS | |||
SHL | 2 | 90 | DS | |||
SHR | 2 | 91 | DS | |||
CALL | 3/5 | 30 | FS | Adresiranje za skok | ||
JMP | 3/5 | 50 | FS | Adresiranje za skok | ||
JEQ | 3/5 | 51 | FS | Adresiranje za skok | ||
JNE | 3/5 | 52 | FS | Adresiranje za skok | ||
JGT | 3/5 | 53 | FS | Adresiranje za skok | ||
LDR | 3/5 | A0 | DS | Adresiranje za podatke | ||
STR | 3/5 | B0 | DS | Adresiranje za podatke |
U tabelama adresiranja, polja su: L - deo literala S - deo vrednosti simbola, D - odredišni registar, R - izvorni registar.
Notacija | Adresiranje | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
<literal> | Neposredno | F0 | 00 | LL | LL |
<symbol> | Neposredno | F0 | 00 | SS | SS |
%<symbol> | PC relativno | F7 | 05 | SS | SS |
*<literal> | Mem. direktno | F0 | 04 | LL | LL |
*<symbol> | Mem. direktno | F0 | 04 | SS | SS |
*<reg> | Reg. direktno | FR | 01 | ||
*[<reg>] | Reg. indirektno | FR | 02 | ||
*[<reg>+<lit>] | Reg. ind. sa pomerajem | FR | 03 | LL | LL |
*[<reg>+<sym>] | Reg. ind. sa pomerajem | FR | 03 | SS | SS |
Notacija | Adresiranje | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
$<literal> | Neposredno | D0 | 00 | LL | LL |
$<symbol> | Neposredno | D0 | 00 | SS | SS |
%<symbol> | PC relativno | D7 | 03 | SS | SS |
<literal> | Mem. direktno | D0 | 04 | LL | LL |
<symbol> | Mem. direktno | D0 | 04 | SS | SS |
<reg> | Reg. direktno | DR | 01 | ||
[<reg>] | Reg. indirektno | DR | 02 | ||
[<reg>+<lit>] | Reg. ind. sa pomerajem | DR | 03 | LL | LL |
[<reg>+<sym>] | Reg. ind. sa pomerajem | DR | 03 | SS | SS |
Ovakve tabele odlično predstavljaju šta je dati izlaz u mašinskom kodu za dati ulaz u jeziku. Preporuka je koristiti ih pri modeliranju ulaznih podataka i leksičke analize.
Modelovanje jezika
Preporuka je upoznati se sa alatima flex i bison pre pisanja bilo kog koda i daljeg čitanja vodiča. Korisno je naći tutorijal:
- Tutorijal sa aquamentus.com
- Tutorijal sa udel.edu
- flex & bison, John Levine je opširna knjiga o ovim alatima
Primena ovih alata za asembler nije trivijalna, i bolje je izdvojiti vreme na pisanju prostijih primera pre početka pisanja asemblera, npr. učitavanje memorije iz hex izlaza linkera u emulator.
Parser uklapa ulazni tekst u prethodno napisana pravila (više o tome na prevodiocima). Pravila izgledaju slično sintaksnim notacijama kao na P1. Pravila se uklapaju od manjih do većih. Kako se ulaz uklopi u pravilo, izvrši se određena radnja. Radnja parsera u našem slučaju je konstrukcija struktura/objekata koje predstavljaju delove jezika, i eventualno spajanje tih jezičkih elemenata u listu kroz koju prolazi sam asembler. Na slici desno je dat primer modela.
Parser popunjava listu elemenata jezika (namerno se ne zovu linije jer je moguće imati više njih u jednoj liniji). Iz elemenata se izvode direktive i instrukcije. Svaka specijalizacija direktive sadrži neki njoj bitan podatak (naziv simbola, literali, izrazi i slično) koji će parser proslediti iz leksema (jezičkih jedinica, npr. literal, identifikator) pri konstrukciji. Slično važi i za instrukcije, gde su namerno odvojena adresiranja kao objekti koje parser kreira pre uklapanja u samu instrukciju, zato što parser uklapa adresiranja pre nego što uklopi instrukciju sa adresiranjem. Kasnije, pri nastanku (uklapanju) instrukcije, ona postaje vlasnik objekta adresiranja. Asembler će, pomoću ovakvog modela, u svojim prolazima (ili prolazu) imati dostupne sve detalje iz ulaznog fajla. Korisno je pri konstrukciji pamtiti i broj linije na kom se element nalazi, radi lepšeg izveštavanja grešaka.