My dream CPU

III. Асемблер.

МЕТОДИ НА АДРЕСАЦИЯ

RCPU има само 3 метода на адресация: непосредствена, абсолютна и индексна.

Непосредствена адресация.

При този вид адресация числото което се съдържа в операнда на инструкцията ще бъде присвоено на някой от регистрите в процесора. С този вид адресация можем непосредствено да зададем стойност на регистър от целочисления модул, модула за числа с плаваща запетая или адресния модул. Дължината на инструкцията е 2 поредни адреса, но когато се отнася до модула за числа с плаваща запетая дължината на инструкцията е 3 последователни адреса, защото числата с плаваща запетая се разполагат в 2 последователни адреса.

Пример:
I: rA <-- #56 // В целочисления модул rA ще получи стойност 56
D: rA <-- #3.14 // В модула за изчисления с плаваща запетая rA ще получи тойност 3.14

Абсолютна адресация.

При този метод операнда на инструкцията е абсолютен адрес, от който ще се прочете съдържанието му и ще се присвои на регистър на някой от модулите на RCPU или обратното, адрес в който ще се запише съдържание на регистър на модул. Когато имаме посока на данните от CPU към паметта данните могат да не се вземат само от регистър, могат да бъдат резултат от аритметично или логическо изчисление, което ще се запише в паметта. Дължината на инструкцията е 2 последователни адреса.

Пример:
I: rB <-- M[, ]500 // rB на целочисления модул ще се зареди от адрес 500

D: rA --> M[, ]600 // rA на модула за изчисления с плаваща запетая ще се запише на адрес 600 и 601

Индексна адресация.

При този вид адресация адресът в който ще се чете или пише се определя от сумата на базов и индексен регистър плюс съдържанието на операнда на инструкцията. Може също само индексен или само базов плюс операнда на инструкцията.

Пример:
I: rA <-- M[rBs1, rX2]5
// rA на целочисления модул ще се зареди от адрес [rBs1 + rX2 + 5]

D: rA --> M[, rX3]0
// rA на модула с плаваща запетая ще се запише в адрес изчислен по следния начин [rX3 + 0].
В адреса сочен от rX3.





ИНСТРУКЦИИ НА RCPU

Инструкцията се състои от код на операцията и операнд, разположен на следващия адрес.

Фиг. 7 Формат на инструкциите.



Кодът на операцията съдържа:

1. Модулът ( конвейер ) за който се отнася инструкцията:
I - целочислен;
D - с плаваща запетая;
A – адресен.

В изписването на асемблер се използва двуеточие „ : “ за разделител между конвейера и регистъра за по-добра четимост.

2. Посока за предаване на данните – памет-процесор, процесор-памет, регистър-регистър. Посоката е обозначена със стрелка.

3. Регистър за който се отнася. В който ще се пише или чете от него. За I: и D: това са rA и rB. За A: rBs1, rBs2, rBs3, rX1, rX2, rX3, rMaxX, IP, SP Когато посоката за предаване на данни е от процесора към паметта са възможни и следните команди, чийто резултат ще бъде записан в паметта:
аритметични: AplsB, AmnsB, BmnsA, AmulB, AdivB, BdivA, sortAB
логически: AandB, AorB, AxorB, AshlB, AshrB, AshrrB

4. Базов и или индексен регистър за определяне на адреса. Това са: rBs1, rBs2, rBs3, rX1, rX2, rX3
Примери:

.....M[rBs1, rX1]10 // Address = rBs1 + rX1 + 10
….M[rBs2, ]5 // Address = rBs2 + 10
….M[, rX3]0 // Address = rX3
….M[rBs2, rX1]15 // Address = rBs2 + rX1 + 15
….M[]255 // Address = 255 // абсолютна адресация


Списък инструкции за конвейера за целочислена обработка

Инструкции за зареждане на регистрите rA и rB.

I: rA <-- M[] - зарежда регистър rA
I: rB <-- M[] - зарежда регистър rB
I: rB <-- # - зарежда регистър rB

Стрелката сочи от паметта към регистъра.
С горните две инструкции са възможни непосредствена, индексна и абсолютна адресация.

Примери:

I: rA <-- #5     - зарежда rA с 5. Непосредствена адресация.

I: rA <-- M[rBs1, rX1]10     - зарежда rA от адрес от паметта получен чрез rBs1 + rX1 + 10. Индексна адресация.

I: rB <-- M[]500     - зарежда rB от адрес 500. Абсолютна адресация.

Със знак „ # “ означаваме непосредствена адресация. С „ M “ памет и се използва за индексна и абсолютна адресация. Когато между скобите не е посочен регистър имаме абсолютна адресация, ако има е индексна.
Инструкции за запис на регистрите в паметта:

I: rA --> M[, ] - запис на rA

I: rB --> M[, ] - запис на rB

Пример:

I: rA --> M[, ]500 - запис на rA в адрес 500.

I: rB --> M[, rX3]0 - запис на rB в адрес сочен от rX3

Аритметични операции:

AplsB     // rA + rB

AmnsB     // rA - rB

BmnsA     // rB- rA

AmulB     // rA * rB

AdivB     // rA / rB

BdivA     // rB / rA


Примери:

I: AplsB --> M[, rX1]3
Резултата от изчислението rA + rB ще се запише в паметта на адрес сочен от rX1+3

I: BdivA --> M550
Резултата от изчислението rB /rA ще се запише в паметта на адрес 550


Логически операции:
AandB - логическо AND
AorB - логическо OR
AxorB - логическо XOR
AshlB - SHL, отместване на ляво в rA по младшите битове на rB
AshrB - SHR, отместване на дясно в rA по младшите битове на rB
AshrrB - SHR, отместване на дясно в rA със знаковия бит по младшите битове на rB

При 32 битово изпълнение на процесора се ползват само младшите 5 бита на rB.
При 64 битово изпълнение на процесора се ползват само младшите 6 бита на rB.
Примери:

I: AandB --> M[rBs3, rX3]
// Резултата от изчислението rA and rB ще се запише в паметта на адрес сочен от rBs3 +rX3

Инструкции с преход:

ifAB - Сравняват се регистрите rA и rB по зададено условие < , <=, =>, >, ==
Извършва се преход при изпълнено условие. Прехода може да се извърши на адрес чрез абсолютна или индексна адресация.
Примери:

I: if ( A > B ) jump M1000 // Ако rA > rB ще се извърши преход на адрес 1000.

sortAB - Извършва сортиране на rA и rB. Разменя стойностите на регистрите по зададено условие по-голямо или по-малко. Може да се извърши преход при: if Exchange – ако е имало размяна.
if NOT - (if NOT Exchange ) ако не е имало размяна
Преходът може да се извърши на адрес чрез абсолютна или индексна адресация.
Примери:

I: SortAB > ; IfExch M1200
// След изпълнението на инструкцията стойността на rA ще е по-голяма от стойността на rB. Ако е била извършена размяна ще се осъществи преход на адрес 1200.

I: SortAB > ; IfNoExch M1300
// След изпълнението на инструкцията стойността на rA ще е по-голяма от стойността на rB. Ако не е била извършена размяна ще се осъществи преход на адрес 1300. Обикновено ако не е имало размяна се прескачат следващите инструкции, които ще запишат регистрите rA и rB обратно в паметта. Записването им обратно в паметта е ненужно защото те са подредени по желаният начин. Това подобрява бързодействието при сортиране.
Инструкции за стека:
Push - поставя съдържанието на регистър в стека
pop - чете от стека и поставя в регистър

Примери:
I: push rA // Поставя съдържанието на регистър rA в стека и намалява съдържанието с 1 на SP – указателя на стека

I: pop rB // Взима върха на стека и го поставя в rB увеличава съдържанието на SP с 1.

Списък инструкции за конвейера за работа с числа с плаваща запетая.

Инструкциите са същите както при конвейера за целочислена обработка. Липсват логическите операции. При работа със стека SP се увеличава или намалява с 2 вместо с едно, защото числата в double форма са 2 пъти по-дълги. Можете да използвате горните примери, като замените I: с D:

Списък с инструкциите на адресният модул

Инструкции посока памет --> регистър:
A: rBs1 <-- M // Зарежда регистър rBs1
A: rBs2 <-- M // Зарежда регистър rBs2
A: rBs3 <-- M // Зарежда регистър rBs3

A: rX1 <-- M // Зарежда регистър rX1
A: rX2 <-- M // Зарежда регистър rX2
A: rX3 <-- M // Зарежда регистър rX3
A: rIP <-- M // Зарежда регистър rIP; Еквивалент на безусловен jump
A: rSP <-- M // Зарежда регистър rSP; Желателно е да се използва само в началото, при установяването на процесора.
A: rMaxX <-- M //Зарежда регистър rMaxX

С всички тези инструкции могат да се използват непосредствена, индексна и абсолютна адресации.

Инструкции посока регистър – памет, са същите като гореизброените памет-регистър, като при изписването им стрелката е с обратна посока. Непосредствена адресация не може да се използва с тях.
Инструкции за преход:
A: IfMaxX rX1 < rMaxX ; M
// Ако rX1 < rMaxX ще се извърши преход на посочен адрес. Могат да се използват регистри rX1, rX2, rX3. Абсолутна адресация.

Инкрементиране:
A: IncX rX2 M
// Инкрементира се регистър rX2. Могат да се използват регистри rX1, rX2, rX3. Индексна и непосредствена адресация.
Инструкции за работа със стека:
A: push rX1
// Поставя в стека съдържанието на регистър rX1. Могат да се използват всички регистри от адресния модул, без SP.

A: pop rX1
// Зарежда от стека rX1. Могат да се използват всички регистри от адресния модул, без SP.

A: pushCi   // Поставя целочислена константа в стека.

A: pushCd   // Поставя число с плаваща запетая в стека.

Последните 2 инструкции pushCi и pushCd са в групата на инструкциите на адресният модул защото променят единствено стойността на SP и естествено поставят стойност в стека. Те не влияят на регистър от друг модул.
Инструкции регистър-регистър

Инструкциите регистър- регистър са възможни между регистри в един и същ модул или между различни модули. При инструкция с източник целочисления или адресния модул и цел модула с плаваща запетая дробната част се нулира. При инструкции с източник модула с плаваща запетая и цел целочисления или адресния модул, дробната част се отрязва.

Регистър- регистър в целочисленият модул:

В тази група инструкции влизат инструкциите за предаване на стойност между регистрите му rA и rB, както и запис на резултат от изчисление в някой от двата регистъра.
Предаване на стойност.
I: rA --> I: rB // Стойността на rA се присвоява на rB
I: rB --> I: rA // Стойността на rB се присвоява на rA

Резултат от изчисление да се присвои на регистър.
I: AplsB --> I: rA // rA + rB ще се присвои на rA

Валидни са всички възможни операции в целочисленият модул.
AplsB, AmnsB, BmnsA, AmulB, AdivB, BdivA, AandB, AorB, AxorB, AshlB, AshrB, AshrrB

I: AplsB --> I: rA
I: AmnsB --> I: rA
I: BmnsA --> I: rA
I: AmulB --> I: rA
I: AdivB --> I: rA
I: BdivA --> I: rA
I: AandB --> I: rA
I: AorB --> I: rA
I: AxorB --> I: rA
I: AshlB --> I: rA
I: AshrB --> I: rA
I: AshrrB --> I: rA

Разбира се резултатът може да се присвои и на rB.

Регистър- регистър в модула с плаваща запетая:

Инструкциите са същите както при целочисленият модул, само префикса е D:.

Регистър- регистър в адресният модул:

Тези инструкции служат за предаване на стойност между регистрите в адресният модул. Трябва да се внимава когато се присвоява стойност на IP, това е еквивалентно на инструкция jump. Също присвояване на нова стойност на SP регистъра може да разруши организацията на стека. Четенето от IP и SP е безпроблемно.

Възможно е между всички регистри в адресният модул.
rBs1, rBs2, rBs3, rX1, rX2, rX3, rMaxX, IP, SP

A: rBs1 --> A: rX2
A: rBs2 --> A: rX2
A: rBs3 --> A: rX2
A: rX1 --> A: rX2
A: rX2 --> A: rX2 // да възможна е, въпреки че е безсмислена
A: rX3 --> A: rX2
A: rMaxX --> A: rX2
A: IP --> A: rX2
A: SP --> A: rX2

Целочислен модул – адресен модул:

Може да се изпълни между всеки регистър на целочисления и всеки регистър на адресния модул.

Примери:

I: rA --> A: rX1

Може резултат от изчисление на целочисления модул да се присвои на регистър от адресния модул.

Пример:
I: AplsB --> A: rX2 // rA + rB се присвоява на rX2
Валидни са всички регистри и операции на целочисленият модул и всички регистри на адресният модул.

Адресен модул – целочислен модул:

A: rX1 --> I: rA // rA на целочисленият модул приема стойността на rX1 от адресният модул.

Възможно е да участва всеки от регистрите на адресният модул ( rBs1, rBs2, rBs3, rX1, rX2, rX3, rMaxX, IP, SP ) както и двата от регистрите на целочисленият модул rA и rB.

Модул с плаваща запетая – адресен модул:

D: rA --> A: rX1 // Целочислената част на регистъра rA ще се присвои на rX1

Възможно е и резултат от изчисление в модула сплаваща запетая да се присвои на регистър от адресният модул.

Например:
D: AmulB --> A: rMaxX // Целочислената част от произведението между регистрите rA и rB ще се присвои на регистър rMaxX от адресният модул.

Аналогично както при целочисленият модул стойността на всеки регистър на модула с плаваща запетая (rA, rB) или резултатът от изчисление в него ( AplsB, AmnsB, BmnsA, AmulB, AdivB, BdivA ) могат да се присвоят на всеки регистър в адресният модул ( rBs1, rBs2, rBs3, rX1, rX2, rX3, rMaxX, IP, SP ) като дробната част се отрязва.

Адресен модул - модул с плаваща запетая:

Стойността на всеки регистър от модулът за адресация ( rBs1, rBs2, rBs3, rX1, rX2, rX3, rMaxX, IP, SP ) може да се присвои на всеки регистър от модула за изчисления с плаваща запетая (rA, rB), като дробната му част се нулира.
Примери:

A: rBs1 --> D: rB // rB на модула за плаваща запетая ще приеме стойността на rBs1 от адресният модул.

Целочислен модул – модул с плаваща запетая:

Всеки регистър ( rA, rB ) или резултатът от всяко изчисление ( AplsB, AmnsB, BmnsA, AmulB, AdivB, BdivA, AandB, AorB, AxorB, AshlB, AshrB, AshrrB ) в целочисленият модул могат да се присвоят на някой от регистрите ( rA, rB ) в модула с плаваща запетая, като дробната им част се нулира.
Примери:

I: AdivB --> D: rA // Резултатът от rA/rB в целочисленият модул ще се присвои на регистър rA от модула с плаваща запетая.

Модул с плаваща запетая - целочислен модул:

Стойността на всеки регистър (rA, rB) от модулът с плаваща запетая или резултат от изчисление в него (AplsB, AmnsB, BmnsA, AmulB, AdivB, BdivA,) могат да се присвоят на регистър от модула за обработка на цели числа (rA, rB). Взима се само целочислената част.
Примери:

D: AmnsB --> I: rA // Целочислената част на резултата от изчислението rA – rB в модула за обработка на числа с плаваща запетая ще се присвои на регистър rA от модула за изчисления с цели числа.

Някои особени инструкции

Инструкции които присвояват стойност на програмният брояч IP имат особеност при тяхното изпълнения. Присвояване на стойност на програмният брояч е еквивалентно на инструкцията jump, която е безусловен преход. При изпълнението на тази инструкция втора степен на конвейера за обработка на инструкции я разпознава и освен нормалното присвояване на стойност на регистър, тя извършва reset на първа степен на конвейера за обработка на инструкции. Това предотвратява изпълнението на инструкцията след нея.