RACUNAR SA FIKSIRANIM PROGRAMOM (PRIMER):
=========================================

Verovali ili ne, znanje koje smo do sada stekli na ovom predmetu nam je
sasvim dovoljno da napravimo racunar!! Ako ne verujete, pogledajte primer
u nastavku. :)

Pretpostavimo da imamo jednostavan racunar koji se sastoji iz:

*) 16 8-bitnih registara R0-R15. Ovi registri su logicki povezani u jednu
   memoriju sa 4-bitnom adresom. 

*) 8-bitne ALU jedinice koja moze da izracunava sledece operacije:
   -) operacija 0000 [no_op1]: propusta prvi operand na izlaz, bez ikakve
      operacije (tzv. "no-operation")
   -) operacija 0001 [zero]: nula funkcija (daje nulu kao rezultat, bez
      obzira na ulaze)
   -) operacija 0010 [add]: sabiranje
   -) operacija 0011 [addc]: sabiranje sa prethodnim prenosom
   -) operacija 0100 [sub]: oduzimanje
   -) operacija 0101 [inc]: uvecanje za jedan
   -) operacija 0110 [dec]: umanjenje za jedan
   -) operacija 0111 [neg]: promena znaka (potpuni komplement)
   -) operacija 1000 [and]: bitovska konjunkcija
   -) operacija 1001 [or]: bitovska disjunkcija
   -) operacija 1010 [xor]: bitovska ekskluzivna disjunkcija
   -) operacija 1011 [not]: bitovska negacija
   -) operacija 1100 [shl]: pomeranje u levo
   -) operacija 1101 [shr]: logicko pomeranje u desno
   -) operacija 1110 [sar]: aritmeticko pomeranje u desno
   -) operacija 1111 [no_op2]: propusta drugi operand na izlaz, bez ikakve
      operacije
      
  ALU jedinica pri svakoj operaciji racuna i flegove O,S,Z,C na osnovu
  rezultata izvrsene operacije na sledeci nacin:
  
   -) C (carry): ovaj fleg se postavlja na 1 u sledecim slucajevima:
      -) pri sabiranju, sabiranju sa prethodnim prenosom, oduzimanju, uvecanju
      za jedan i umanjenju za jedan: ako je doslo do neoznacenog prekoracenja.
      -) pri pomeranju u levo ili desno, ako je vrednost poslednjeg istisnutog
      bita jednaka 1.
   -) Z (zero): ovaj fleg se postavlja na 1 akko je rezultat 0, pri svim
   operacijama.
   -) S (sign): ovaj fleg se postavlja na najvisi bit rezultata pri svim
      operacijama.
   -) O (overflow): ovaj fleg se postavlja na 1 u sledecim slucajevima:
      -) pri sabiranju, sabiranju sa prenosom, oduzimanju, uvecanju
      i umanjenju za jedan: ako je doslo do oznacenog prekoracenja
      -) pri pomeranju u levo: ako je doslo do promene znaka rezultata
      -) pri promeni znaka: ako se komplementira vrednost -128.

*) 8-bitne magistrale preko koje se prenose podaci. 

*) 8-bitnog registra P ciji je ulaz povezan na magistralu, a izlaz je
   povezan na drugi ulaz ALU jedinice i sluzi da se u njega privremeno
   smesti drugi operand pre operacije.  Prvi ulaz ALU jedinice je
   povezan direktno na magistralu.

*) 8-bitnog registra A koji prihvata i privremeno cuva rezultat
   operacije iz ALU jedinice. Njegov ulaz je povezan na izlaz
   ALU jedinice, a izlaz je povezan na magistralu.

   NAPOMENA: A i P registri su neophodni zato sto imamo samo jednu
   magistralu, pa ne mozemo istovremeno da dovedemo oba operanda na
   ALU jedinicu i da rezultat u istom koraku vratimo u odredisni
   registar.  Zato je neophodno jedan operand prvo sacuvati u registru
   P, a zatim drugi direktno dovesti na ulaz ALU jedinice. Slicno,
   rezultat izracunavanja se mora privremeno sacuvati u registru A, pa
   se u sledecem koraku prebaciti na odrediste. U realnim sistemima,
   procesori imaju vise internih magistrala preko kojih mogu operande
   i rezultat istovremeno prenositi, sto ubrzava rad racunara.

*) 4-bitnog registra PSW koji prihvata i cuva flegove koje ALU racuna.
   Njegov ulaz je povezan na psw izlaz ALU jedinice, a njegov izlaz
   se prosledjuje na ulaz kontrolne jedinice (vidi dole)

   NAPOMENA: Izracunati flegovi se koriste za grananja u programu, jer
   mozemo na osnovu rezultata prethodne operacije odluciti koji korak
   ce se sledeci izvrsiti. 

*) kontrolne jedinice (CU) koja upravlja svim ovim komponentama. Ona u
   svakom ciklusu casovnika generise KONTROLNE SIGNALE koji svim
   komponentama govore sta treba da rade u tom koraku. Kontrolni
   signali koje CU jedinica generise su:

   -) reg_adr: 4-bitni signal koji selektuje registar R0-R15 iz koga se vrsi
   citanje ili u koji se vrsi pisanje
   -) reg_in: signal koji zahteva od izabranog registra da prihvati i sacuva
   vrednost sa magistrale
   -) reg_out: signal koji zahteva od izabranog registra da svoju vrednost
   posalje na magistralu
   -) p_in: signal koji zahteva da P registar prihvati i sacuva vrednost
   sa magistrale
   -) alu_op: 4-bitni signal koji selektuje operaciju koju treba da izvrsi
   ALU jedinica
   -) psw_in: signal koji zahteva od PSW registra da sacuva izracunate flegove
   iz ALU jedinice
   -) a_in: signal koji zahteva od A registra da sacuva izracunatu vrednost
   iz ALU jedinice
   -) a_out: signal koji zahteva od A registra da svoju vrednost posalje na
   magistralu

Svi registri reaguju na uzlazni rub casovnika. Sa druge strane, stanje
kontrolne jedinice (i njen izlaz, tj. kontrolni signali) se menja na
silaznom rubu casovnika, kako bi kontrolna jedinica imala vremena da u
obzir uzme vrednosti flegova u PSW registru (koji se menjaju na
uzlaznoj ivici) pri racunanju novog stanja. 

Kontrolna jedinica je u sustini jedan konacni transduktor koji na
ulazu ima vrednost PSW registra (jer izvrsavanje algoritma zavisi od
toga da li vrednosti flegova nakon prethodne operacije zahtevaju
grananje ili ne) a na izlazu ima kontrolne signale. Stanja konacnog
transduktora odgovaraju pozicijama u algoritmu koji se izvrsava, tj.
govore nam dokle smo stigli u izvrsavanju algoritma.

Primetimo da sve gore opisane komponente vec znamo da napravimo
(registre, konacne transduktore, ALU jedinicu koja izvrsava navedene
operacije). Ovaj jednostavan racunar moze da izvrsava bilo koji
algoritam, pod uslovom da je za izvrsavanje tog algoritma dovoljno 16
8-bitnih registara [ovo nije sustinski problem, jer se kolicina
raspolozive memorije moze lako povecati]. 

AKCIJE koje ovakav racunar moze obavljati u svakom pojedinacnom
koraku (ciklusu casovnika) su:

-) Ri -> P : prebacivanje vrednosti iz Ri u P

-) Ri op P -> A,PSW: izracunavanje operacije (Ri op P) u ALU
   jedinici, gde je Ri podatak iz registra Ri koji se propusta kroz
   magistralu, i smestanje rezultata u A, a flegova u PSW

-) A -> Ri : prebacivanje vrednosti iz A u Ri, preko magistrale

-) A -> P: prebacivanje vrednosti iz A u P, preko magistrale

-) A op P -> A,PSW: izracunavanje operacije (A op P) u ALU jedinici
   i smestanje rezultata u A, a flegova u PSW. Vrednost registra
   A se propusta preko magistrale do prvog ulaza ALU jedinice.
   (primetimo da nije problem to sto se A koristi i kao operand i
   kao odrediste gde se cuva rezultat; u trenutku kada se rezultat
   sacuva u A, tj. prilikom uzlaznog ruba casovnika, vrednost na
   magistrali ce se promeniti, sto ce uticati na ulaz ALU jedinice,
   ali tada je vec kasno da eventualno promenjeni rezultata ALU
   jedinice ponovo bude sacuvan u A, jer je signal casovnika
   prosao). 


Dakle, svaki algoritam se mora predstaviti kao niz ovih elementarnih
koraka. Kako su ovi koraci znatno jednostavniji od tipicnih naredbi
koje se javljaju u visim programskim jezicima, navedimo nekoliko
primera kako se neke od tih naredbi mogu predstaviti elementarnim
koracima koje nas racunar moze da izvrsava:


*) Naredba dodele: Ri = Rj

   1) Rj no_op1 P -> A, PSW
   2) A -> Ri

Dakle, prvi korak je propustanje Rj kroz ALU jedinicu bez ikakve
operacije (no_op1, tj. "no-operation") i cuvanje u A registru.
Drugi korak je premestanje iz A u Ri registar.

*) Naredba: Ri = Rj + Rk

  1) Rk -> P
  2) Rj add P -> A, PSW
  3) A -> Ri

Dakle, najpre se drugi sabirak sacuva u P (tj. dovodi se na drugi
ulaz ALU jedinice koji je povezan na izlaz P registra). Zatim se
prvi sabirak preko magistrale dovodi na prvi ulaz ALU jedinice i
vrsi se operacija sabiranja, a rezultat se cuva u A. Zatim se
vrednost iz A prebaci u odredisni registar Ri.

*) Uporedjivanje Ri < Rj

  1) Rj -> P
  2) Ri sub P -> A, PSW

Dakle, uporedjivanje se svodi na oduzimanje. Pritom, sama razlika
sacuvana u A registru nas ne zanima, vec nas zanimaju flegovi u PSW
registru. U slucaju Ri < Rj (ako su neoznaceni brojevi u pitanju)
dovoljno je nakon izvrsene operacije pogledati vrednost C flega. Ako
je on 1, znaci da je Ri < Rj, pa je oduzimanje proizvelo prekoracenje.
U slucaju drugih relacija, gledaju se drugi flegovi (npr, za Ri == Rj
gledamo Z fleg, u slucaju Ri < Rj za oznacene brojeve gledamo S xor O
kombinaciju flegova, i sl.).

*) Naredba: Ri = -Rj

   1) Rj neg P -> A, PSW
   2) A -> Ri

Dakle, u prvom koraku racunamo operaciju promene znaka (primetimo da
se u ovoj operaciji vrednost registra P uopste ne koristi, jer se
menja znak prvom operandu ALU jedinice). Izracunata vrednost se
smesta u A. Nakon toga se vrednost iz A prebacuje u Ri. 


IMPLEMENTACIJA ALGORITAMA U GORE OPISANOM MODELU RACUNARA:
==========================================================

Implementacija algoritama se svodi na dizajn konacnog transduktora
kontrolne jedinice, a to je nesto sto smo vec naucili kako se radi.
Napomenimo da u ovom modelu racunara svaki algoritam podrazumeva
drugaciju kontrolnu jedinicu, tj. ako zelimo da nas racunar izvrsava
novi algoritam, moramo da dizajniramo novu kontrolnu jedinicu. Zbog
toga se ovakav racunar i zove RACUNAR SA FIKSIRANIM PROGRAMOM, jer
je program, tj. algoritam ugradjen u sam hardver racunara [prvi
elektronski racunari, poput ENIAC-a su funkcionisali na ovaj nacin].

Krenimo od jednog jednostavnog primera. Neka se u registrima R0 i R1
nalaze neoznaceni brojevi x i y.  Imlementirajmo sledeci algoritam:

if(R0 > R1)
{
  R2 = R1;
}
else
{
  R2 = R0;
}

Ovaj algoritam ce vrednost min(x,y) da upise u R2. Opisimo ovaj
algoritam na jeziku naseg racunara:

0) RO -> P  (1)
1) R1 sub P -> A, PSW  (2)
2) C == 1 ? R1 no_op1 P -> A, PSW (3) 
2) C != 1 ? R0 no_op1 P -> A, PSW (3)
3) A -> R2 (4)
4)  --     (4)


Notacija koju smo koristili je sledeca:

<tekuce_stanje>) <uslov> ? <akcija> (<novo_stanje>)

<tekuce_stanje> je stanje u kome se moze primeniti taj korak, dok
<uslov> predstavlja uslov pod kojim se taj korak moze izvrsiti.
<uslov> se izrazava nad flegovima koji se nalaze na ulazu kontrolne
jedinice (npr C == 1 znaci "ako je C fleg jednak 1"). <akcija>
predstavlja akciju koja se izvrsava u tom koraku (transfer, ALU
operacija), dok <novo_stanje> predstavlja stanje u koje idemo nakon
izvrsene akcije.  Ukoliko u tekucem stanju akcija koja ce se izvrsiti
ne zavisi od uslova, tada navodimo samo akciju i novo stanje, tj. imamo
pojednostavljeni oblik:

<tekuce_stanje>) <akcija> (<novo_stanje>)

Iz ove notacije se direktno moze odrediti konacni transduktor kontrolne
jedinice. Naime, za svako stanje imamo (u zavisnosti od ulaza) akciju
koju treba izvrsiti (tj. izlaz u vidu kontrolnih signala) i novo stanje
u koje se prelazi. 

Evo tablica ekscitacije za gore opisani algoritam:


S2 S1 S0 | C  |  Sn2 Sn1 Sn0 |  Reg_3 Reg_2 Reg_1 Reg_0 Reg_in Reg_out P_in Psw_in A_in A_out Alu_3 Alu_2 Alu_1 Alu_0 |  J2 K2 J1 K1 J0 K0  
 0  0  0 | 0  |   0   0   1  |   0     0      0     0     0       1     1     0     0     0    0      0    0     0    |   0  -  0  -  1  - 
 0  0  0 | 1  |   0   0   1  |   0     0      0     0     0       1     1     0     0     0    0      0    0     0    |   0  -  0  -  1  -
 0  0  1 | 0  |   0   1   0  |   0     0      0     1     0       1     0     1     1     0    0      1    0     0    |   0  -  1  -  -  1
 0  0  1 | 1  |   0   1   0  |   0     0      0     1     0       1     0     1     1     0    0      1    0     0    |   0  -  1  -  -  1
 0  1  0 | 0  |   0   1   1  |   0     0      0     0     0       1     0     1     1     0    0      0    0     0    |   0  -  -  0  1  -
 0  1  0 | 1  |   0   1   1  |   0     0      0     1     0       1     0     1     1     0    0      0    0     0    |   0  -  -  0  1  -
 0  1  1 | 0  |   1   0   0  |   0     0      1     0     1       0     0     0     0     1    0      0    0     0    |   1  -  -  1  -  1
 0  1  1 | 1  |   1   0   0  |   0     0      1     0     1       0     0     0     0     1    0      0    0     0    |   1  -  -  1  -  1
 1  0  0 | 0  |   1   0   0  |   0     0      0     0     0       0     0     0     0     0    0      0    0     0    |   -  0  0  -  0  -
 1  0  0 | 1  |   1   0   0  |   0     0      0     0     0       0     0     0     0     0    0      0    0     0    |   -  0  0  -  0  -
 1  0  1 | 0  |   -   -   -  |   -     -      -     -     -       -     -     -     -     -    -      -    -     -    |   -  -  -  -  -  -
 1  0  1 | 1  |   -   -   -  |   -     -      -     -     -       -     -     -     -     -    -      -    -     -    |   -  -  -  -  -  -
 1  1  0 | 0  |   -   -   -  |   -     -      -     -     -       -     -     -     -     -    -      -    -     -    |   -  -  -  -  -  -
 1  1  0 | 1  |   -   -   -  |   -     -      -     -     -       -     -     -     -     -    -      -    -     -    |   -  -  -  -  -  -
 1  1  1 | 0  |   -   -   -  |   -     -      -     -     -       -     -     -     -     -    -      -    -     -    |   -  -  -  -  -  -
 1  1  1 | 1  |   -   -   -  |   -     -      -     -     -       -     -     -     -     -    -      -    -     -    |   -  -  -  -  -  -


U ovoj tablici S2 S1 S0 su bitovi stanja S (imamo ukupno 5 stanja, pa
nam je potrebno 3 bita). C nam je ulaz konacnog transduktora (to je C
fleg, ostali flegovi u ovom algoritmu nemaju uticaja na izvrsenje, pa
ih ne uzimamo u obzir). Sn2 Sn1 Sn0 je novo stanje u koje prelazimo.
Reg_3 do Reg_0 su bitovi Reg_adr kontrolnog signala (tj. odabira
registra koji zelimo da koristimo u tom koraku). Alu_3 do Alu_0 su
bitovi Alu_op kontrolnog signala (tj. koju operaciju zelimo da ALU
izvrsi u tom koraku). Ostali signali su jednobitni. Na osnovu ove
tablice racunamo vrednosti J2,K2,J1,K1,J0,K0, kao i svih kontrolnih
signala (u funkciji od S2, S1, S0, i C). Nakon minimizacije ovih
funkcija kreiramo odgovarajuce sekvencijalno kolo na uobicajen
nacin. 

Minimizacija funkcija:

J2:

    S2' S2' S2 S2
S0' 0   0   -  -  C'
S0' 0   0   -  -  C
S0  0   1   -  -  C
S0  0   1   -  -  C'
    S1' S1  S1 S1'

J2 = S0 S1

K2:

    S2' S2' S2 S2
S0' -   -   -  0  C'
S0' -   -   -  0  C
S0  -   -   -  -  C
S0  -   -   -  -  C'
    S1' S1  S1 S1'


K2 = 0

J1:

    S2' S2' S2 S2
S0' 0   -   -  0  C'
S0' 0   -   -  0  C
S0  1   -   -  -  C
S0  1   -   -  -  C'
    S1' S1  S1 S1'

J1 = S0

K1:

    S2' S2' S2 S2
S0' -   0   -  -  C'
S0' -   0   -  -  C
S0  -   1   -  -  C
S0  -   1   -  -  C'
    S1' S1  S1 S1'

K1 = S0


J0:

    S2' S2' S2 S2
S0' 1   1   -  0  C'
S0' 1   1   -  0  C
S0  -   -   -  -  C
S0  -   -   -  -  C'
    S1' S1  S1 S1'

J0 = S2'

K0:

    S2' S2' S2 S2
S0' -   -   -  -  C'
S0' -   -   -  -  C
S0  1   1   -  -  C
S0  1   1   -  -  C'
    S1' S1  S1 S1'


K0 = 1


Reg3 = 0
Reg2 = 0

Reg1:

    S2' S2' S2 S2
S0' 0   0   -  0  C'
S0' 0   0   -  0  C
S0  0   1   -  -  C
S0  0   1   -  -  C'
    S1' S1  S1 S1'

Reg1 = S0 S1

Reg0:

    S2' S2' S2 S2
S0' 0   0   -  0  C'
S0' 0   1   -  0  C
S0  1   0   -  -  C
S0  1   0   -  -  C'
    S1' S1  S1 S1'


Reg0 = S0 S1' + S0' S1 C

Reg_in = Reg1 = S0 S1

Reg_out:

    S2' S2' S2 S2
S0' 1   1   -  0  C'
S0' 1   1   -  0  C
S0  1   0   -  -  C
S0  1   0   -  -  C'
    S1' S1  S1 S1'

Reg_out = S1' S2' + S0' S2'

P_in:

    S2' S2' S2 S2
S0' 1   0   -  0  C'
S0' 1   0   -  0  C
S0  0   0   -  -  C
S0  0   0   -  -  C'
    S1' S1  S1 S1'


P_in = S0' S1' S2'


Psw_in

    S2' S2' S2 S2
S0' 0   1   -  0  C'
S0' 0   1   -  0  C
S0  1   0   -  -  C
S0  1   0   -  -  C'
    S1' S1  S1 S1'

Psw_in = S0 S1' + S0' S1

A_in = Psw_in

A_out =  Reg_in = S0 S1

Alu_3 = Alu_1 = Alu_0 = 0


Alu_2:


    S2' S2' S2 S2
S0' 0   0   -  0  C'
S0' 0   0   -  0  C
S0  1   0   -  -  C
S0  1   0   -  -  C'
    S1' S1  S1 S1'

Alu_2 = S0 S1'



Osnovni problem kod ovakvog dizajna racunara je slozenost postupka.
Naime, u slucaju iole slozenijeg algoritma imacemo veliki broj koraka
algoritma, pa samim tim i veliki broj stanja automata, sto ce tablice
ekscitacije uciniti veoma velikim, a proces minimizacije funkcija
isuvise komplikovanim. Naravno, ovo stoji ako radimo "rucno", na
papiru. U praksi, ako koristimo neki od gotovih alata u ovom postupku
(sto je gotovo uvek slucaj), tada postupak postaje veoma jednostavan,
jer se od dizajnera kontrolne jedinice samo ocekuje da opise dijagram
prelazaka iz stanja u stanje (sto se svodi na opis automata u nekom
simbolickom obliku, poput naseg opisa gore).

[za gornji primer pogledati odgovarajuci logisim model u prilogu].

Evo jednog malo slozenijeg primera algoritma (u pitanju je varijanta
Euklidovog algoritma za racunanje R0 = NZD(R0,R1)):

// C-oliki opis algoritma
while(R0 != R1)
{
 if(R0 > R1)
  R0 = R0 - R1;
 else
  R1 = R1 - R0;
}
// Rezultat ostaje u R0

Ovom algoritmu odgovara sledeci niz koraka u nasem modelu racunara:

0) RO -> P  (1)
1) R1 sub P -> A, PSW  (2)
2) Z == 1 ? -- (5)
2) Z == 0 ? -- (3)
3) C == 0 ? A -> R1 (0)
3) C == 1 ? A neg P -> A, PSW (4)
4) A -> R0 (0)
5) -- (5)

Za vezbu probajte sami da dizajnirate odgovarajuci konacni
transduktor. [napominjem da ce biti nesto teze nego u prethodnom
primeru, jer ovde imamo dodatno Z fleg koji uzimamo u obzir, pa ce sve
funkcije koje se minimizuju biti funkcije od 5 argumenata (S2, S1, S0,
C i Z), sto otezava primenu Karnoovih mapa za minimizaciju]
