..

[RS] Како ради процесор или тако нешто

Како сам без икаквог разлога провео недеље свог живота правећи осмобитни процесор који нема неку сврху осим да ми „троши време”, било би штета да га не пропратим подједнако „бескорисним” текстом који би служио као нека документација која објашњава како исти ради, а и као упутство за рекреацију и даљу надоградњу за читавих 0 читалаца овог текста.

Треба погледати два типа архитектура када се дизајнира процесор, а то су Фон Нојман и Харвард. Разлика је у начину на који се користи bus. Харвард користи два, док Вон Нојман архитектура користи један „дељени” bus за податке и инструкције. Како је пројекат свакако трајао више него што је планирано, а и како су туторијали и видео снимци које сам гледао већином били за Фон Нојман архитектуру, то се на крају и правило.

Цео процесор се прави у Logisim Evolution, али је небитно који симулатор логичких кола се користи, верујем да ће било који моћи да постигне што може и овај. А почиње се од „нула”, „јединица” и NAND логичких капија.

Прва ствар коју правимо је:


D Type Flip Flop је оно од чега правимо сваки регистар у процесору. Сваки чува један бит, а реагују на „импулс” clock-a, те се користе да се чувају привремени подаци. D Flip Flop треба да прати следећу табелу:

PRE CLR CLK D = Q NOT Q
0 0 1   1 0
0 0 0   0 1
0 1 X X   0 1
1 0 X X   1 0
1 1 X X   1 1

Имамо четири улаза: PRESET, CLEAR, CLOCK, D. Реално за потребе основног процесора није неопходно имати PRE, али битно је знати како функционише процесор и са таквим „асинхроним” инпутом који овде служи као одређени override, јер игнорише оно што се уноси као D. Где табела показује Х, ту је инпут апсолутно „небитан”, а где се појављује стрелица то представља „горњи пулс” clock-a. Сачувана вредност се обележава са Q, а инвертована као NOT Q. Моја имплементација је приказана на слици испод а направљена је од 4 улаза, два излаза и 6 NAND логичких капија.

DFlipFlop


Након направљеног D Type Flip Flop-a време је да се он искористи за прављење регистара. Почевши од оних једнобитних.


Једнобитни регистар ћемо да користимо за опциони унос бита, тако што уводимо LOAD. Активирањем њега, наш бит A0 се заправо „записује”, док се са угашеним LOAD-ом у Q стално чува 0. Таблицом истинитости приказани су сви могући примери:

CLR CLK LOAD A0 = Q NOT Q
1 X X X   0 1
0 0 0   0 1
0 0 1   0 1
0 1 X   A0 NOT A0

На слици се види и где је додат DFlipFlop, и такође се може приметити да једна тачка није накачена а то је PRESET који је за моје потребе био „непотребан”. Имплементација унутар Logisim-a изгледа овако:

SingleBitRegister


Спајањем четири једнобитна регистра, добијамо четворобитни. Нема пуно шта да се објашњава, сваки једнобитни регистар има свој бит, док деле заједнички LOAD, CLK и CLR. Output им је искључиво Q.

FourBitRegister


Оно што регистри „избацују” не може да се повеже директно на BUS, већ мора да постоји неки buffer како би се избегао „конфликт” при избацивању података различитих система у исто време. Значи сваки подсистем ће имати buffer који ће користити за повезивање са магистралом. За то је идеалан tri-state buffer, који изгледа овако:

TriStateBuffer

Који прати следећу таблицу истинитости:

D ENABLE = Q
X 0   High Impedance
0 1   0
1 1   1

Концепт је врло једноставан за схватити, постоји „прекидач” који контролише да ли се податак преноси или не — од њега зависи хоће ли output постојати или не. Уколико је он угашен, не постоји излаз (Hi-Z). Уколико је укључен, бит који излази зависи од улаза, односно излаз „пресликава” улаз. Овим добијамо потпуну контролу над тим „да л’ нешто иде на магистралу или не”.

Од овога се може направити buffer било које величине, спајањем одређеног броја tri-state buffer-a. Ако ћемо симулирати већ постојеће архитектуре, правимо четворобитни tri-state buffer, иако бисмо реално могли одмах прећи и на осмобитни.

Четворобитни tri-state buffer изгледа овако:

FourBitTriStateBuffer

Значи на графикону су приказана 4 улаза, 4 излаза, 4 tri-state-buffera и један ENABLE који је претходно наведени „прекидач”. А може да се направи и осмобитни tri-state buffer коришћењем два четворобитна.

EightBitBuffer

Од овога се прави регистар са buffer-ом, прво четворобитни а онда „дуплањем” и осмобитни. Оно што сада направимо се заправо користи као A и B регистри у процесору.


FourBitBufferedRegister

Значи четири улаза, која иду у четворобитни регистар који смо раније направили, у који такође иду остали његови неопходни улази CLR, CLK и LOAD, а излази иду директно у улаз четворобитног tri-state buffer-a који такође прима и ENABLE сигнал и на основу њега „прослеђује” излаз.

Дуплањем целог овог елемента, можемо да добијемо осмобитни регистар са buffer-ом.

EightBitBufferedRegister

Шема ће деловати можда мало другачије, али то је зато што је овај осмобитни регистар на „вишем нивоу” од четворобитног, те ми заправо на слици не видимо обичан регистар или четворобитни buffer, већ видимо искључиво два четворобитна регистра са buffer-ом у себи. Али принцип остаје исти: имамо 8 битова улаза, 8 битова излаза, регуларне контроле CLR, CLK, LOAD као и додатну ENABLE.


Инструкциони регистар прихвата улаз са горња 4 бита магистрале, односно „opcode” (операциони код), који ће бити дефинисан касније. Ова 4 бита се прослеђују директно у control logic када је II (Instruction In) сигнал активан. То резултира слањем релевантних команди кроз систем на основу opcode-а из инструкционог регистра. Да би се ово постигло, обичан осмобитни регистар и осмобитни buffer могу се повезати у „петљу”.

FourBitInstructionRegister

Овај граф приказује начин на који инструкциони регистар управља подацима унутар система. Осмобитни регистар са buffer-ом (десно) преузима податке са магистрале (DATA_IN) када се активира сигнал за учитавање (LOAD), док се његов рад синхронизује преко такта (CLK). Виша четири бита излаза (IR4_IR7) представљају opcode који иде директно у контролну логику, док се нижа четири бита користе за податке или адресе. Коришћењем излазног осмобитног buffer-a, који се контролише преко сигнала IO, омогућено је да се регистар повеже у „петљу” (loop) и по потреби врати податке на магистралу без изазивања конфликта.


Након што смо решили инструкциони регистар, треба нам нешто што ће нам заправо показати резултат нашег рада. Ту на сцену ступа Output Register.

Овај регистар је прилично једноставан — његов посао је да „ухвати” податак са магистрале када му контролна логика то нареди (преко сигнала који бисмо могли назвати OI или OUT) и да га проследи на спољни приказ, обично на неке LED диоде или седмосегментни дисплеј. За разлику од претходних регистара, овај не мора да има повратну спрегу са магистралом, јер он служи само за излаз.

OutputRegister

У суштини, ово је обичан осмобитни регистар без buffer-a који „закључа” вредност са магистрале у тренутку када се деси OUT команда. Ово нам омогућава да видимо резултат операције (нпр. збир два броја) чак и када се подаци на самој магистрали касније промене током извршавања следећих инструкција.