- Felpörög az asztali CPU-piac a következő pár hónapban
- Hősködik és száguldozik az új Arc meghajtó
- A Panasonic is nyit a TiVo okostévé rendszer irányába?
- Rengeteg csatlakozó van a HP legfrissebb, irodai célú monitorgóliátján
- Computex 2024: teljesen integrált hibrid hűtéssel közeleg az MSI új csúcs-VGA-ja
- AMD K6-III, és minden ami RETRO - Oldschool tuning
- Nvidia GPU-k jövője - amit tudni vélünk
- Mikrokontrollerek Arduino környezetben (programozás, építés, tippek)
- Milyen processzort vegyek?
- AMD GPU-k jövője - amit tudni vélünk
- Házi barkács, gányolás, tákolás, megdöbbentő gépek!
- ASUS ROG PG32UCDM: OLED csúcsmonitor tesztje
- Autóhifi
- Dell notebook topic
- A Panasonic is nyit a TiVo okostévé rendszer irányába?
Hirdetés
-
5G-vel és hőkamerával strapálja magát az Ulefone
ma A ThermoVue rendszere mellett az éjjellátó képességek is megvannak.
-
Retro Kocka Kuckó 2024
lo Megint eltelt egy esztendő, ezért mögyünk retrokockulni Vásárhelyre! Gyere velünk gyereknapon!
-
Mozgásban a Conscript
gp A túlélőhorror PC-re és konzolokra érkezik, a steames demó jövő hónap elején lesz kipróbálható.
Aktív témák
-
t3m1nat0r
csendes tag
Sokak szerint a processzorok működésének megértéséhez magas mérnöki előtanulmányok szükségesek.
Hogy ez mekkora tévedés, az itt ki fog hamarosan derülni.. -
t3m1nat0r
csendes tag
Talán érdemes lenne egy egyszerű processzorral kezdeni. Legyen ez a 6502, ami a commodore 64-est is vezérelte, na meg a terminátort.
"In the science fiction movie The Terminator (1984), starring Arnold Schwarzenegger, the audience at one point is treated to a view through the T-800 Model-101 robot character's eye/camera display with some 6502 assembly/machine code program fragments scrolling down the screen. "
http://en.wikipedia.org/wiki/MOS_Technology_6502
http://www.llx.com/~nparker/a2/opcodes.html
http://www.llx.com/~nparker/a2/opcodes.html
Ha az ember megnézi ennek a processzornak az utasítás készletét, akkor első pillanatban megrémül, hogy milyen sok van ezekből. Ha kicsit átnézzük ezeket, akkor kiderül, hogy a legtöbb utasítás ugyan annak az alaputasításnak a módosulatai.http://www.obelisk.demon.co.uk/6502/instructions.html
Igy már 11 csopotra lehet bontani ezeket. Egy kezdőnek még mindig ijesztő lehet, de tovább lehet egyszerűsíteni a képet.
Az első csoport valamilyen adatot visz egyik "hely"-ről a másikra. A hely fogalmát itt még majd definiálni kell. Itt ez a fogalom nem utcákat vagy bármi más megszokott dolgot jelent.
Ezek:
Load/Store Operations
Register Transfers
Stack Operationstöltés/tárolás
register tartalom áthelyezése
verem operációkA második csoport "biteken" "bitekkel" végez műveletet. A bitek fogalmát is definiálni kell majd.
Logical
Arithmetic
Increments & Decrements
Shifts
Status Flag Changeslokigai bit műveletek
aritmetikai műveletek
regiszter érték nővelés, csökkentés 1-el
eltolások és forgatások
státusz beállitásokA harmadik csopot a program elagazasait kezeli, irányítja. Ezek valójában az első csoporthoz tartoznak, mert az a fő feladatuk, hogy az ugrasi cimet a Program Counter-be helyezik.
http://www.obelisk.demon.co.uk/6502/registers.html
Jumps & Calls
Branches
System FunctionsUgrások és szubrutin hívások
elágazások
rendszer funkciók -
ABnormal
őstag
jó ezekről olvasni,1993-ban írtam ilyen nyelven az utolsó programomat
-
t3m1nat0r
csendes tag
Definiálni kellene, hogy mit jelent a hely és bit fogalma a gépben.
Ehhez tudni kell, hogy hogyan tárolja az információt a gép.Ez a memória feladata.
http://en.kioskea.net/contents/pc/ram.php3
A megadott linken rácsban elhelyezett kondenzátorokat lehet látni.
Itt egy 6x6-os rács van a képen. Ez egy 6 byte-os memóriának felel, ahol egy byte-ból most csak 6 bit látszik.Egy byte valójában 8 bites, vagyis 8 kondenzátornak felel meg.A c64-ben 65536x8 ilyen kondenzátor van. A c64 memóriája 64 kbyte. Ennek a fogalomnak fizikailag ez a kondenzátor tömb felel meg.
Ilyen egyszerű a kezdet, és később sem lesz sokkal bonyolultabb.A fizikai megvalósítástól függően nem kizárólag kondenzátor tárolhat egy bitet. Lehet tranzisztorokkal visszacsatolást létrehozni, amik szintén képesek egy bit tárolására.
http://class.ee.iastate.edu/cpre305/labs/lab07.html
A programozás szempontjából a különböző fizikai megoldások nem lényegesek. Annyi azért még leírok, hogy a műveleteket nem követlenül a memóriában végzi a processzor, hanem beolvassa a memória tartalmát egy regiszterbe. Ezek a regiszterek gyors működésű tranzisztorokból állnak legtöbbször. A modern processzorok már nem is egyből a regiszterekbe olvasnak, hanem elöszőr közbeiktatott több lépcsős gyorsító memóriákba. De nem célom a modern cpu-k leírása.
Minden byte-ot /8 kondenzátort/ a memóriába egy címvezetékkel lehet elérni. Ez lehet a vízszintes vonal. Ez a c64-nél 65536 vezzetéket jelent. Ezt binárisan kódolva 16 biten lehet ábrázolni. 2 a 16.-on az pont ennyi. Ezt a 16 bites számot nevezzük címnek. Ez az adott 8 bites kondenzátor tömb memória címe.
Ahhoz, hogy fizikailag ez működjön, át kell alakítani ezt a 16 bitet 65536 bitté, hiszen a memóriát ennyi vezetéken lehet elérni. Ez a memória címző egység dolga, amivel szintén nem kell programozás szinten nekünk foglalkozni.
A memória fele haladó 16 bites vezetékköteg a címbusz, a kondenzátoroktól visszajövő az adatbusz.Innentől ismert, hogy mi az a bit, hogy lesz belőle byte, továbbá mit jelent ennek a helye és címe.
-
t3m1nat0r
csendes tag
Nem kerülhetem el azt, hogy a számábrázolásokról írjak. Ezek nélkül nem lesz tiszta, miért fér el 16 biten a 65536-1 decimális szám.
A kettes számrenszer igazából egy választott ábrázolás a gépekben, hiszen bármilyen szimbólumrendszert hozzá lehetne rendelni egy adott byte-hoz, ami 8 kondenzátor értéke.
De a kettes számrendszer felel meg a legjobban a célnak. Miért?
Mert a kondenzátor vagy fel van töltve, vagy nem. A kettes számrendszerben pedig egy számot 0 és 1 számokkal írunk le, ami egyértelműen megfeleltethető a kondenzátor állapotainak.Tizes számrendszerben, mint köztudott, 10 számjeggyel /szimbólummal/ írható le bármilyen szám. Elszámolunk 9-ig, utánnak "túlcsordulás" keletkezik. Ezt egy újabb helyiértékkel jelöljük, majd folytatjuk a számolást megint 0-tól 9-ig.
A kettes számrendszerben annyi a változás, hogy mindig 0-tól 1-ig számolunk, majd "túlcsordulás" jön. Az első bináris szám, ahol ez megtörténik a bináris 10,ami a decimális 2-es. Ugye 0, 1, 10/túlcsordulás/, ami decimálisan 0,1,2.Lehet ez már óvodás szintnek tűnik, de nem mérnököknek írok, hanem azoknak, akiknek halvány elképzelésük sincs, mi megy végbe egy ilyen gépben.
Egy egyszerű számológéppel meg lehet nézni, hogy az 10000000000000000 bináris szám, az 65536. Azért írtan hogy -1, mert ez már 17 számjegyű. 16 bittel tehát a legmagasabb címezhető memória a bináris 1111111111111111, azaz a 65535.
Ezt a sok egyest nagyon kényelmetlen kezelni, könnyű eggyel kevesebbet vagy többet írni belőle. Hamar meg is unták a programozók, és bevezettek egy egyszerűbb ábrázolási módot. Ami elsőre talán bonyolultabb.
Ez a hexadecimális, tizenhatos számrendszerbeli ábrázolás.
Mivel nincs a 10 11 12 13 14 15 számjegyekre külön jel, így használni őket pedig veszélyes lenne, mert nem lenne egyértelmű a leírás, ezért ezeket betűkkel helyettesítették. Ezek lettek az A,B,C,D,E,F betűk.
Tehát úgy számolunk 16-os számokkal, hogy 1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11,12,13,14,15,16,17,18,19,1A,1B,.....Két hexadecimális számmal leírható egy byte. Nem csoda, hiszen egy fél byte 4 bit. 2 a 4.-en pedig 16. Egyszerű.
-
t3m1nat0r
csendes tag
Most kezd érdekes lenni a probléma.
Az már sejthető, hogy a programkód és az adatok a memóriában vannak.De mit jelent az, hogy fut a program?
Ehhez először is a regisztereket kell megismerni.Program Counter
Stack Pointer
Accumulator
Index Register X
Index Register Y
Processor StatusAz elsőnél már meg is állhatunk. Ez az a 16 bites címregiszter, ami arra a memória byte-ra mutat, ami éppen "végrehajtódik".
Ez annyit jelent, hogy a processzor kiküldi a memória fele ezt a címet /rákapcsolja a regisztert a címbuszra/ , az pedig beállítja az adatvezetékeket az adott című memória byte kondenzátorainak megfelelő értékre.
Ezeket a folyamatokat időziteni kell, mivel az elektronok nem végtelen sebességgel haladnak.A behozott byte lesz az utasítás. Ez az adott processzortól függően megmondja, hogy mi lesz a következő lépés.
Lehet, hogy az utasítás utáni byte-ot be kell hozni, és hozzáadni az akkuhoz /Accumulator/, vagy az utasítás után egy cím található, ahova el kell ugrani.
Ha elvégezte a műveletet, akkor a Program Counter értékét növeli automatikusan a processzor, és elhozza a következő byte-ot, a következő utasítást.Már fut is a program.
Látszik, hogy igazából a memóriában bármilyen byte-kombináció lehet. Akár képi információ vagy valamilyen szöveg. A gépet ezt nem érdekli, neki az a feladata, hogy ezt utasítások sorozataként értelmezze, mivel a Program Counter értékét valaki erre a memória területre állította.
Ha a program eltéved /hibás, vagy a memória sérül, stb/ akkor "megfagy" a program, vagy jön a "kékhalál".
A commodore egyszerűen csak újraindult. Nem bonyolította túl a témát.Mostmár az is érthető, hogy hogyan ágazik el egy program.
A Program Counter értékét néhány utasítás képes módosítani. Ezek a Jumps & Calls és a Branches utasítások.
A jump és a "jump to a subrutine2 mindig elugranak, míg a Branches tipusúk csak akkor, ha a megadott feltétel teljesül. A szubrutin hívás még annyiban különleges, hogy a veremben eltárolja a visszatérési értéket, amit majd a "return from subrutine" újra elő fog venni. A magasabb szintű nyelvek ezt használják a procedurák és függvényhívásokhoz. Nem pont ezt, csak ha c64-en fug a progi.Eddig igazából semmi más nem törént, csak byte-ok mozogtak a memóriából a processzor valamelyik regiszterébe. Ez a lényege a gép működésének. Magasabb szinten a memória nem címekkel érhető el, hanem változók neveivel. De ezek mindig ilyen memória-címeket rejtenek.
-
t3m1nat0r
csendes tag
A maradék regiszterek
Stack Pointer
Accumulator
Index Register X
Index Register Y
Processor StatusA Stack Pointer-ről már volt szó a szubrutin hívásnál. Ez egy ideiglenes tárolásra kijelölt memória területre
mutat. Ide lehet olyan adatokat "lenyomni", amiket csak kevés ideig kell megőrízni.
A magasszintű nyelvek lokális változói is ide kerülnek.
Ehhez tartoznak a POP és PUSH műveletek, amikke a veremre rakhatunk adatot, vagy leszedhetjük onnan.PHA Push accumulator on stack
PHP Push processor status on stack
PLA Pull accumulator from stack N,Z
PLP Pull processor status from stackAz Accumulator az a regiszter, ahol műveleteket végez a processzor az adatokon. A modernebb cpu-kon már több ilyen funkciójú regiszter is található, és így jobban optimalizálható a kód, kevesebbszer kell a memóriához fordulnia.
Az index regiszterek a címzést segítik.A Processor Status vagy flag register bitjei különböző állapotait mutatják a processzornak. Ezeket bitműveleteket lehet végezni, és a Branches utasításokhoz is ezek adják meg a feltételeket. Ezek általában valamilyen művelet elvégzése után állnak be az adott állapotba. Mondjuk a "CMP Compare accumulator", ami összehasonlít két számot kivonás segítségével, két egyenlő értéket hasonlított össze. Ez a "Zero Flag" bitet fogja beállítani, ami majd a következő "BEQ Branch if zero flag set" vagy "BNE Branch if zero flag clear" utasítást fogja vezérelni.
-
t3m1nat0r
csendes tag
A logikai és az aritmetikai műveletek az Accumulator értékét manipulálják.
Itt még nem volt szorzás és osztás, bizony meg kellett írni azt is. Mennyivel egyszerűbb, és unalmasabb a mai processzorok programozása.A logikai műveletek bitekre vonatkoznak. Egyszerűen leírva annyi a feladatuk, hogy biteket állítsanak 1-re vagy 0-ra. Ez nem ugy oldották meg, hogy mindig megadom a módosítani kívánt bit azonosító-számát, hanem maszkokkal lehet a biteket manipulálni. Ha 1-esre akarom az akku 7.bitjét állítani, akkor az "ORA Logical Inclusive OR" utasításnak egy 0x80 hexadecimális paramétert adok. A 8 az binárisan 1000 a 0 az 0000, tehát a 7.bit egyes lesz, a többi marad a régi állapotában. A ugyanezt az "EOR Exclusive OR"-al végzem el, akkor a 7. bit az ellentétes állapotába áll be.
Igazából nincs szándékomban leírni az összes utasítás működését, csak a gép alapvető funkcióinak a bemutatása volt a célom.Mint kiderült, nem kell mérnöki végzettség ahhoz, hogy az ember megértse a processzor működésének alapjait.
Ahogy a programozásához sem diploma kell, hanem gép, idő és kódtáblázat.Persze aki úgy képzeli, hogy a próbálkozás egyenlő azzal, hogy összevissza nyomkodja a gombokat, az feleslegesen végzett el annyi egyetemet.
-
t3m1nat0r
csendes tag
Miért beszélek én 7. bitről, mikor az a 8.?
Nem elírás, hanem ez egy megszokott számozási módszer a számítástechnikában. Akik programoznak, azok ismerik, hogy az első tömb elem mindig a [0]. Ennek praktikus oka van, a tömbnek van egy báziscíme, amihez hozzáadódik az index.
A bitek ugyan így 0-tól kezdődnek.
-
t3m1nat0r
csendes tag
Az elején a bitekkel végzett műveletekhez soroltam az aritmetikai műveleteket. Ez nem a szokásos besorolás, de igaz.
A regiszterekbe és a memóriában mindig bitek vannak.Az hogy mi most egy decimális számként gondolunk rá, vagy egy pixel szinértékeként, már csak értelmezésbeli külömbség. Attól ott még egy kondenzátor tömb van fizikailag, ami biteket tárol.
Szín úgy lesz ebből a bitcsoportból, hogy áthelyezzük a videómemóriába. Ebből egy dekódoló áramkör olyan jelet fog előállítani , ami a monitoron szines pixelként fog megjelenni.
Ha ezt a bitcsopotot a hangkártyára küldöm, akkor hang lesz belőle. Ha ráállítom az utasításszámláló regisztert, akkor programkód.Egy memóriaterület azért fog lebegőpontos számot jelképezni, mert olyan műveleteket végzek el rajta, amelyek ezt lebegőpontos számként kezelik.
-
t3m1nat0r
csendes tag
Ahhoz, hogy fizikailag ez működjön, át kell alakítani ezt a 16 bitet 65536 bitté, hiszen a memóriát ennyi vezetéken lehet elérni.
Igazából ennek elég egyszerű a megoldása. A bináris fákhoz hasonlóan felosztható a memória is. A legfelső bit ha 0, akkor a baloldali memória aktív, ha 1 akkor a jobb. A következő bit ezt a két részt osztja további darabokra.
-
sonar
addikt
Nem rossz, de szerintem egy logout blogban nagyon olvasottsága lenne
A tudást mástól kapjuk, a siker a mi tehetségünk - Remember: Your life – Your choices!
-
ABnormal
őstag
nincs kedved egy pár példaprogrammal szemléletesebbé tenni az utasításokat? nem kell bonyolult,csak néhány alap...
LDA #$FF
STA $1000ilyesmikre gondoltam...
-
t3rm1nat0r
csendes tag
Na , visszatértem
Mielőtt az asm-ről beszélnék, előbb a hardvert kellene megismerni közelebbről.
Szó volt a Program Counter-ről, ami egy számláló, ahogy a neve is mutatja.
Ezek egy olyan elemekből állnak, amik visszacsatolással megjegyzik az állapotukat.
Ezeknek ismét több megoldásuk lehetséges, a vezérlésük történhet élvezérléssel, lehet rajtuk reset bemenet.De az átláthatóság miatt vegyük a legegyszerűbb megoldást:
http://webpages.charter.net/dawill/tmoranwms/Circuits_2008/Type_D_Flip-Flop.gifEz két visszacsatolt részből áll, a master és a slave flip-flop-ból. Ezek lehetnek nand vagy nor kapukból felépítve, ismét csak részletkérdés. A fontos, az a visszacsatolt hurok, ez a két csatolt kapunál mindig ellentétes állapotú.
A két flip-flop ellentétes jelre áll be. Ez a CLK bemenet, ami vezérli a számlálót. A slave rész ezt invertálva kapja.Ez még igazából nem jó számláláshoz, ahhoz össze kell kötni a D bemenetet az egyik Q kimenettel. Ekkor mindig ellentétes állapotába áll be a bit.
Ha több ilyen bitet összerakok, és a CLK bemenetre az előző Q kimenetét kötöm, akkor meg is kaptam a számlálót.Hogy ne csak a levegőbe beszéljek, ezt működés közben is be fogom mutatni.
[ Szerkesztve ]
-
t3rm1nat0r
csendes tag
A továbbiakban ahhoz hogy valamiféle értelmes szimulációt lehessen bemutatni, tudni kellene, hogy épül fel egy nand kapu.
Ehhez a cmos megoldást választottam. De itt is sok más fizikai kivitelezés létezik.
http://en.wikipedia.org/wiki/FileMOS_NAND.svg
http://en.wikipedia.org/wiki/CMOSEz egy kevert megoldás, n és p tipusú tranzisztorokból áll. Mindig csak az egyik tipus aktív, amiatt áram csak nagyon rövid ideig folyik. Ezeket használják a kis fogyasztású eszközökben.
Ha A vagy B bemenetet Vss-re kapcsolom /-/, akkor az Out Vdd szintre /+/ áll be, mert valamelyik felső tranzisztor lesz aktív.
A minkét bemenet Vdd-t kap, akkor a két alsó tranzisztor Vss-re kapcsolja a kimenetet. /out/
Ennek van egy igazság táblája
A B out
+ + -
- + +
+ - +
- - +Ez megfelel a nand állapotainak, ha + az az 1, és a - a 0 állapot,
Ezeket az igazságtáblákat nem kell bemagolni. Néhány egyszerű szabályra épül az egész.Az AND csak akkor ad igaz /1/ kimenetet, ha mindkét bemenet igaz. Ez az első eset.
A B out
11 1
01 0
10 0
00 0Az OR csak akkor ad 0-át, ha mindkét bemenet 0. Ha VAGY az egyik VAGY a másik 1, akkor a kimenet is 1.
A B out
11 1
01 1
10 1
00 0A XOR csak akkor lesz 1, ha ellentétes a két bemenet állapota.
A B out
11 0
01 1
10 1
00 0Az N betű a NAND-nál annyit jelent, hogy invertálni kell a kapott értéket.
Ez az 1-est 0-ára változtatja, és fordítva.A NAND kapuk használatának mint látszik, ismét praktikus oka van, ez az egyik legegyszerűbben megvalósítható logikai kapu.
AND kaput úgy kapunk, hogy egy invertert kapcsolunk utánna. Ha nem akarunk túl optimalizált áramkört, akkor kiindulhatunk a tervezésnél tisztán NAND vagy NOR kaputömbből.
Ekkor az invertert úgy kapom, hogy az egy NAND kapu egyik bemenetét felhúzom.
Ezt a módszert fogom alkalmazni. -
t3rm1nat0r
csendes tag
válasz t3rm1nat0r #18 üzenetére
A linkbe került egy smile-vezérlő karakter, de jó a link.
-
t3rm1nat0r
csendes tag
A logikai műveleteknél ezeket az alaputasításokat már említettem. Ott azt mondtam, hogy maszkokkal lehet a biteket manipulálni. Ez annyit jelent, hogy egy 8 bites regiszterhez 8 bitet adunk meg, amiken egyenként végrehajtódik az, amit az imént leírtam.
Esszerint 8 darab A és B bemeneti érték van. A bitek bármilyen állapotban lehetnek.
/terhesek azért nem xD /10101100 A
11001101 B
10001100 out = A AND B10101100 A
11001101 B
11101101 out A OR B10101100 A
11001101 B
01100001 out A XOR B /vagy EOR/Igy látszik a logikája a műveleteknek, ha decimálisan vagy hexában írom fel, akkor már csak gyakorlott szem érti, mi miért történik.
0xac A
0xcd B
0x8c out = A AND BVannak még a forgatások és léptetések. Itt csak annyi történik, hogy jobbra vagy balra eltolódik bitenként a regiszter
10101100 A
01011000 out ROTATE LEFT /a rövidítés processzor függő/10101100 A
01010110 out RIGHT
11010110 out RIGHT a legfelső bit ismétlődik. Mivel INT tipusnál az tárolja az előjelet, ezért így a szám negatív marad.Az A értéke decimálisan 172, jobbra forgatás után 86. Ez a fele, a forgatást osztás helyett lehet használni, ha 2 hatványával osztunk.
Régebbi hardveres megoldásoknál ezért találkozunk lépten nyomon olyan számokkal, hogy 2 4 8 16 32 64 128 256 512 1024 ... mert ez az osztást /és ha balra forgatok, akkor szorzást/ sokkal egyszerűbben valósítható meg hardverileg, és még gyorsabb is a működése, mint majd kiderül.Be fogok mutatni egy teljes összeadó arámkört működés közben, ahol látszani fog, miért eszik olyan sok időt egy hagyományos processzor, és miért számol például egy geforce sokkal gyorsabban.
[ Szerkesztve ]
-
t3rm1nat0r
csendes tag
Mivel egy c program lesz ami majd emulálja a hardver működését, ezért kicsit a programozás rejtelmeiben is elmerülök. Ezért került ide ez a topik.
Ha megnézzük, hogy egy D flip-flop mennyi kapuból áll, és egy kapu mennyi tranzisztorból, elsőre elég elrettentőnek látszik a feladat.
Itt jön a képbe a programozás igazi lényege. Mert nem az a lényeg, hogy az összes c nyelvjárás szintaktikai külömbségeit fejből fujja az ember. Azt egy ovodás is kiguglizza.A feladat felbontása kisebb részfeladatokra. Ez az, amit /még/ nem tudnak a gépek.
Mivel a c nyelv egy logikai kapu működését egyszerűen utánnozza, ezért ez lesz az alapszint. Erre épül fel majd minden. Mivel látványos programot akarok, ezért a tranzisztorok állapotát is meg lehet majd jeleníteni a kapu állapotának ismeretében.
Igazából egy processzort nem kapuszinten terveznek, hanem nagyobb egységekből rakják össze. Ez programozásnál is egy bevált módszer. Ha már tesztelt, és biztosan jól működő részegységekből építkezünk, akkor az új rendszer gyorsabban áll össze, és kisebb a hibalehetőség.A nemrég belinkelt Dflipflop-nak ennyi a kódja.Ez egyszerűen megmonja, hogy egy sorXsor-os NAND tömbben melyik kapu melyik két másikhoz kapcsolódjon.
void define_dflip(int t,int l1)
{
int tr[]={
t+0, t+1, t+2, t+3, t+4,
t+sor+0, t+sor+1, t+sor+2, t+sor+3, t+sor+4,0};//5-9define_links(tr[0],link_5V,l1,0); //inverter
define_links(tr[5],link_5V,tr[4],1);define_links(tr[1],l1,tr[5],0); define_links(tr[2],tr[7],tr[1],1);
define_links(tr[6],l1,tr[4],1); define_links(tr[7],tr[2],tr[6],0);define_links(tr[3],tr[0],tr[2],1); define_links(tr[4],tr[9],tr[3],0);
define_links(tr[8],tr[0],tr[7],1); define_links(tr[9],tr[4],tr[8],1);
}Innentől egy 8 bites számlálónak már csak ennyi a kódja.Ez megadja, hogy két soronként legyen lefele egy-egy Dflipflop, és mindig az előző kimenetére csatlakozzon.
//counter
int counter_bazis=2,counter_out_offset=4;
int tr=counter_bazis;
define_dflip(tr,0); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;Definiálni kellene a define_links() függvényt. Mondjuk legyen ilyen.
void define_links(int t,int l1,int l2,int default_out)
{
nand[t].link[0]=l1;
nand[t].link[1]=l2;
nand[t].out=default_out;
}Ebből már sejthető, hogy az alapstruktúrának valami hasonlónak kell lennie.
struct struct_nand
{
int in1,in2,out;
int link[2];
int xykoord[3][2];
}nand[2000];Lesz egy kapunak két bemenete és egy kimenete. Hogy honnan szedje az értéket a bemenet, ezt adja meg a link[]. Ezt definiáltam az előbb.
A kapuk szimulációja sem sokkal bonyolultabb.
for(j=0;j<sor*sor;j++)
if((j%sor))//elso sor nem kell
{
int link1=nand[j].link[0];
int link2=nand[j].link[1];if(link1==link_5V) nand[j].in1=1;//fix input
if(link2==link_5V) nand[j].in2=1;
if(link1==link_0V) nand[j].in1=0;
if(link2==link_0V) nand[j].in2=0;if(link1>=0) nand[j].in1=nand[link1].out;//out -> in1,2
if(link2>=0) nand[j].in2=nand[link2].out;
}
for(j=0;j<sor*sor;j++)
if((j%sor))//elso sor nem kell
{
nand[j].out=!(nand[j].in1 & nand[j].in2);//NAND muvelet
}A kapu lehet az 5V-ra vagy a földre kötve, de kaphatja a bemenetét egy másik kapuról. Ha ezt beállitottuk, akkor már csak a NAND művelet elvégzése van hátra.
Igazából ez már így működik, de senki nem kiváncsi egyesek meg nullák ugrálására a képernyőn.
Na ez a rész már kissé bonyolultabb lesz, de nem vészes.[ Szerkesztve ]
-
t3rm1nat0r
csendes tag
Elég a mellébeszélésből, lássuk a lényeget.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <X11/Xlib.h>
#include <assert.h>
#include <unistd.h>
Display *disp;
Window win;
GC gc;
void pixel(int x,int y,int color)
{
XSetForeground(disp,gc,color);
XDrawPoint(disp, win, gc, x,y);
}
void draw_line(int x1,int y1,int x2,int y2,int color)
{
XSetForeground(disp,gc,color);
XDrawLine(disp, win, gc, x1,y1,x2,y2);
}
void initialize()
{
disp = XOpenDisplay((0));
win = XCreateSimpleWindow(disp, DefaultRootWindow(disp), 0,0, 1200, 850, 0,0,0);
XSelectInput(disp, win, StructureNotifyMask);
XMapWindow(disp, win);
gc = XCreateGC(disp, win, 0, (0));
XSetForeground(disp,gc,0);
while(1)
{
XEvent event;
XNextEvent(disp, &event);
if (event.type == MapNotify)break;
}
}
//#define random_nand
struct struct_nand
{
int in1,in2,out;
int link[2];
int xykoord[3][2];
}nand[2000];
int szinek[]={0x777700,0xffff00};
int xykoord[10][2];
const int link_0V =-3;
const int link_5V =-2;
const int link_none=-1;
const int sor=32;
const int ketsor=32*2;
void draw_tranz(int x,int y,int l1,int l2,int l3,int n)
{
draw_line(x,y,x,y+8,0xff0000);
draw_line(x+2,y,x+2,y+8,0xff0000);
xykoord[n][0]=x-4;//in
xykoord[n][1]=y+4;
draw_line(x-4,y+4,x-1,y+4,szinek[l1]);
draw_line(x+3,y+2,x+6,y+2,szinek[l2]);
draw_line(x+3,y+6,x+6,y+6,szinek[l3]);
draw_line(x+6,y-2,x+6,y+2,szinek[l2]);
draw_line(x+6,y+9,x+6,y+6,szinek[l3]);
if(n==1)
{
xykoord[4][0]=x+6;//out
xykoord[4][1]=y+9;
}
if(n==0)
{
xykoord[5][0]=x+6;//0.tr out
xykoord[5][1]=y+9;
}
}
void draw_nand(int j)
{
if(nand[j].link[0]==link_none)
if(nand[j].link[1]==link_none) return;
int x=j%sor;
int y=j/sor;
x*=30;
y*=40;
draw_tranz(x+12,y+12,nand[j].in1,1,!nand[j].in1,0);//1 bal
draw_tranz(x+24,y+12,nand[j].in2,1,!nand[j].in2,1);//3 db jobb lefele
draw_tranz(x+24,y+24,nand[j].in1, !nand[j].in1,0,2);
draw_tranz(x+24,y+36,nand[j].in2, !nand[j].in2,0,3);
int q=0,w=2;//in
draw_line(xykoord[q][0],xykoord[q][1],xykoord[q][0],xykoord[w][1],szinek[nand[j].in1]);
draw_line(xykoord[w][0],xykoord[w][1],xykoord[q][0],xykoord[w][1],szinek[nand[j].in1]);
q=1;w=3;
draw_line(xykoord[q][0],xykoord[q][1],xykoord[q][0],xykoord[w][1],szinek[nand[j].in2]);
draw_line(xykoord[w][0],xykoord[w][1],xykoord[q][0],xykoord[w][1],szinek[nand[j].in2]);
w=4;
draw_line(xykoord[w][0],xykoord[w][1],xykoord[w][0]+3,xykoord[w][1],szinek[nand[j].out]);//out
nand[j].xykoord[0][0]=xykoord[w][0]+3;
nand[j].xykoord[0][1]=xykoord[w][1];
w=0;
draw_line(xykoord[w][0],xykoord[w][1],xykoord[w][0]-3,xykoord[w][1],szinek[nand[j].in1]);//in1
draw_line(xykoord[w][0]+12,xykoord[w][1]+15,xykoord[w][0]-3,xykoord[w][1]+15,szinek[nand[j].in2]);//int2
nand[j].xykoord[1][0]=xykoord[w][0]-3;
nand[j].xykoord[1][1]=xykoord[w][1];
nand[j].xykoord[2][0]=xykoord[w][0]-3;
nand[j].xykoord[2][1]=xykoord[w][1]+15;
w=5;
draw_line(xykoord[w][0],xykoord[w][1],xykoord[w][0]+12,xykoord[w][1],szinek[!nand[j].in1]);//in1
}
void draw_connect(int j,int link,int s,int dx,int col)
{
if(link<0) return;
int x=nand[j].xykoord[s][0];
int y=nand[j].xykoord[s][1];
int x3=nand[link].xykoord[0][0];
int y3=nand[link].xykoord[0][1];
int x2,y2;
x2=x;
y2=y+dx;
draw_line(x,y,x2,y2,col);x=x2;y=y2;
x2=x3;
y2=y;
draw_line(x,y,x2,y2,col);x=x2;y=y2;
x2=x3+dx;
y2=y;
draw_line(x,y,x2,y2,col);x=x2;y=y2;
x2=x3+dx;
y2=y3;
draw_line(x,y,x2,y2,col);x=x2;y=y2;
x2=x3;
y2=y3;
draw_line(x,y,x2,y2,col);x=x2;y=y2;
}
void draw_layer()
{
int j;
for(j=0;j<1000;j+=40) draw_line(0,j+9,1000,j+9,0xffff00);//tap vezetekek
for(j=0;j<1000;j+=40) draw_line(0,j+6,1000,j+6,0x777700);
for(j=0;j<sor*sor;j++) draw_nand(j);
for(j=0;j<sor*sor;j++)
{
int dx=2+(j%8)*2;
draw_connect(j,nand[j].link[0],1,dx,szinek[nand[j].in1]);
draw_connect(j,nand[j].link[1],2,dx,szinek[nand[j].in2]);
}
}
void define_links(int t,int l1,int l2,int default_out)
{
nand[t].link[0]=l1;
nand[t].link[1]=l2;
nand[t].out=default_out;
}
void define_adder(int t,int l1,int l2,int l3)
{
int tr[]={
t+0, t+1, t+2, t+3, t+4,
t+sor+0, t+sor+1, t+sor+2, t+sor+3, 0};//5-8
define_links(tr[0],l1,l2,0); define_links(tr[1],l1,tr[0],0);
define_links(tr[2],tr[5],tr[1],0); define_links(tr[3],tr[2],l3,0);
define_links(tr[4],tr[3],tr[2],0);
define_links(tr[5],tr[0],l2,0); define_links(tr[6],tr[3],l3,0);
define_links(tr[7],tr[4],tr[6],0); define_links(tr[8],tr[0],tr[3],0);
}
void define_dflip(int t,int l1)
{
int tr[]={
t+0, t+1, t+2, t+3, t+4,
t+sor+0, t+sor+1, t+sor+2, t+sor+3, t+sor+4,0};//5-9
define_links(tr[0],link_5V,l1,0); //inverter
define_links(tr[5],link_5V,tr[4],1);
define_links(tr[1],l1,tr[5],0); define_links(tr[2],tr[7],tr[1],1);
define_links(tr[6],l1,tr[4],1); define_links(tr[7],tr[2],tr[6],0);
define_links(tr[3],tr[0],tr[2],1); define_links(tr[4],tr[9],tr[3],0);
define_links(tr[8],tr[0],tr[7],1); define_links(tr[9],tr[4],tr[8],1);
}
void define_decoder(int tr3,int tr4,int mask)
{
int dx[]={sor,sor,sor,sor};//invertalva egy ketsorral lejjebb
if(mask&1) dx[0]=0;
if(mask&2) dx[1]=0;
if(mask&4) dx[2]=0;
if(mask&8) dx[3]=0;
define_links(tr3 ,tr4+dx[0] ,tr4+ketsor+dx[1],0);
define_links(tr3+1,tr3,link_5V,0); //inverter
define_links(tr3+2,tr4+ketsor*2+dx[2],tr4+ketsor*3+dx[3],0);
define_links(tr3+3,tr3+2,link_5V,0);//inverter
define_links(tr3+4,tr3+1,tr3+3,0);
define_links(tr3+5,tr3+4,link_5V,0);//inverter
}
void nand_gates()
{
int i,j,y;
nand[0].out=1;
nand[sor].out=1;
for(j=0;j<sor*sor;j++)
{
nand[j].in1=1;
nand[j].in2=1;
nand[j].link[0]=link_none;
nand[j].link[1]=link_none;
#ifdef random_nand
nand[j].link[0]=j + (rand()%4) + (rand()%4)*sor;
nand[j].link[1]=j + (rand()%4) + (rand()%4)*sor;
#endif
}
//counter
int counter_bazis=2,counter_out_offset=4;
int tr=counter_bazis;
define_dflip(tr,0); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
define_dflip(tr,tr+counter_out_offset-ketsor); tr+=ketsor;
//address decoder
int tr3=20,tr4=counter_bazis + counter_out_offset, addr=0;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
define_decoder(tr3,tr4,addr++); tr3+=sor;
//adder
int adder_bazis=9,adder_out_offset=34;
int tr1=adder_bazis,tr_out1=counter_bazis+counter_out_offset,tr_out_carry=link_0V;
define_adder(tr1,link_0V,tr_out1,tr_out_carry); tr1+=ketsor; tr_out1+=ketsor;
tr_out_carry=adder_bazis + adder_out_offset + 1;
define_adder(tr1, link_5V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
define_adder(tr1, link_0V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
define_adder(tr1, link_5V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
define_adder(tr1, link_0V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
define_adder(tr1, link_0V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
define_adder(tr1, link_0V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
define_adder(tr1, link_0V, tr_out1, tr_out_carry); tr1+=ketsor; tr_out1+=ketsor; tr_out_carry+=ketsor;
while(1)
{
//printf("%d.. %d %d \n",k,nand[0].out,nand[sor].out);
draw_layer();
for(i=0;i<100;i++)
{
//draw_layer();//ido kell mig minden beall, kirajzolhato a koztes allapot
for(j=0;j<sor*sor;j++)
if((j%sor))//elso sor nem kell
{
int link1=nand[j].link[0];
int link2=nand[j].link[1];
if(link1==link_5V) nand[j].in1=1;//fix input
if(link2==link_5V) nand[j].in2=1;
if(link1==link_0V) nand[j].in1=0;
if(link2==link_0V) nand[j].in2=0;
if(link1>=0) nand[j].in1=nand[link1].out;//out -> in1,2
if(link2>=0) nand[j].in2=nand[link2].out;
}
for(j=0;j<sor*sor;j++)
if((j%sor))//elso sor nem kell
{
nand[j].out=!(nand[j].in1 & nand[j].in2);//NAND muvelet
}
}
int s=1,a=0;
for(y=0;y<16;y+=2)
{
// for(x=0;x<6;x++) printf("%d ",nand[x+sor*y].out);
int e=nand[counter_bazis + counter_out_offset + sor*y].out;//counter kimenet
if(e) a+=s;
s<<=1;
printf("%d ",e);
}
printf(" = %d \n",a);
a=0;s=1;
for(y=0;y<16;y+=2)
{
int e=nand[adder_bazis + sor*y + adder_out_offset].out;//adder kimenet
if(e) a+=s;
s<<=1;
printf("%d ",e);
}
printf(" = %d \n",a);
nand[0].out^=1;
printf("\n");
// getchar();
}
}
int main()
{
initialize();
nand_gates();
XFlush(disp);
getchar();
return 0;
} -
t3rm1nat0r
csendes tag
válasz t3rm1nat0r #23 üzenetére
A program már tartalmazza a cím dekódolót és az összeadót is. Ezek így néznek ki.
-
t3rm1nat0r
csendes tag
válasz t3rm1nat0r #24 üzenetére
Talán kezdem a decoderrel.
Mint kivehető a képből, négy bemeneti vezetékből 16 kimenetet állít elő. Helyesebben a 16 közül mindig csak egy aktív. A 4 vezeték egy 4 bites decimális számként van értelmezve. A 16 vezeték közül mindig az aktív, amelyik sorszáma megfelel a deciális szám értékének.
Az első lépés, hogy a 4 vezeték invertálódik. Ez azért kell mert mint mostmár tudjuk, az AND kapu akkor fog aktíválódni, ha minden bemenete 1. Itt négy bemenetű AND kapuk vannak a képen. Ezért nem kell megtanulni a táblázatot, elég csak a szabályt alkalmazni. 1000 bemenetű AND kapura is az érvényes.
Tehát a 10 érteknél a vezetéken 1010 érték lesz. A két nullás vezetéknek az inverzét kell venni, így kapjuk az 1111 értéket, ami már aktíválni fogja az AND kaput.void define_decoder(int tr3,int tr4,int mask)
{
int dx[]={sor,sor,sor,sor};//invertalva egy ketsorral lejjebbif(mask&1) dx[0]=0;
if(mask&2) dx[1]=0;
if(mask&4) dx[2]=0;
if(mask&8) dx[3]=0;define_links(tr3 ,tr4+dx[0] ,tr4+ketsor+dx[1],0);
define_links(tr3+1,tr3,link_5V,0); //inverterdefine_links(tr3+2,tr4+ketsor*2+dx[2],tr4+ketsor*3+dx[3],0);
define_links(tr3+3,tr3+2,link_5V,0);//inverterdefine_links(tr3+4,tr3+1,tr3+3,0);
define_links(tr3+5,tr3+4,link_5V,0);//inverter
}/A programban nincs szükség invertálásra, mert a decoder a counter-t dekódolja, ami Dflipfloppokból áll. Azokról pedig közvetlenül levehető a kimenet inverze, hiszen a visszacsatolt rész pont így működik./
[ Szerkesztve ]
Aktív témák
- Autós topik
- A választási tévinformációk ellen küzd a Meta
- Ukrajnai háború
- Vallás
- AMD K6-III, és minden ami RETRO - Oldschool tuning
- Android alkalmazások - szoftver kibeszélő topik
- Diablo IV
- GoodSpeed: SAMSUNG Galaxy Buds FE (SM-R400NZAAEUE) a 9 éves SONY SBH20 utódja (nálam)
- PlayStation 5
- E-roller topik
- További aktív témák...
- ThinkPad P1 Gen4 27% 16" 4K IPS érintő i7-11850H T1200 32GB 1TB NVMe ujjlolv IR kam gar
- Acer Gaming (i5 8.th, 8 GB , 256 GB, 1050, 17.3 FHD) notebook! AkciÓ!
- Gyönyörű autómatricák azonnal gyors országos kiszállítással! PH-soknak 30% kedvezmény!
- Asus K95VJ, 18,4" FHD, I7-3630QM 8x3,40 GHz, 16GB DDR3, 250GB SSD+1TB HDD, 1GB VGA ,WIN 10, Számla,
- Asus R751L, 17,3" FHD, I7-4510U, 8GB DDR3, 1TB HDD, 2GB VGA ,WIN 10, Számla, garancia
Állásajánlatok
Cég: Ozeki Kft.
Város: Debrecen
Cég: Promenade Publishing House Kft.
Város: Budapest