1. Zadání
Od operandu X, jehož délka ve slabikách (1 slabika = 1B = 8b) je zapsána v instrukci za operačním znakem jako přímý operand a jehož počáteční adresa je uložena v registru D, se odečte druhý přímý operand, který je 8bitový a nezáporný.
Příznaky CF, OF, SF, ZF a AF musí být nastaveny definovaným způsobem, a to (pokud možno) konzistentně s ostatními instrukcemi. Obsah registru W nemusí být po provedení operace definován. Obsah registru D může být po provedení operace změněn definovaným způsobem. Obsah ostatních by měl zůstat (pokud možno) po provedení operace nezměněn.
2. Popis chování
Jako operační znak jsem zvolil 0Ch, protože to byl jeden z prvních volných operačních znaků. Instrukce je tedy očekávána ve tvaru, jak požaduje zadání (první slabika je operační znak, další je délka prvního operandu ve slabikách, poslední slabika je vlastní druhý 8bitový nezáporný operand).
Po provedení instrukce budou nastaveny příznaky takto: všechny příznaky nastaví na 0, pouze SF se nastaví podle výsledku operace tzn. pokud je výsledek správný (nezáporný) je SF = 0 jinak SF = 1.
První operand je také nezáporné číslo, které je zapsané v paměti jako little-endian. Po provedení instrukce je výsledek zapsán v paměti na stejné adrese, jako byl zapsán první operand (také little-endian). Dále jsou vynulovány všechny použité registry: W, L, D (i T).
3. Stručný popis algoritmu
Vycházíme ze vztahu, podle kterého funguje odčítačka, tedy A – B = A + NOT(B) + 1 – M. Jinými slovy, přivedu-li na sčítačku ALU horkou jedničku, nejnižší slabiku prvního operandu a negovaný druhý operand (obě rozšířené nulami), a pokud dostanu CF = 1, je zřejmé, že došlo ke správnému sečtení. Protože CF = 1, nemusíme již odečítat M v uvedeném vztahu, a správný výsledek je nižší slabika výsledku součtu. Druhý operand byl menší než nejnižší slabika prvního operandu, tedy výsledek se skládá ze všech ostatních slabik prvního operandu a nejnižší slabika je nižší slabika výsledku operace.
Pokud bude nejnižší slabika prvního operandu menší než druhý operand, budou nastaveny flagy: CF = 0 a SF = 1, protože nejvyšší slabika výsledku ve 2 slabikové sčítačce ALU bude FFh. Musíme tedy pokračovat s další slabikou prvního operandu rozšířenou nulami, ke které přičteme FFFFh, což je vlastně výpůjčka z dalšího řádu. Bude-li další slabika prvního operandu větší než 0, dojde k přenosu CF = 1 a vše proběhne v pořádku.
Nebude-li další slabika druhého operandu větší než nula (tedy různá od nuly), nedojde nikdy k přenosu do vyššího řádu a SF bude po projití celého prvního operandu nastaven do 1. Snadno tedy poznáme, že výsledek je platné kladné číslo podle SF.
4. Vývojový
diagram
5. Výpis větve mikroprogramu
Navázání větve – operační znak 0Ch
DEC_3_00_00:{
, 0 , 5 , DEC_MOJE ; dekodovani IR3 IR2, instrukce MOJE
, 0 , 5 , LD2 ; dekodovani IR3 IR2, instrukce LD2
, 0 , 5 , OP2_010 ; dekodovani IR3 IR2, instrukce OP2 - 010
, 0 , 5 , OP2_011 ; dekodovani IR3 IR2, instrukce OP2 - 011
}
dále následuje rozhodovací blok
DEC_MOJE: {
, 0 , 0 , INTCHECK ; 00h - tak tohle nebyla moje instrukce
, 0 , 0 , INTCHECK ; 04h - tak to taky neni ona
, 0 , 0 , INTCHECK ; 08h - ne ne, zase vedle
, 0 , 0 , MOJE ; 0Ch - jo jo - tohle je moje instrukce
}
výpis vlastního mikroprogramu instrukce
MOJE: OEPC OEAB ; vysle adresu 1. primeho operandu na AB
OEPC MRD OEAB ECINL ; nacte 8bitu z DB do registru DIL
OEINZE PEL ; nacte DIL do registru L
, 0 , 14 , MOJE_KONTROLA_LZ ; zkontroluje, zda je L <> 0
MOJE_KONTROLA_LZ:{
, 0 , 0 , MOJE_START ; LZERO = 0 tak zacneme provadet instrukci
, 0 , 0 , MOJE_CHYBA ; LZERO = 1 tak se instrukce neprovede
}
MOJE_START: ECPC OEPC OEAB ; vysle adresu 2. primeho operandu
OEPC MRD OEAB ECINL ; nacte 8bitu z DB do registru DIL
ECPC OEINZE PET ; nacte nulami rozsireneho DIL do registru T
OED OEAB ; vysle adresu D na AB
OED OEAB MRD ECINL ; do DIL nacte [D]
OEINZE ECW , 2 , 0 , ; DIL rozsiri nulami do W
CFS0 ECF UCF ; nastavi CF na 1
ECF ECW OET , 11 , 0 , ; W + NOT(T) + CF -> W, nastavi flagy
ECOUTWR OEW ; W -> D0
OED OEAB ; vysile adresu z D na AB
OEWR OED OEAB MWR ; do pameti na adresu D dolni cast D0
ECD ECL ; dec L, inc D
MOJE_SMYCKA: , 0 , 14 , MOJE_LZ ; kontrola L
MOJE_LZ: {
, 0 , 18 , MOJE_CF ; LZERO = 0, kontrola CF
, 0 , 0 , MOJE_KONEC ; LZERO = 1 tak KONEC
}
MOJE_CF: {
, 0 , 0 , MOJE_DALSI ; CF = 0 musime pokracovat
, 0 , 0 , MOJE_KONEC ; CF = 1 tak konec
}
MOJE_DALSI: ECW ; 0 -> W
OEW ECW , 3 , 0 ; NOT(W) -> W
OED OEAB ; D -> AB
OED MRD OEAB ECINL ; [D] -> DIL
OEINZE PET ; nulami rozsirene DIL -> T
ECF ECW OET , 10 , 0 , ; W + T -> W, nastavyme flagy
ECOUTWR OEW ; W -> D0
OED OEAB ; vysilam adresu z D na AB
OEWR OED OEAB MWR ; do pameti na adresu D dolni cast D0
ECD ECL , 0 , 0 , MOJE_SMYCKA ; dec L, inc D
MOJE_KONEC: ECW ; 0 -> W
OEW PEL ; W -> L
OEPSW PET ; PSW -> T
ECF ECW ; 1 -> ZF, ostatni 0
OEPSW ECW , 2, 0 ; PSW -> W
ECW , 15 , 0 ; SHL W (maska SF 0000 0010 0000 0000)
ECW OET , 4 , 0 ; W AND T -> W
OEW PEF ; W -> FLAGS
ECW ; 0 -> W
OEW PET PED PEL ; nulovani T E D W
, 0 , 0 , INTCHECK ; konec instrukce
MOJE_CHYBA: ECW ; 0 -> W
OEW PEL ; W -> L
OEPSW PET ; PSW -> T
ECF ECW ; 1 -> ZF, ostatni 0
OEPSW ECW , 2, 0 ; PSW -> W
ECW , 15 , 0 ; SHIFT W LEFT 1 nastavime SF na 1
OEW PEF ; W -> FLAGS
ECW ; 0 -> W
OEW PET PED PEL ; nulovani T E D W
, 0 , 0 , INTCHECK ; konec instrukce
Konec výpisu mikroprogramu.
6. Výsledky ladění
Instrukce |
[D] |
CF |
OF |
SF |
ZF |
AF |
[D] |
0C00FFh |
01h |
0 |
0 |
1 |
0 |
0 |
01h |
0C01FBh |
FFh |
0 |
0 |
0 |
0 |
0 |
04h |
0C01FBh |
FBh |
0 |
0 |
0 |
0 |
0 |
00h |
0C01FBh |
FAh |
0 |
0 |
1 |
0 |
0 |
FFh |
0C02FBh |
00FFh |
0 |
0 |
0 |
0 |
0 |
0004h |
0C02FBh |
01FBh |
0 |
0 |
0 |
0 |
0 |
0100h |
0C0201h |
0100h |
0 |
0 |
0 |
0 |
0 |
00FFh |
0C02FBh |
01FAh |
0 |
0 |
0 |
0 |
0 |
00FFh |
0C02FBh |
00FAh |
0 |
0 |
1 |
0 |
0 |
FFFFh |
0C03FBh |
0100FFh |
0 |
0 |
0 |
0 |
0 |
010004h |
0C03FBh |
0100FBh |
0 |
0 |
0 |
0 |
0 |
010000h |
0C03FBh |
010000h |
0 |
0 |
0 |
0 |
0 |
00FFFFh |
0C0301h |
001000h |
0 |
0 |
0 |
0 |
0 |
000FFFh |
0C0302h |
000002h |
0 |
0 |
0 |
0 |
0 |
000000h |
0C03FBh |
0000FAh |
0 |
0 |
1 |
0 |
0 |
FFFFFFh |
Vysvětlivky: [D] značí obsah paměti na adrese uvedené při zavolání instrukce v D (já jsem používal FF04h) a dále, do délky operandu uvedeného v instrukci. Protože je DOP little-endian je obsah zapsán v paměti převráceně, tedy pro [D] = 0100FBh je na adrese FF04h zapsána slabika FBh, na FF05h je 00h a na FF06h je 01h.
7. Závěr
Podařilo se mi vyhovět všem požadavkům uvedeným v zadání až na přesně konzistentní nastavení příznaku ZF s ostatními instrukcemi. Abych vyhověl i tomuto požadavku, musel bych použít minimálně dalších dvou registrů. Přestože registr U jsem nepoužil, další volný registr nebyl k dispozici, proto bych musel změnit další registr a nevyhověl bych zadání v jiném bodě a to, aby zůstal nezměněn obsah ostatních registrů. Proto jsem zvolil toto řešení, instrukce je kratší (přidal jsem 54 nových mikroinstrukcí), méně náročnější (měl jsem s tím méně práce) a dále se domnívám, že k zjištění nulovosti operace v assemleru by nebylo zapotřebí tolik práce jako k ošetření této skutečnosti v mikroassembleru.
Semestrální práce z nlp mi přišla velice poučná. Mohl jsem si vyzkoušet jak bude procesor reagovat na můj vlastní mikroprogram a pochopil jsem, že napsání firmware pro nějaký přístroj není jednoduchá záležitost.
Trochu mi vadilo, že dokud jsem si nenašel na internetu nějakou již vypracovanou práci z minulých let, nevěděl jsem jak to vlastně má vypadat. Možná to zní divně, ale nevěděl jsem jak mám vlastně začít, z jakého konce to mám uchopit. Proto by, podle mne, bylo vhodné dát na internet nějakou vzorovou práci k prostudování; měli bychom jistotu (my studenti), že práce uveřejněná přednášejícím má všechny náležitosti, jaké má mít i naše práce.
Dále mám připomínku k simulátoru DOP. Vadí mi, že
nelze po načtení souboru s mikroinstrukcemi načíst jiný soubor
s mikroinstrukcemi. Po zjištění chyby v mikroprogramu je tedy nutné
program restartovat. Velice to zdržuje ladění.