111111111 111111111 1111111 11111111 111111 1111111 Tietokoneen mysteeri sekventiaalilogiikka Petteri Kaski Tietotekniikan laitos Aalto-yliopisto CS-A112 Ohjelmointi 2 1. maaliskuuta 217 111111111 11111111 11111111 11111111 11111111 111111111 111111111 111111111 111111111 111111 11111111
Tietokoneen mysteeri (4 kierrosta) 2. Bitit ja data binäärilukujärjestelmä, bittien käsittely Scalalla 3. Kombinaatiologiikka 4. Sekventiaalilogiikka 5. Ohjelmoitava kone logiikkaporteista rakennettuja piirejä Scala-simuloituna kello ja takaisinkytkentä Scala-simulaatioon, prosessorin laskentapolku konekieliohjelmoimme 5574-porttista Scalalla rak. & simuloitua armlet -prosessoria
3. Sekventiaalilogiikka
Millä periaatteilla tietokone toimii? Mitä on laskenta? Miten rakennetaan ohjelmoitava kone?
Kierroksen 3 jälkeen osaamme rakentaa (Scalalla) koneita, jotka käsittelevät bittejä
Kombinaatiologiikan työkalusto? NOT EI 1 (johtoa) AND JA (syöteelementtejä) OR TAI (logiikkaportteja)
Mutta onko kombinaatiologiikka riittävän väkevä työkalusto rakentamaan ohjelmoitava kone?
Kombinaatiologiikalla voidaan rakentaa konfiguroitavia piirejä Osa syötteistä ohjaa ( konfiguroi ) mitä piiri laskee ulostuloihin
Ohjelmoitavuus tuntuu silti voimakkaammalle ominaisuudelle kuin konfiguroitavuus Jokin keskeinen periaate puuttuu?
Pohjalta pohdiskellen Mikä olisi mahdollisimman yksinkertainen kone, jota emme osaa rakentaa kombinaatiologiikalla?
Kone, 1 joka kasvattaa laskuria yhdellä 1 aina kun painamme 1 1 nappia?
Yhdellä kasvattaja kombinaatiologiikalla +1 [demo] import minilog._ // NOTE UPGRADE TO minilog! def buildhalfadder(ai: Gate, c: Gate) = (ai && c, (!ai && c) (ai &&!c)) def buildincrementer(aa: Bus) = { var c = aa.host.true // initial carry is true val r = new Array[Gate](aa.length) for(i <- until aa.length) { val (c_out,s) = buildhalfadder(aa(i), c) r(i) = s c = c_out } new Bus(r) } val n = 4 val c = new Circuit() // a host object for our gates (new in minilog) val ins = c.inputs(n) // have the host create a new bus of n input elements val outs = buildincrementer(ins) // build an incrementer
Kone, joka kasvattaa 1 laskuria yhdellä aina kun 1 painamme nappia? 1 1 Missä se nappi on? (ja millä periaatteella nappi toteutetaan?)
???? 1 +1 1???? 1 1 Takaisinkytkentä ulostuloista sisääntuloihin aina kun nappia painetaan
system starts at time t = t = +1 the incrementer adds one to its inputs to obtain the output???? 1 +1 clock triggers and feedbacks occur???? 1 t = 1 +1 the incrementer adds one to its inputs to obtain the output 1 1 clock triggers and feedbacks occur Kellopulssin ( napin ) liipaisemat kiinteät takaisinkytkennät t = 2 +1 1 1 the incrementer adds one to its inputs to obtain the output clock triggers and feedbacks occur mahdollistavat saman kombinaatiopiirin käytön aina uudestaan ja uudestaan......
system starts at time t = t = +1 the incrementer adds one to its inputs to obtain the output???? 1 +1 clock triggers and feedbacks occur???? 1 t = 1 +1 the incrementer adds one to its inputs to obtain the output 1 1 clock triggers and feedbacks occur Aika t =, 1, 2,... mitataan kellopulssien lukumääränä piirin t = 2 +1 the incrementer adds one to its inputs to obtain the output käynnistämisestä 1 1 clock triggers and feedbacks occur Piiri käynnistettäessä siis t =...
Sekventiaalilogiikan työkalusto NOT EI? (johtoa) 1 AND JA OR TAI (kelloliipaistuja (logiikkaportteja) (syöteelementtejä) takaisinkytkentöjä)
Onko meillä nyt ohjelmoitava kone?
Kyllä (vähän on vielä rakentamista, mutta koneen periaatteet on nyt esitelty sekventiaalilogiikka riittää)
Kierros 4: Sekventiaalilogiikka Kello ja takaisinkytkentä Scala-simuloituna (minilog -pakkaus ja Trigger-työkalu) Sekventiaalipiirit ja niiden suunnittelu Prosessorin laskentapolku ( data path ) muistilla Laskentakäskyt (5. kierros: Ohjelmoitava prosessoriarkkitehtuuri & konekieliohjelmointi)
minilog-pakkaus ja Trigger-työkalu
Kombinaatiopiirejä rakennetaan lähes kuten tinylog -pakkauksellakin: import minilog._ // NOTE UPGRADE TO minilog! def buildhalfadder(ai: Gate, c: Gate) = (ai && c, (!ai && c) (ai &&!c)) def buildincrementer(aa: Bus) = { var c = aa.host.true // initial carry is true val r = new Array[Gate](aa.length) for(i <- until aa.length) { val (c_out,s) = buildhalfadder(aa(i), c) r(i) = s c = c_out } new Bus(r) } val n = 4 val c = new Circuit() // a host object for our gates (new in minilog) val ins = c.inputs(n) // have the host create a new bus of n input elements val outs = buildincrementer(ins) // build an incrementer
Takaisinkytkentöjen rakentaminen Scalalla import minilog._ // NOTE UPGRADE TO minilog! val n = 4 val c = new Circuit() // a host object for our gates (new in minilog) val ins = c.inputs(n) // have the host create a new bus of n input elements val outs = buildincrementer(ins) // build an incrementer ins.buildfeedback(outs) // feed the outputs back to the inputs (new in minilog) buildfeedback-metodi rakentaa syöte-elementtiin (tai syöte-elementtiväylään) takaisinkytkennä(n/t) metodin argumenttina annetusta portista (väylästä) Kellon liipaisu Scalalla c.clock() // trigger the clock in circuit c
minilog-pakkauksesta ja sen suunnittelusta lisää lukemistossa (*)
Trigger-työkalu [demo] nappi import minilog._ // NOTE UPGRADE TO minilog! def buildhalfadder(ai: Gate, c: Gate) = (ai && c, (!ai && c) (ai &&!c)) def buildincrementer(aa: Bus) = { var c = aa.host.true val r = new Array[Gate](aa.length) for(i <- until aa.length) { val (c_out,s) = buildhalfadder(aa(i), c) r(i) = s c = c_out } new Bus(r) } val n = 4 val c = new Circuit() // a host object for our gates (new in minilog) val ins = c.inputs(n) // have the host create a new bus of n input elements val outs = buildincrementer(ins) // build an incrementer ins.buildfeedback(outs) val t = new Trigger(c) t.watch("ins", ins.reverse) t.watch("outs", outs.reverse) t.go() // trigger requires a host object // we can watch gates or buses in the host object //... reversion shows least signif. bit on the right // opens up the graphical interface
Tavoite: Prosessorin laskentapolku ja laskentakäskykanta
Pohjalta ponnistaen myös prosessorisuunnitteluun Summankerryttäjä ( summa-akkumulaattori )
user in???????? Adder????
Summankerryttäjä [demo] import minilog._ // NOTE UPGRADE TO minilog! def buildadder(aa: Bus, bb: Bus) = { new Bus( ((aa zip bb).scanleft((aa.host.false, aa.host.false))) { case ((s,c),(a,b)) => (a+b+c,(a && b) (a && c) (b && c)) }.drop(1).map(_._1)) } val n = 8 val c = new Circuit() val accum_in = c.inputs(n) val user_in = c.inputs(n) val accum_out = buildadder(accum_in, user_in) accum_in.buildfeedback(accum_out) val t = new Trigger(c) t.watch("accum_in", accum_in.reverse) t.watch("user_in", user_in.reverse) t.watch("accum_out", accum_out.reverse) t.go()
Akkumulaattori toimii kuten piiriin rakennettu muuttuja (jonka arvo muuttuu kellon käydessä)
Prosessoriarkkitehtuurissa tällaisia muuttujia kutsutaan rekistereiksi armlet-arkkitehtuurissamme on kahdeksan 16-bittistä rekisteriä: $, $1, $2, $3, $4, $5, $6 ja $7
Aritmetiikka-logiikkayksikkö (ALU) Prosessorin osa, joka varsinaisesti laskee
armlet ALU $ $1 $2 $3 $4 $5 $6 $7 operation Arithmetic logic unit L A B $ $1 $2 $3 $4 $5 $6 $7
add $4, $, $3 $ $1 $2 $3 $4 $5 $6 $7 + "add" 1 11 $ $1 $2 $3 $4 $5 $6 $7
Tuetut laskuoperaatiot ( laskentakäskyt ) nop # no operation mov $L, $A # $L = $A (copy the value of $A to $L) and $L, $A, $B # $L = bitwise AND of $A and $B ior $L, $A, $B # $L = bitwise (inclusive) OR of $A and $B eor $L, $A, $B # $L = bitwise exclusive-or of $A and $B not $L, $A # $L = bitwise NOT of $A add $L, $A, $B # $L = $A + $B sub $L, $A, $B # $L = $A - $B neg $L, $A # $L = -$A lsl $L, $A, $B # $L = $A shifted to the left by $B bits lsr $L, $A, $B # $L = $A shifted to the right by $B bits asr $L, $A, $B # $L = $A (arithmetically) shifted to the right by $B bits operaatio mitä operaatio tekee rekistereille $L, $A, $B
Vakio-operandit (ei-rekisterioperandit) $ $1 $2 $3 $4 $5 $6 $7 immed_in Arithmetic logic unit operation L A B $ $1 $2 $3 $4 $5 $6 $7
Vakio-operandit (ei-rekisterioperandit) mov $L, I add $L, $A, I sub $L, $A, I and $L, $A, I ior $L, $A, I eor $L, $A, I lsl $L, $A, I lsr $L, $A, I asr $L, $A, I # $L = I (copy the immediate data I to $L) # $L = $A + I # $L = $A - I # $L = bitwise AND of $A and I # $L = bitwise (inclusive) OR of $A and I # $L = bitwise exclusive OR of $A and I # $L = $A shifted to the left by I bits # $L = $A shifted to the right by I bits # $L = $A (arithmetically) shifted to the right by I bits operaatio mitä operaatio tekee rekistereille $L, $A ja vakiolle I
ALU Trigger-työkalulla [demo] import armlet._ new ALUTrigger()
Laskentapolku ( data path )
Laskentapolun osat lcu_e C $ $1 $2 $3 $4 $5 $6 $7 read_in Load completion unit immed_in Arithmetic logic unit operation L A B mem_read_e mem_write_e mem_addr mem_data Memory interface unit loa_e sto_e L A lcu_e C $ $1 $2 $3 $4 $5 $6 $7
Muistirajapintayksikkö $ $1 $2 $3 $4 $5 $6 $7 mem_read_e mem_write_e mem_addr mem_data Memory interface unit loa_e sto_e L A lcu_e C $ $1 $2 $3 $4 $5 $6 $7 loa $L, $A # $L = [contents of memory word at address $A] sto $L, $A # [contents of memory word at address $L] = $A operaatio mitä operaatio tekee rekistereille $L, $A ja muistille
Muisti (prosessorin ulkopuolella) mem_read_e mem_write_e read_out Memory mem_addr mem_data (muistiyksikön rakentaminen harjoituksissa)
Laskentapolun osat lcu_e C $ $1 $2 $3 $4 $5 $6 $7 read_in Load completion unit immed_in Arithmetic logic unit operation L A B mem_read_e mem_write_e mem_addr mem_data Memory interface unit loa_e sto_e L A lcu_e C $ $1 $2 $3 $4 $5 $6 $7
Entäpä laskentapolun konfigurointi? Käpistelemällä?
armlet-laskentapolun haluttu toiminta määrätään käskyllä ( instruction ), joka on 16-bittinen sana (Eräät armlet-käskyt koostuvat kahdesta 16-bittisestä sanasta, varsinaisesta käskystä ja tätä seuraavasta vakiosta)
Käskykanta (laskentapolkua ohjaavat käskyt) nop # no operation mov $L, $A # $L = $A (copy the value of $A to $L) and $L, $A, $B # $L = bitwise AND of $A and $B ior $L, $A, $B # $L = bitwise (inclusive) OR of $A and $B eor $L, $A, $B # $L = bitwise exclusive-or of $A and $B not $L, $A # $L = bitwise NOT of $A add $L, $A, $B # $L = $A + $B sub $L, $A, $B # $L = $A - $B neg $L, $A # $L = -$A lsl $L, $A, $B # $L = $A shifted to the left by $B bits lsr $L, $A, $B # $L = $A shifted to the right by $B bits asr $L, $A, $B # $L = $A (arithmetically) shifted to the right by $B bits mov $L, I add $L, $A, I sub $L, $A, I and $L, $A, I ior $L, $A, I eor $L, $A, I lsl $L, $A, I lsr $L, $A, I asr $L, $A, I # $L = I (copy the immediate data I to $L) # $L = $A + I # $L = $A - I # $L = bitwise AND of $A and I # $L = bitwise (inclusive) OR of $A and I # $L = bitwise exclusive OR of $A and I # $L = $A shifted to the left by I bits # $L = $A shifted to the right by I bits # $L = $A (arithmetically) shifted to the right by I bits loa $L, $A # $L = [contents of memory word at address $A] sto $L, $A # [contents of memory word at address $L] = $A
Käskyjen binääriesitys (**) sub $2, $, $1 11111 ior $7, $1, 12345 1111111 111111
Käskynpurkuyksikkö lcu_e C $ $1 $2 $3 $4 $5 $6 $7 read_in Load completion unit instr_in mem_read_e mem_write_e mem_addr Arithmetic logic unit Memory interface unit Instruction decoder unit immed_in mem_data lcu_e C $ $1 $2 $3 $4 $5 $6 $7
Laskentapolku Trigger-työkalulla [demo] import armlet._ new DataPathTrigger()
Mikroarkkitehtuuri ja käskykanta
Caveat armlet sisältää vain kaikkein keskeisimmät arkkitehtuuriperiaatteet erityisesti von Neumann rekisterikonearkkitehtuuri Varsinaiset nykyaikaiset prosessoriarkkitehtuurit ovat huomattavasti edistyneempiä kuin armlet-arkkitehtuuri Sivuutettu mm.: Fysikaalinen toteutus, välimuistit (caching), rinnakkaisuus (superscalar, multicore,...), vaiheistus (pipelining), virtualisointi (esim. virtuaalimuisti), laitteistorajapinnat, keskeytykset, moniajo,...
Harjoituksissa Koneenrakennusta Portti- ja väylätason piirisuunnittelua, sekventiaalilogiikalla Tietokoneen toimintaperiaatteita rakennamme oman pienen muistiyksikön sekventiaalilogiikalla kertolaskupiirin vaiheistaminen ( pipelining ), jotta piiristä saadaan matalampi ja siten nopeampi (haastetehtävä)
Tehtävät oscillator jaksollinen sekventiaalipiiri siirtorekisterillä LFSR lineaarinen takaisinkytkentä-siirtorekisteri memory yhden sanan ja monen sanan muistiyksiköt seqmul sekventiaalinen kertolaskupiiri pipelining (haastetehtävä) logaritmisesti vaiheistettu lineaarisen (tai logaritmisen!) syvyyden kertolaskuyksikkö
Seuraava luento (ma 6.3. klo 1 12) poikkeuksellisesti salissa TU2, TUAS-talo, Maarintie 8