[8085] Molestowanie procka

Kącik dla elektroniki retro - układy, urządzenia, podzespoły, literatura itp.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

[8085] Molestowanie procka

Postautor: gaweł » piątek 03 maja 2024, 11:57

Mając uruchomione środowisko z prockiem 8085 można
by zrobić trochę badań i eksperymentów.
Jest wyświetlacz LCD, więc weryfikacja nieudokumentowanych
instrukcji daje się łatwo zrealizować. Na początek
badania związane z przerwaniami połówkowymi.
Generowało mi się trochę „dziwności”, ale później się okazało,
że był błąd w sofcie i po poprawce per saldo
zgadza się z literaturą. Jest jeszcze jedna „dziwność”,
bo nie zauważyłem wpływu operacji zerowania
przerwania 7.5 na działanie całości. Być może problem
jest szerszy i należy go rozpatrywać w szerszej perspektywie.


irq75_000.jpg


Badania przerwania 7.5 w 8085

Mając hardware z prockiem i8085 pomyślałem sobie, że fajnie jest zrobić trochę doświadczeń dotyczących przerwania 7.5 (inne są niestety sprzętowo zablokowane, jak pokazuje schemat), tylko przerwanie 7.5 ma doprowadzony sygnał, pozostałe są uglebione na stałe (przerwanie 5.5 i 6.5 reagują na poziom wysoki, przerwanie 7.5 reaguje na zbocze narastające).
irq75_001.png

Więc by uruchomić przerwanie należy wykonać następujący zapis instrukcją SIM (set interrupt mask).

Kod: Zaznacz cały

Init_hardware                                      ;
        mvi     a , Enable75Inter                  ;
        sim                                        ;
        ret

Wartość i znaczenie bitów w Enable75Inter jest następujące:
irq75_002.png

Jak tego się nie wykona, to procek nie reaguje na przerwania (sprawdziłem). Jak wygląda problematyka po sygnale reset? Przed ustawieniem maski wykonałem instrukcję RIM (read interrupt mask) i stan akumulatora zapisałem w zmiennej do późniejszego wyświetlenia.

Kod: Zaznacz cały

Init_hardware                                      ;
        rim                                        ;
        sta     RIMByte                            ;
        mvi     a , Enable75Inter                  ;
        sim                                        ;
        ret   

By mieć pełna kontrolę nad przerwaniami (czyli generować je samemu), wyjąłem z układu 8253 i dałem taki oto układ (taki ogólnofilozoficzny zadawacz stanów bez dzwonienia styków bazujący na CD4044 – poczwórnym przerzutniku RS).
irq75_003.png

Czerwony kabelek to plus zasilania, niebieski to minus zasilania a pozostałe to wyjścia (jest używane jedno: też czerwony skrajnie prawy).
irq75_004.jpg

irq75_005.jpg

Po odpaleniu programu jest wyświetlony stan konfiguracyjny po resecie.
irq75_006.jpg

Gdzie znaczenie bitów jest następujące:
irq75_007.png

To by się zgadzało z tym, co jest napisane w dokumentacji Intela.
Naciśnięcie przycisku w zadawaczu stanów nie generuje jeszcze nic (jest stan zera: dioda nie świeci).
irq75_008.jpg

Zmiana stanu z zera na jedynkę (zbocze narastające) generuje przerwanie.
irq75_009.jpg

Jego obsługa to:

Kod: Zaznacz cały

        .org    RST75Entry                         ;
        push    psw                                ;
        rim                                        ;
        sta     RIMByte                            ;
        lda     IRQCnt                             ;
        inr     a                                  ;
        sta     IRQCnt                             ;
        mvi     a , 1                              ;
        sta     IRQFlag                            ;
        mvi     a , Cler75FlipFlop                 ;
        sim                                        ;
        pop     psw                                ;
        ei                                         ;
        ret                                        ;

czyli zapamiętanie stanu RIM wewnątrz obsługi przerwania (zmienna RIMByte), zliczenie przerwania (zmienna IRQCnt) i ustawienie flagi, że doszło do przerwania (zmienna IRQFlag). Wyniki są „spożytkowane” w programie „na zewnątrz” przerwania w funkcji main.

Kod: Zaznacz cały

Main                                               ;
        call    InitialiseLCD                      ;
        call    ClrScrLCD                          ;
        lxi     h , HelloMessage                   ;
        call    WriteTextLCD                       ;
        call    NewLineLCD                         ;
        mvi     a , '#'                            ;
        call    WriteChLCD                         ;
        lda     IRQCnt                             ;
        call    DispHex                            ;
        call    DisplayRIM                         ;
Main_0                                             ;
        lda     IRQFlag                            ;
        cpi     0                                  ;
        jz      Main_0                             ;
        mvi     a , 0                              ;
        sta     IRQFlag                            ;
        call    ClrScrLCD                          ;
        mvi     a , '*'                            ;
        call    WriteChLCD                         ;
        lda     IRQCnt                             ;
        call    DispHex                            ;
        call    DisplayRIM                         ;
        call    NewLineLCD                         ;
        rim                                        ;
        sta     RIMByte                            ;
        mvi     a , ' '                            ;
        call    WriteChLCD                         ;
        mvi     a , ' '                            ;
        call    WriteChLCD                         ;
        mvi     a , ' '                            ;
        call    WriteChLCD                         ;
        call    DisplayRIM                         ;
        jmp     Main_0                             ;

W pierwszym wierszu są zapamiętane dane z wnętrza przerwania, w drugim wierszu są spoza obsługi przerwania (z funkcji main).
irq75_010.jpg

Różnice są niewielkie: widać, że przyjęcie przerwania jest połączone z wykonaniem instrukcji blokującej przerwania (DI). W obsłudze przerwania jest jeszcze:

Kod: Zaznacz cały

        .org    RST75Entry                         ;
.
.
.
        mvi     a , Cler75FlipFlop                 ;
        sim                                        ;
.
.
.
        ret                                        ;

irq75_011.png

ale nie zauważyłem różnicy: czy flaga jest zerowana czy nie.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [8085] Molestowanie procka

Postautor: gaweł » piątek 03 maja 2024, 18:08

arhl_00.jpg


Instrukcja ARHL procesora 8085

Nieudokumentowana (przynajmniej u Intela) instrukcja ARHL (arytmetycznego przesunięcia w prawo pary rejestrów HL) jest opisana w dokumentacji, którą wyszukał nasz kolega :arrow: Tapy. Przesunięcie arytmetyczne to takie, gdzie najstarszy bit jest powielany (by liczba traktowana w kodzie U2 nie zmieniała znaku), całość jest przesunięta o 1 bit w prawo a najmłodszy bit jaki wychodzi z pary rejestrów HL jest zapisywany do flagi CY. Tą operację można traktować jako dzielenie liczby w kodzie U2 przez 2, natomiast wskaźnik CY zawiera resztę z dzielenia. Program wypisuje swoje epistoły na wyświetlaczu LCD: w pierwszym wierszu są zawartości pary rejestrów przed operacją, w drugim wierszu po operacji oraz pokazany jest stan wskaźnika przeniesienia CY. Program obrabia kilka przykładów i by wszystko nie mignęło na wyświetlaczu, przed każdą prezentacją oczekuje na wystąpienie przerwania 7.5, które ustawia flagę badaną w funkcji main. Powstaje „krokowa” możliwość prezentacji działania instrukcji ARHL.
Wybrane przykłady to:

Kod: Zaznacz cały

        call    StepWait                           ;
        lxi     h , 0001h                          ;
        call    ArhlTest                           ;
        call    StepWait                           ;
        lxi     h , 0002h                          ;
        call    ArhlTest                           ;
        call    StepWait                           ;
        lxi     h , 5555h                          ;
        call    ArhlTest                           ;
        call    StepWait                           ;
        lxi     h , 0aaaah                         ;
        call    ArhlTest                           ;
        call    StepWait                           ;
        lxi     h , 0ffffh                         ;
        call    ArhlTest                           ;

Funkcja testująca to:

Kod: Zaznacz cały

ArhlTest                                           ;
        shld    SaveHLBefore                       ;
        arhl                                       ;
        shld    SaveHLAfter                        ;
        mvi     a , 0                              ;
        aci     0                                  ;
        sta     ProcFlags                          ;
        call    ClrScrLCD                          ;
        lxi     h , HLPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveHLBefore + 1                   ;
        call    DispByte                           ;
        lda     SaveHLBefore                       ;
        call    DispByte                           ;
        call    NewLineLCD                         ;
        lxi     h , HLPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveHLAfter+ 1                     ;
        call    DispByte                           ;
        lda     SaveHLAfter                        ;
        call    DispByte                           ;
        lxi     h , CPrompt                        ;
        call    WriteTextLCD                       ;
        lda     ProcFlags                          ;
        call    DispBit                            ;
        ret                                        ;

Wyciągnięcie wskaźnika CY to wynik operacji: 0 [mvi a,0] + 0 + CY [aci 0]. Wynik wynosi 0 albo 1 w zależności od stanu wskaźnika CY.
Pierwszy przypadek to liczba 1: 1 podzielić przez 2 = 0 i reszty 1.
arhl_01.jpg

Drugi przypadek: 2 / 2 = 1 reszty 0.
arhl_02.jpg

Trzeci przypadek: 5555hex = 21845 dec / 2 = 10922 dec = 2AAA hex i reszty 1 (nawet się zgadza).
arhl_03.jpg

Kolejny wariant: AAAA hex = -21846 dec / 2 = D555 hex = - 10923 dec i reszty 0.
arhl_04.jpg

Ostatni przypadek: FFFF hex = -1 dec / 2 = FFFF hex = -1 dec i reszty 1. Trochę mnie to zdziwiło, ale jest poprawnie, gdyż -1 * 2 = -2 i do tego dodać resztę (-2 + 1 = -1). Nie ma się do czego przyczepić, jest właściwie.
arhl_05.jpg

Znaczy, że procek kuma co to jest ARHL.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [8085] Molestowanie procka

Postautor: gaweł » sobota 04 maja 2024, 11:34

dsub_0.jpg


Instrukcja DSUB procesora 8085

W podobnej technologii zbadane zostało działania instrukcji DSUB (16-bitowej operacji odjęcia od zawartości pary rejestrów HL zawartość pary rejestrów BC z wynikiem pozostawionym w HL). Według dokumentacji Tundry, instrukcja modyfikuje wskaźniki: Z, S, P i CY – znaczy jest przeznaczona do operacji w kodzie naturalnym binarnym, choć również zadziała dla liczb w kodzie U2, ale nie będzie wiadomo, czy nie nastąpiło przepełnienie (wskaźnik V). Podobnie jak poprzednio, program wypisuje swoje epistoły na wyświetlaczu LCD: w pierwszym wierszu są zawartości pary rejestrów przed operacją, w drugim wierszu po operacji oraz pokazany jest stan modyfikowanych wskaźników. Program obrabia kilka przykładów.

Kod: Zaznacz cały

Main_0                                             ;
        call    StepWait                           ;
        lxi     h , 0001h                          ; 0001 hex – 0505 hex
        lxi     b , 0505h                          ;
        call    DsubTest                           ;
        call    StepWait                           ;
        lxi     h , 0505h                          ; 0505 hex – 0505 hex
        lxi     b , 0505h                          ;
        call    DsubTest                           ;
        call    StepWait                           ;
        lxi     h , 0505h                          ; 0505 hex – 0501 hex
        lxi     b , 0501h                          ;
        call    DsubTest                           ;
        jmp     Main_0                             ;

Sama procedura testu to:

Kod: Zaznacz cały

DsubTest                                           ;
        shld    SaveHLBefore                       ;
        lxi     d , SaveBCBefore                   ;
        mov     a , c                              ;
        stax    d                                  ;
        inx     d                                  ;
        mov     a , b                              ;
        stax    d                                  ;
        dsub                                       ;
        shld    SaveHLAfter                        ;
        push    psw                                ;
        pop     d                                  ;
        mov     a , e                              ;
        sta     ProcFlags                          ;
        call    ClrScrLCD                          ;
        lxi     h , HLPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveHLBefore + 1                   ;
        call    DispHex                            ;
        lda     SaveHLBefore                       ;
        call    DispHex                            ;
        lxi     h , BCPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveBCBefore + 1                   ;
        call    DispHex                            ;
        lda     SaveBCBefore                       ;
        call    DispHex                            ;
        call    NewLineLCD                         ;
        lxi     h , HLPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveHLAfter+ 1                     ;
        call    DispHex                            ;
        lda     SaveHLAfter                        ;
        call    DispHex                            ;
        call    DispFlags                          ;
        ret                                        ;

Wydobycie wskaźników jest zrealizowane następująco: akumulator i wskaźniki zapisane na stos i pobrane do jakiejkolwiek pary rejestrów, wskaźniki znajdą się w młodszej części pary rejestrów. Wyświetlenie stanu wskaźników to już operacja iloczynu logicznego stanu zapisanych wszystkich wskaźników i odpowiedniej maski bitowej do wyselekcjonowania poszukiwanego bitu.

Kod: Zaznacz cały

SFlagMask       .equ    10000000b                  ;
ZFlagMask       .equ    01000000b                  ;
ACFlagMask      .equ    00010000b                  ;
PFlagMask       .equ    00000100b                  ;
CYFlagMask      .equ    00000001b                  ;
;***************************************************
DispFlags                                          ;
        lxi     h , SPrompt                        ;
        call    WriteTextLCD                       ;
        lda     ProcFlags                          ;
        ani     SFlagMask                          ;
        call    DispBit                            ;
        lxi     h , ZPrompt                        ;
        call    WriteTextLCD                       ;
        lda     ProcFlags                          ;
        ani     ZFlagMask                          ;
        call    DispBit                            ;
        lxi     h , ACPrompt                       ;
        call    WriteTextLCD                       ;
        lda     ProcFlags                          ;
        ani     ACFlagMask                         ;
        call    DispBit                            ;
        lxi     h , PPrompt                        ;
        call    WriteTextLCD                       ;
        lda     ProcFlags                          ;
        ani     PFlagMask                          ;
        call    DispBit                            ;
        lxi     h , CYPrompt                       ;
        call    WriteTextLCD                       ;
        lda     ProcFlags                          ;
        ani     CYFlagMask                         ;
        call    DispBit                            ;
        ret                                        ;

Finał jest następujący:
dsub_1.jpg

dsub_2.jpg

dsub_3.jpg

Arytmetycznie się zgadza, sprawdziłem za pomocą kalkulatora.
W jednym przypadku było odejmowanie liczby większej od mniejszej, gdzie wynik wyszedł „ujemny”, gdyż został ustawiony wskaźnik zarówno S jak i CY. Ten drugi może posłużyć do operacji 32-bitowych, ale trzeba pokombinować, gdyż nie ma instrukcji odjęcia 16-bitowego z uwzględnieniem CY.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

tapy
User
User
Posty: 124
Rejestracja: niedziela 14 kwie 2019, 17:09
Kontaktowanie:

Re: [8085] Molestowanie procka

Postautor: tapy » sobota 04 maja 2024, 12:44

Molestowanie procka

... a jak się on odpowiednim władzom poskarży? :lol:

Jak dobrze pamiętam to Phillip Stevens rozszerzył bibliotekę zmiennoprzecinkową w Z88DK która wykorzystywała te niepublikowane instrukcje 8085 co skutkowało, że tego typu operacje były szybsze niż w Z80. Źródła powinny być w dystrybucji Z88DK.

PS. Tak dla zmylenia przeciwnika zawarty tam assembler z88dk-z80asm obsługuje te instrukcje 8085. ;)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [8085] Molestowanie procka

Postautor: gaweł » poniedziałek 06 maja 2024, 21:41

Instrukcja LDHI procesora 8085

ldhi_00.jpg


Badania zawsze warto robić. Właśnie namierzyłem pluskwę w oprogramowaniu emulatora procka (będzie więc poprawka) a przy okazji silnie napiechotną metodą uświadomiłem sobie, że LDHI nie ustawia wskaźników (co wyraźnie jest zaznaczone w dokumentacji). Mnie się ubzdurało, że instrukcja ustawia flagi po operacji, więc są ujęte w sofcie (co później okazało się niepotrzebne, ale… zostało). Dopiero jak mi flagi „w głowie” się nie zgadzały z tymi pokazanymi na wyświetlaczu, to rozum mi wrócił i sprawdziłam w dokumentacji.
Technologia znacząco nie odbiega od poprzednich.
Instrukcja LDHI to dosumowanie do DE operandu immediate i zachowanie wyniku w HL. Test instrukcji to (ponieważ operand LDHI jest immediate, a nie chciało mi się aż tak dłubać, by z kodu wyciągnąć wartość operandu dla LDHI, jest on wpisany do akumulatora, no trzeba zadbać o zgodność operandu z wartością ładowaną do acu):

Kod: Zaznacz cały

Main_0                                             ;
        call    StepWait                           ;
        lxi     h , 0001h                          ;
        mvi     a , 01h                            ;
        ldhi    01h                                ;
        call    LdhiTest                           ;
        call    StepWait                           ;
        lxi     h , 0ffffh                         ;
        mvi     a , 01h                            ;
        ldhi    01h                                ;
        call    LdhiTest                           ;
        call    StepWait                           ;
        lxi     h , 5555h                          ;
        mvi     a , 55h                            ;
        ldhi    55h                                ;
        call    LdhiTest                           ;
        call    StepWait                           ;
        lxi     h , 0AAAAh                         ;
        mvi     a , 10h                            ;
        ldhi    010h                               ;
        call    LdhiTest                           ;
        call    StepWait                           ;
        lxi     h , 0AAAAh                         ;
        mvi     a , 0ffh                           ;
        ldhi    0ffh                               ;
        call    LdhiTest                           ;
        jmp     Main_0                             ;

Sama operacja to:

Kod: Zaznacz cały

DEPrompt        .defb   'DE=',0
HLPrompt        .defb   'HL=',0
ImArgPrompt     .defb   ' argument imediate=',0
CPrompt         .defb   ' CY=',0
LdhiTest                                           ;  DE = HL + <arg>
        sta     ImArg                              ;
        push    psw                                ;
        pop     b                                  ;
        mov     a , c                              ;
        sta     ProcFlags                          ;
        shld    SaveHL                             ;
        push    d                                  ;
        pop     h                                  ;
        shld    SaveDE                             ;
        call    ClrScrLCD                          ;
        lxi     h , HLPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveHL + 1                         ;
        call    DispHex                            ;
        lda     SaveHL                             ;
        call    DispHex                            ;
        lxi     h , ImArgPrompt                    ;
        call    WriteTextLCD                       ;
        lda     ImArg                              ;
        call    DispHex                            ;
        call    NewLineLCD                         ;
        lxi     h , DEPrompt                       ;
        call    WriteTextLCD                       ;
        lda     SaveDE + 1                         ;
        call    DispHex                            ;
        lda     SaveDE                             ;
        call    DispHex                            ;
        call    DispFlags                          ;
        ret                                        ;

Uzyskane wyniki są następujące i zgadzają się z kalkulatorem:
ldhi_01.jpg

W następnym wyzerowany wskaźnik Z wywołał głębszą rozkminę.
ldhi_02.jpg

ldhi_03.jpg

ldhi_04.jpg

ldhi_05.jpg
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [8085] Molestowanie procka

Postautor: gaweł » środa 08 maja 2024, 20:52

vflag_00.jpg



Wskaźnik V procesora 8085

Oficjalnie wskaźnika takowego nie ma tym procesorze, więc jak zbadać coś, czego nie ma. Ana trzeba zbadać…
Zaczęło się od instrukcji RSTV (restartu od wskaźnika nadmiaru V). No jest instrukcja w dokumentacji Tundry, więc zapewne twórcy wiedzą co robią. RSTV to skok do programu na adresie 40 hex i zapewne procek nie będzie miał problemów z wykonaniem takiej instrukcji, ale… coś musi ten wskaźnik ustawić. Z pewnością nie będzie to instrukcja RDEL (poniżej), gdyż:
1. w opisie nie ma wzmianki o zmianie wskaźnika V,
2. w tabelce w zaznaczonej kolumnie wskaźnik V znalazł się przez pomyłkę, instrukcja przesunięć jako instrukcje o charakterze logicznym zwykle nie generują informacji o nadmiarze (robią to typowo instrukcje arytmetyczne),
3. w innym miejscu dokumentacji podano, że wskaźnik V to bit numer 1 w rejestrze statusów i jest ustawiany przez instrukcja arytmetyczne w zakresie 8- i 16-bitów.
vflag_01.png

vflag_02.png

Znaczy, że głównym powodem ustawienia wskaźnika V są wszystkie instrukcje arytmetyczne. Intel do czegoś takiego się nie przyznaje, googiel też nie zdradza tajemnic Intel’a. Pozostaje „reverse engineering”. Do badań nad zmianami wskaźnika V na pierwszy ogień poszła instrukcja ADD (jako 8-bitów) – kilka operacji z różnymi wartościami operandów:

Kod: Zaznacz cały

        call    StepWait                           ;
        mvi     a , 01h                            ;
        mvi     b , 80h                            ;
        call    ArthTest                           ;
        call    StepWait                           ;
        mvi     a , 7fh                            ;
        mvi     b , 01h                            ;
        call    ArthTest                           ;
        call    StepWait                           ;
        mvi     a , 0ffh                           ;
        mvi     b , 0ffh                           ;
        call    ArthTest                           ;
        call    StepWait                           ;
        mvi     a , 0c0h                           ;
        mvi     b , 0ffh                           ;
        call    ArthTest                           ;
        call    StepWait                           ;
        mvi     a , 0c0h                           ;
        mvi     b , 080h                           ;
        call    ArthTest                           ;
        call    StepWait                           ;
        mvi     a , 0c0h                           ;
        mvi     b , 07fh                           ;
        call    ArthTest                           ;

Operacja testu arytmetycznego to:

Kod: Zaznacz cały

APrompt         .defb   ' A=',0
BPrompt         .defb   ' B=',0
RPrompt         .defb   ' R=',0
;***************************************************
ArthTest                                           ;
        lxi     d , Argument1                      ;
        stax    d                                  ;
        lxi     h , Argument2                      ;
        mov     m , b                              ;
        add     b                                  ;
        sta     Result                             ;
        push    psw                                ;
        pop     b                                  ;
        lxi     h , ProcFlags                      ;
        mov     m , c                              ;
        call    ClrScrLCD                          ;
        lxi     h , APrompt                        ;
        call    WriteTextLCD                       ;
        lda     Argument1                          ;
        call    DispHex                            ;
        lxi     h , BPrompt                        ;
        call    WriteTextLCD                       ;
        lda     Argument2                          ;
        call    DispHex                            ;
        call    NewLineLCD                         ;
        lxi     h , RPrompt                        ;
        call    WriteTextLCD                       ;
        lda     Result                             ;
        call    DispHex                            ;
        call    DispFlags                          ;
        ret                                        ;

Pierwszy przykład: 01 hex + 80 hex
vflag_03.jpg

Procek mówi, że wynik to 82 hex i wskaźnik V=0. Kalkulator w kompie potwierdza.
vflag_04.png

1 hex (1 dec) + 80 hex (-128 dec) = 81 hex (-127 dec). Wynik jest poprawny (mieści się na jednym bajcie), więc wskaźnik V=0 → pasuje.

Drugi przykład, to: 7F hex + 01hex
vflag_05.jpg

Tu już bez kalkulatora widać, że jest nadmiar, gdyż argumenty są dodatnie a wynik jest ujemny → wynik jest niepoprawny w sensie arytmetyki w kodzie U2. Przy okazji, procek również sygnalizuje ustawiony wskaźnik V.


Kolejny przykład: ff hex + ff hex
vflag_06.jpg

Wynik to: ff hex (-1 dec) + ff hex (-1 dec) = fe hex (-2 dec), i również bez kalkulatora można stwierdzić, że jest poprawny, co również sygnalizuje procek V=0.

Następny przykład: c0 hex + ff hex
vflag_07.jpg

Dla ludzie jest to: c0 hex (-64 dec) + ff hex (-1 dec) = bf hex (-64 dec) i jest OK, co potwierdza procek poprzez V=0, a ja sprawdziłem na kalkulatorze.
vflag_08.png


Kolejny test to: c0 hex + 80 hex
vflag_09.jpg

Bez kalkulatora widać, że wynik jest krzywy, gdyż c0 hex jest liczbą ujemną (dokładniej to -64 dec), 80 hex jest liczbą ujemną (-128 dec) a ich suma wypada jako liczba dodatnia (40 hex). Procek również to zauważył i ustawił wskaźnik V=1.


Ostatni przypadek: c0 hex + 7F hex
vflag_10.jpg

Normalnie to jest następująco: c0 hex (-64 dec) + 7F hex (127 dec) = 3F hex (63 dec), co można nawet policzyć na palcach. Ja użyłem kalkulatora i jest OK.
vflag_11.png

Znaczy, że procek 8085, robi co trzeba ale zarząd Intel’a do tego się nie przyznaje. Podsumowując, warto sprawdzić jeszcze arytmetykę 16-bitową, ale już mi się nie chciało. Skoro robi to dla 8-bitów to zapewne operacje 16-bitowe też modyfikują wskaźnik V.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [8085] Molestowanie procka

Postautor: gaweł » czwartek 09 maja 2024, 13:59

rstv_0.jpg


Instrukcja RSTV procesora 8085

Po eksperymentach ze wskaźnikiem V przyszła kolej na instrukcję RSTV. Napisałem program, w którym w przypadku wystąpienia nadmiaru zostanie wywołane takie „przerwanie softwarowe”, jest to skok pok adres 40 hex. Reakcja na przerwanie jest banalnie prosta: ustawia flagę, że takowe zaistniało.

Kod: Zaznacz cały

RST75Entry      .equ    0003ch
RSTVEntry       .equ    00040h
.
.
.
;***************************************************
        .org    RSTVEntry                          ;
        jmp     RSTVService                        ;
;***************************************************
.
.
.
RSTVService                                        ;
        push    psw                                ;
        mvi     a , 1                              ;
        sta     RstvFlag                           ;
        pop     psw                                ;
        ret                                        ;

Tym razem postanowiłem wypróbować arytmetykę 16-bitową, czyli instrukcję DAD (w wariancie: HL = HL + BC). Zostały przygotowane dwa zestawy wartości argumentów. Pierwszy nie ustawia wskaźnika nadmiaru, drugi ustawia.

Kod: Zaznacz cały

Main_0                                             ;
        call    StepWait                           ;
        lxi     h , 0555h                          ;
        lxi     b , 0777h                          ;
        call    RSTVTest                           ;
        call    StepWait                           ;
        lxi     h , 7fffh                          ;
        lxi     b , 0055h                          ;
        call    RSTVTest                           ;
        jmp     Main_0                             ;

Sama procedura testu zapisuje wartości argumentów i wyników (jak i również wskaźników) do pamięci RAM do późniejszego wyświetlenia na LCD.

Kod: Zaznacz cały

HLPrompt        .defb   'HL=',0
BCPrompt        .defb   ' BC=',0
RPrompt         .defb   ' R=',0
RstvPresent     .defb   '    RSTV zaistnialo',0
;***************************************************
RSTVTest                                           ;
        mvi     a , 0                              ;
        sta     RstvFlag                           ;
        mov     a , l                              ;
        sta     Argument1                          ;
        mov     a , h                              ;
        sta     Argument1 + 1                      ;
        mov     a , c                              ;
        sta     Argument2                          ;
        mov     a , b                              ;
        sta     Argument2 + 1                      ;
        dad     b                                  ;
        push    psw                                ;
        pop     b                                  ;
        mov     a , c                              ;
        sta     ProcFlags                          ;
        rstv                                       ;
        mov     a , l                              ;
        sta     Result                             ;
        mov     a , h                              ;
        sta     Result + 1                         ;
        call    ClrScrLCD                          ;
        lxi     h , HLPrompt                       ;
        call    WriteTextLCD                       ;
        lda     Argument1 + 1                      ;
        call    DispHex                            ;
        lda     Argument1                          ;
        call    DispHex                            ;
        lxi     h , BCPrompt                       ;
        call    WriteTextLCD                       ;
        lda     Argument2 + 1                      ;
        call    DispHex                            ;
        lda     Argument2                          ;
        call    DispHex                            ;
        call    NewLineLCD                         ;
        lxi     h , RPrompt                        ;
        call    WriteTextLCD                       ;
        lda     Result + 1                         ;
        call    DispHex                            ;
        lda     Result                             ;
        call    DispHex                            ;
        call    DispFlags                          ;
        lda     RstvFlag                           ;
        cpi     0                                  ;
        rz                                         ;
        lxi     h , RstvPresent                    ;
        call    WriteTextLCD                       ;
        ret                                        ;

Wszystko wyszło jak powinno. Pierwszy przypadek: 555 hex + 777 hex = CCC hex i flaga nie ustawia się.
rstv_1.jpg

Drugi przypadek ma za zadanie wygenerować wskaźnik V: 7FFF hex + 0055 hex przekracza pojemność 16-bitów → zostaje ustawiony wskaźnik V. Ponieważ za instrukcją DAD jest instrukcja RSTV, nastąpiło wywołanie obsługi wyjątku, która odnotowała ten fakt by o tym zdarzeniu później poinformować.
rstv_2.jpg

Niby wszystko OK (w procku), gorzej jest w programie emulatora. Tam dla operacji arytmetycznych 8-bitowych i 16-bitowych jest wyliczany wskaźnik V.
rstv_3.png

tylko, że dla 8- i 16-bitów źle to rachuje. Gdzieś kiedyś znalazłem formułę określenia wskaźnika V (nawet jest zgodna z tym co podaje dokument Tundry) i się nie zgadza z rzeczywistością, bo przykładowo 7FFF hex → znak argumentu 1 to 0, 0055 hex → znak argumentu 2 to 0 i 8054 hex → znak wyniku to 1. Jak nie rachować, to wychodzie false [ ( 0 and 0 ) or ( 0 and 1 ) or ( 0 and 1) = 0]. Mo i … maliny.
rstv_4.png

Po długich poszukiwaniach w sieci znalazłem w jakiejś akademickiej prezentacji wykładów informację, że:
  • V = 1 gdy suma dwóch liczb dodatnich daje wynik ujemny (proste i nie podlega dyskusji),
  • V = 1 gdy suma dwóch liczb ujemnych daje wynik dodatni (proste i nie podlega dyskusji),
  • nadmiar nie występuje przy dodawaniu liczb przeciwnych znaków (no tu muszę zaufać).
Zmieniłem w programie formułę określającą wartość wskaźnika V na:

Kod: Zaznacz cały

  function ComputeVFlag ( Arg1Flag : boolean ;
                          Arg2Flag : boolean ;
                          ResFlag  : boolean ) : boolean ;

  begin (* ComputeVFlag *)
    ComputeVFlag := ( Arg1Flag and Arg2Flag and ( not ResFlag ) ) or
                    ( ( not Arg1Flag ) and ( not Arg2Flag ) ) and ResFlag ;
  end (* ComputeVFlag *) ;

  function ComputeV16Flag ( OpResult : word ;
                            Arg1     : word ;
                            Arg2     : word ) : boolean ;
  var
    Arg1Flag            : boolean ;
    Arg2Flag            : boolean ;
    ResFlag             : boolean ;

  begin (* ComputeV16Flag *)
    Arg1Flag := ( Arg1 and $8000 ) <> 0 ;
    Arg2Flag := ( Arg2 and $8000 ) <> 0 ;
    ResFlag := ( OpResult and $8000 ) <> 0 ;
    ComputeV16Flag := ComputeVFlag ( Arg1Flag , Arg2Flag , ResFlag ) ;
  end (* ComputeV16Flag *) ;

i tym razem zadziałało. Jest to prowizoryczna poprawka, gdyż jest tylko dla operacji dodawania. W przypadku operacji odejmowania jest deczko inaczej. Znów trzeba poprawić program emulatora.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1274
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [8085] Molestowanie procka

Postautor: gaweł » niedziela 12 maja 2024, 20:40

jui_00.jpg


Instrukcja JUI procesora 8085

Tak sobie myślę, że nie ma potrzeby macania każdej nieudokumentowanej instrukcji procka. Skoro dotychczas się zgadza, to właściwie nie ma potrzeby podchodzić do reszty z dozą braku zaufania. Jednak nie wszystko jest takie fajne na jakie wygląda. Przymierzyłem się do instrukcji JUI (mniemam, że JNUI jest jej dopełnieniem). Po pierwsze dostępna dokumentacja mnie zaskoczyła (i to dosłownie). W opisie instrukcji JNUI jest fragment, który jest spoza kontekstu, nie pasuje. Występuje dziwna zbieżność z opisem instrukcji wyżej (źle zadziałało kopij/wklej?). Sytuacja powtarza się w JUI.
jui_01.png

Byłem przekonany, że wskaźnik UI dotyczy nadmiaru w operacji inkrement/dekrement pary rejestrów.
jui_02.png

Literalnie rzecz biorąc, nadmiar dotyczy operacji w kodzie U2 a tu jest mowa o inkrementach i dekrementach. Wskaźnik V już istnieje, więc po co?
W drugim dokumencie wskazanym przez kolegę :arrow: Tapy nie ma więcej informacji (no może tylko tyle, że tam wskaźnik nazywa się X5). Może jednak rzeczywiście chodzi o inkrement i dekrement w kodzie binarnym. Sprawdźmy.

Kod: Zaznacz cały

Main_0                                             ;
        call    StepWait                           ;
        lxi     b , 0555h                          ;
        call    JUI1Test                           ;
        call    StepWait                           ;
        lxi     b , 0ffffh                         ;
        call    JUI1Test                           ;
        call    StepWait                           ;
        lxi     b , 0555h                          ;
        call    JUI2Test                           ;
        call    StepWait                           ;
        lxi     b , 0h                             ;
        call    JUI2Test                           ;
        jmp     Main_0                             ;

gdzie są dwa warianty: jeden dotyczy inkrementacji, drugi dekrementacji.

Kod: Zaznacz cały

NutJumpTxt      .defb   '* nie skoczylo *' , 0
JumpTxt         .defb   '* skoczylo *' , 0
BCPrompt        .defb   'BC=',0
;***************************************************
OperationTxt1   .defb   ' operacja inkrementacji' ,0
;***************************************************
JUI1Test                                           ;
        push    b                                  ;
        lxi     h , Argument                       ;
        mov     m , c                              ;
        inx     h                                  ;
        mov     m , b                              ;
        call    ClrScrLCD                          ;
        lxi     h , BCPrompt                       ;
        call    WriteTextLCD                       ;
        lda     Argument + 1                       ;
        call    DispHex                            ;
        lda     Argument                           ;
        call    DispHex                            ;
        lxi     h , OperationTxt1                  ;
        call    WriteTextLCD                       ;
        call    NewLineLCD                         ;
        pop     b                                  ;
        inx     b                                  ;
        jui     JUI1Test_0                         ;
        lxi     h , NutJumpTxt                     ;
        call    WriteTextLCD                       ;
        ret                                        ;
JUI1Test_0                                         ;
        lxi     h , JumpTxt                        ;
        call    WriteTextLCD                       ;
        ret                                        ;

Kod: Zaznacz cały

OperationTxt2   .defb   ' operacja dekrementacji' ,0
;***************************************************
JUI2Test                                           ;
        push    b                                  ;
        lxi     h , Argument                       ;
        mov     m , c                              ;
        inx     h                                  ;
        mov     m , b                              ;
        call    ClrScrLCD                          ;
        lxi     h , BCPrompt                       ;
        call    WriteTextLCD                       ;
        lda     Argument + 1                       ;
        call    DispHex                            ;
        lda     Argument                           ;
        call    DispHex                            ;
        lxi     h , OperationTxt2                  ;
        call    WriteTextLCD                       ;
        call    NewLineLCD                         ;
        pop     b                                  ;
        dcx     b                                  ;
        jui     JUI2Test_0                         ;
        lxi     h , NutJumpTxt                     ;
        call    WriteTextLCD                       ;
        ret                                        ;
JUI2Test_0                                         ;
        lxi     h , JumpTxt                        ;
        call    WriteTextLCD                       ;
        ret                                        ;

No i wyszło, że działa (chyba w interpretacji liczb jako naturalne binarne).
jui_03.jpg

jui_04.jpg
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse


Wróć do „Retro”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości