Menü Bezárás

4 bites mini processzor

Régóta gondolkodtam egy saját számítógép megépítésén, és mostanra jutottam el odáig, hogy meg is tudjam valósítani. Az elkészítésben nagy segítséget nyújtott a SEM és a műhelyük, ahonnan alkatrészeket kaptam, és hibajavítás céljából egy nyákot is legyártottam.

A cikk egy saját tervezésű processzorról fog szólni, amit a Digit tárgyban már megismert regiszterek, számlálók és multiplexerek segítségével sikerült összeraknom. Igyekeztem a lehető legegyszerűbb (azaz legkevesebb hibalehetőséget tartalmazó) áramkört létrehozni.

A processzor két 10×10 cm-es nyákból áll, az egyiken a vezérlő egység, a másikon az aritmetikai egység kapott helyet. Maga a processzor 4-bites (azaz 0 és 15 közötti számokkal dolgozik). Az eredeti változatban sajnos elég sok hibát találtam, de az ide feltöltött tervrajzokban ezek már javítva vannak. Jelenleg a bemenetre 4 kapcsolót, a kimenetre pedig 4 LED-et raktam, de ez akár shift regiszterekkel is bővíthető.

Schematic: aritmetikai egységvezérlő egység

Utasításkészlet:

Aritmetikai utasítások esetén az egyik operandus a 4-bites akkumulátor (A) regiszer vagy a 0. A másik operandus lehet egy szám, az INPUT külső bemenet, vagy egy adat a memóriából, illetve ezek kettes komplensei (azaz -1 -szeresei).

  • add/sub: összeadás és kivonás (modulo 16), az átvitelbit minden műveletvégzés után alaphelyzetbe állítódik
  • and/or/xor: bitműveletek
  • mov: adatmozgatás, az A regiszer tartalma a megadott címre kerül az adatmemóriába, vagy az OUTPUT kimeneti regiszterbe
  • jmp: ugrás, a programszámláló (PC) regiszter átállítása
  • jz/jnz: feltételes ugrás, csak akkor ugrik, ha A zérus, illetve nem zérus

Az utasítások formátuma “utasítás érték”, pl. “add 5“, de az assembler bonyolultabb parancsokat is ismer, amiket visszaalakít a processzor számára érthetővé, pl. “inc @0” (ami C-ben ezt jelenti: memory[0]++ ) helyett “and 0, or @0, add 1, mov @0“.

Aritmetikai egység:

Itt található az adatmemória, amiben 16 darab 4-bites érték tárolható. A memória adatbuszán található még egy three-state buffer is, hogy írni és olvasni is lehessen belőle. Minden aritmetikai utasítás után számolás eredménye az A regiszterbe kerül. Ha “mov OUTPUT” utasítás érkezik, akkor az OUTPUT kimeneti regiszterbe másolódik az A regiszter értéke.

Maga a számítást végző rész egy mindössze 3 darab logikai kapus (azaz AND, OR, XOR) IC-ből álló kombinációs hálózat, ami az eredményt bitenként számítja ki, és beleshifteli az A regiszterbe. A bitek számítása között keletkező átvitelt és az eredmény zérusságát egy külön státuszregiszterben tárolom, ahonnan csak a zérus (Z) jelet vezettem ki. Emiatt egy műveletvégzés 4 órajelet igényel.

A maradék IC multiplexer, ami arra szolgál, hogy a operandust (szám, memória vagy INPUT) és a megfelelő művelet eredményét (add/sub, and, or vagy xor) kiválassza, illetve hogy a műveletek elején a carry és zero flageket alaphelyzetbe állítsa.

Vezérlő egység:

A feladata, hogy a programmemóriában az éppen a programszámláló (PC) által kijelölt címen található utasításnak megfelelően állítsa elő a vezérlőjeleket az aritmetikai egység számára. A PC regiszer két darab számlálóból áll, így összesen 256 utasítás megcímzésére alkalmas. A programmemória adat- és címvezetékei ki vannak vezetve, hogy pl. egy Arduino-val lehessen rá a programot feltölteni.

Egy aritmetikai számoláshoz 4 órajel szükséges, de még az aktuális utasítást több memóriacímről is ki kell olvasni (mivel minden utasítás 12 bites, de a memóriának csak 8 adatvezetéke van), ezért az egyszerűség kedvéért minden utasításnak 8 órajelnyi időt adtam, és egy számláló alsó 3 bite segítségével állítottam elő a vezérlőjeleket (pl. az adatmemória írása, az A regiszer léptetése, stb.).

Az itt található gombokkal lehet resetelni, és a végrehajtást szünetelni.

Példaprogramok (erős idegzetűeknek):

Az Arduinonak csak az a szerepe, hogy feltöltse a programokat, és még debuggerként is használható. Feltéve, hogy a program már beíródott a programmemóriába, csak egy külső órajel kell a működéshez, amit szintén az Arduino szolgáltat.

Egyszerű számláló, ami a bemenetről beolvasott számnak megfelelő ciklusnyit várakozik:

/*
ezt valósítja meg a kód:
counter = 0;
while(true){
	delay = INPUT;
	while(delay--) {}
	OUTPUT = counter++;
}
*/


alias delay @0 //változók deklarálása
alias counter @1

	eq counter, 0 //értékadás
	
loop: //ez egy címke
	eq delay, INPUT
	
delayloop:
	jz break
	dec delay
	jmp delayloop
	
break:
	eq OUTPUT, counter
	inc counter
	jmp loop

Megszámolja az 1-es biteket a bemeneten (popcount):

alias db @0
alias i @1
	
popcount:
	eq i, INPUT
	eq db, 0

loop:
	ld i
	jz exit
	and 0b1000
	jz skip_inc
	inc db

skip_inc:	
	ld i
	add i
	mov i
	jmp loop

exit:
	eq OUTPUT, db
	jmp popcount

Pszeudovéletlenszám-generátor:

/*
	lsfr -- linear-feedback shift register
	
	részletek: https://en.wikipedia.org/wiki/Linear-feedback_shift_register
	15-ös periódusú 4-bites számsorozat előállítása

	while(true){
		if (i & 1)  { i = (i >> 1) ^ feed; }
		else        { i = (i >> 1);        }
	}
	
	a "feed" értéke csak 9 vagy 0xC lehet
*/

alias i @0 //így lehet változókat deklarálni
alias j @1 //segédváltozó
alias feed 9 //ez egy konstans

	nop
init:
	eq i, INPUT //az INPUT nem lehet 0
	
lsfr:
	eq OUTPUT, i
	
	//először j = i >> 1 értéket kell kiszámítani
	//mivel nincs jobbra shiftelés, ezért bitvadászat következik
	
	//j = 0
	eq j, 0
	//j += i&0b1000 ? 0b0100 : 0
	tst i, 0b1000
	jz skip1
	ld j
	add 0b0100
	mov j
	
skip1:
	//j += i&0b0100 ? 0b0010 : 0
	tst i, 0b0100
	jz skip2
	ld j
	add 0b0010
	mov j
	
skip2:
	//j += i&0b0010 ? 0b0001 : 0
	tst i, 0b0010
	jz skip3
	ld j
	add 0b0001
	mov j
	
skip3:
	//most már: j = i >> 1
	
	tst i, 1
	jnz if
	jz else
	
	//if(i&1){
if:
	//i = j^feed
	ld j
	xor feed
	mov i
	jmp endif
	
	//}else{
else:
	//i = j
	eq i, j
	
	//}
endif:
	jmp lsfr

 

Related Posts

WordPress Appliance - Powered by TurnKey Linux