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í.

vše v zabalený i s timhle souborem ve wordu