-
1. Data: 2011-06-18 18:13:05
Temat: Do osób znających instrukcje procesora Z80
Od: "Piotrek" <p...@p...onet.pl>
Parę miesięcy temu nosiłem się z zamiarem napisania emulatora jakiejś
rzeczywistej maszyny, wybór padł na ZX Spectrum i procesor Z80. Od jakiegoś
czasu wcielam swój plan w życie, tzn. pieczołowicie emuluję kolejne instrukcje
procesora i potwierdziło się to, czego się obawiałem-nie rozumiem jak
instrukcje odejmowania oddziałują na pewne flagi (tzn. dlaczego oddziałują
inaczej niż mi się zdaje). Z manuali i stron, którymi się posiłkuję, można
wyczytać między wierszami, że odejmowanie z technicznego punktu widzenia
niczym nie różni się od dodawania, tzn. procesor Z80 operację odejmowania
wewnętrznie i tak konwertuje sobie do operacji dodawania, jedynie stan flagi N
odróżnia te działania od siebie, cała arytmetyka odbywa się w kodzie
uzupełnieniowym do 2. Coś mnie jednak tknęło i poprosiłem na pewnym
anglojęzycznym forum o zweryfikowanie moich przypuszczeń co do wyników trzech
przykładowych działań i okazało się, że we wszystkich trzech przypadkach się
myliłem (w każdym wynik był dokładnie przeciwny niż sądziłem).
Załóżmy, że ograniczymy rozważania do operacji na rejestrach 8-bitowych. Moje
wątpliwości dotyczyły zachowania flag C (przeniesienia, ustawianej gdy nastąpi
przeniesienie z bitu 7, tzn. wynik nie zmieści się na 8 bitach) i H
(półprzeniesienia, ustawianej gdy dojdzie do przeniesienia z bitu 3 na 4).
Rozpatrywane były następujące operacje:
1) działanie 3 - 5 (w praktyce załadowanie pierwszej wartości do rejestru A i
wykonanie instrukcji SUB 5).
Moim zdaniem nie dojdzie tu do półprzeniesienia, zdaniem mojego dyskutanta-tak.
Oto jak rozumowałem:
3 - 5 to dla procesora de facto 3 + (-5), 3 to bitowo 00000011,
-5 to 11111011 (działamy w U2).
Zapisując to jedno pod drugim i rachując pisemnie od prawej do lewej (od
najmłodszego bitu do najstarszego) i zakładając, że procesor liczy to tak
samo, dostaję kolejno:
- na pozycji 0 sumę 1 + 1 -> mamy przeniesienie z bitu 0 na 1
- na pozycji 1 sumę 1 + 1 + 1 (przeniesienie) -> mamy przeniesienie z 1 na 2
- na pozycji 2 sumę 0 + 0 + 1 (przeniesienie) -> brak przeniesienia z 2 na 3
Ponieważ ostatnie działanie nie wygenerowało nowego przeniesienia, a dalej nie
mamy już sytuacji, w której sumowalibyśmy dwie jedynki, nie ma bata, żeby
wygenerowało nam się nowe przeniesienie, w szczególności przeniesienie z bitu
3 na 4. Zdaniem mojego dyskutanta jednak występuje. Gdzie tu błądzę?
2) działanie 11 - (-5)
Tu według mojego rozumowania procesor tłumaczy sobie to odejmowanie na
dodawanie 11 + 5. Dalej, postępując analogicznie jak w przypadku 1), widzę jak
byk przeniesienie z bitu 3 na 4, którego zdaniem mojego dyskutanta nie ma.
Wygląda na to, że błądzę tak, jak w przypadku 1), tylko nie wiem dlaczego.
3) Postawiłem tezę, że odjęcie czegokolwiek od 0 nie może spowodować żadnego
przeniesienia. Mój argument: skoro dla Z80 0 - cokolwiek to w rzeczywistości
0 + (- cokolwiek), a 0 bitowo to po prostu 00000000, nie możemy przy
którejkolwiek parze bitów dostać sumu większej od 1, więc nie ma mowy o
przeniesieniu na którejkolwiek pozycji. Mój dyskutant oczywiście stwierdził,
że mylę się po raz trzeci i odjęcie od 0 czegokolwiek poza 0 wygeneruje i
przeniesienie, i półprzeniesienie. Za prawdziwością tego, co mówi, przemawia
niestety też jedna z oficjalnych dokumentacji, która w odniesieniu do
instrukcji NEG (która jest właśnie odjęciem wartości rejestru A od 0 i
wstawieniem do tegoż rejestru wyniku tego działania) mówi, że flaga C ma być
ustawiona zawsze z wyjątkiem sytuacji, w której przed wykonaniem instrukcji
rejestr A zawierał wartość 0.
Zastanawiające jest to, że mój tok rozumowania we wszystkich przypadkach
prowadzi do stwierdzenia będącego negacją stanu faktycznego. Wygląda na to, że
nie myślę źle, tylko moje rozumowanie opiera się na jakiejś błędnej
przesłance. Niestety, mojemu dyskutantowi nie chciało się już wczytywać w mój
tok myślenia prowadzący do złych wyników, mam nadzieję, że komuś z Was zechce
się wyprowadzić mnie z błędu. Odsyłanie mnie do literatury raczej w niczym tu
nie pomoże-przeglądam równolegle kilka manuali i właściwie żaden nie rozwiewa
moich wątpliwości. Owszem, da się w nich znaleźć przykłady na to jak operacje
dodawania wpływają na stan poszczególnych flag, ale o odejmowaniu praktycznie
się nie wspomina, ewentualnie sugeruje się tylko, że przy odejmowaniu "jest
tak samo". Wygląda na to, że jednak nie do końca, dlatego też bardzo proszę
Was o wytknięcie mi błędów w rozumowaniu.
--
Wysłano z serwisu OnetNiusy: http://niusy.onet.pl
-
2. Data: 2011-06-18 18:47:58
Temat: Re: Do osób znających instrukcje procesora Z80
Od: Sebastian Biały <h...@p...onet.pl>
On 2011-06-18 20:13, Piotrek wrote:
> czego się obawiałem-nie rozumiem jak
> instrukcje odejmowania oddziałują na pewne flagi
http://mamedev.org/release.html
Rozpakuj, poszukaj CPU Z80 i z kodu dowiesz się jak działa. Osoby mające
pojęcie o Z80 w takich szczegółach chyba juz wymarły ;)
-
3. Data: 2011-06-18 18:54:58
Temat: Re: Do osób znających instrukcje procesora Z80
Od: Bronek Kozicki <b...@s...net>
On 18/06/2011 19:13, Piotrek wrote:
> Zastanawiające jest to, że mój tok rozumowania we wszystkich przypadkach
> prowadzi do stwierdzenia będącego negacją stanu faktycznego. Wygląda na to, że
> nie myślę źle, tylko moje rozumowanie opiera się na jakiejś błędnej
> przesłance.
ta przesłanka to założenie że implementacje odejmowania jest wrapperem
dla dodawania. Tak nie jest; operacja odejmowania ustawia flagi tak, aby
miały one sens dla odejmowania, a nie dla dodawania.
B.
-
4. Data: 2011-06-18 23:07:01
Temat: Re: Do osób znających instrukcje procesora Z80
Od: "Piotrek" <p...@p...onet.pl>
> ta przesłanka to założenie że implementacje odejmowania jest wrapperem
> dla dodawania. Tak nie jest; operacja odejmowania ustawia flagi tak, aby
> miały one sens dla odejmowania, a nie dla dodawania.
Tak podejrzewałem (chociaż z książek/manuali/stron, które do tej pory
przejrzałem na ten temat, nijak to nie wynikało). Orientujesz się może jak
flagi C i H są ustawiane w przypadku odejmowania, tzn. byłbyś w stanie podać
mi analogiczne reguły? Sensowne wydaje się przyjęcie, że dla odejmowania
flaga C jest ustawiana przy pożyczce z bitu nr 9 (faktycznie
nieistniejącego), o ile operację odejmowania potraktujemy jako pisemne
odejmowanie dwóch liczb binarnych. Niestety, nadal nie umiem podać
analogicznej reguły dla półprzeniesienia-teoretycznie następowałoby ono w
przypadku pożyczki z bitu 4, ale nie do końca mi to pasuje.
-
5. Data: 2011-06-18 23:11:25
Temat: Re: Do osób znających instrukcje procesora Z80
Od: "Piotrek" <p...@p...onet.pl>
> Sensowne wydaje się przyjęcie, że dla odejmowania
> flaga C jest ustawiana przy pożyczce z bitu nr 9
Miało być: bitu 9, czyli o numerze 8 licząc od 0
-
6. Data: 2011-06-19 07:56:42
Temat: Re: Do osób znających instrukcje procesora Z80
Od: Bronek Kozicki <b...@s...net>
On 19/06/2011 00:07, Piotrek wrote:
>> ta przesłanka to założenie że implementacje odejmowania jest wrapperem
>> dla dodawania. Tak nie jest; operacja odejmowania ustawia flagi tak, aby
>> miały one sens dla odejmowania, a nie dla dodawania.
>
> Tak podejrzewałem (chociaż z książek/manuali/stron, które do tej pory
> przejrzałem na ten temat, nijak to nie wynikało). Orientujesz się może jak
> flagi C i H są ustawiane w przypadku odejmowania, tzn. byłbyś w stanie podać
> mi analogiczne reguły? Sensowne wydaje się przyjęcie, że dla odejmowania
niestety, podręcznik asemblera Z80 zgubiłem 20 lat temu ...
B.
-
7. Data: 2011-06-19 18:50:40
Temat: Re: Do osób znających instrukcje procesora Z80
Od: Mariusz Kruk <M...@e...eu.org>
epsilon$ while read LINE; do echo \>"$LINE"; done < "Piotrek"
>Załóżmy, że ograniczymy rozważania do operacji na rejestrach 8-bitowych. Moje
>wątpliwości dotyczyły zachowania flag C (przeniesienia, ustawianej gdy nastąpi
>przeniesienie z bitu 7, tzn. wynik nie zmieści się na 8 bitach) i H
>(półprzeniesienia, ustawianej gdy dojdzie do przeniesienia z bitu 3 na 4).
Niezależnie od tego, czy odejmowanie jest tłumaczone, czy nie,
http://www.z80.info/z80code.htm twierdzi, że przy SUB:
[...]
C or carry flag 1 if answer <0 else 0
Z or zero flag 1 if answer = 0 else 0
P flag 1 if overflow in twos complement else 0
S or sign flag 1 if 127<answer<256 else 0
N flag 1
H or half carry flag 1 if borrow from bit 4 else 0
[...]
A przy SBC:
[...]
C or carry flag 1 if <0 else 0
Z or zero flag 1 if result = 0 else 0
P flag 1 if TC >127 or <-128 else 0
S or sign flag 1 if 127 < n <256 else 0
N flag 1
H or half carry flag 1 if borrow from bit 12 else 0
[...]
(w ostatniej linijce oczywisty błąd, powinno być "bit 4"; dalej jest
wersja szesnastobitowa, w której powinno być o bicie dwunastym).
>Rozpatrywane były następujące operacje:
>
>1) działanie 3 - 5 (w praktyce załadowanie pierwszej wartości do rejestru A i
>wykonanie instrukcji SUB 5).
>
>Moim zdaniem nie dojdzie tu do półprzeniesienia, zdaniem mojego dyskutanta-tak.
>Oto jak rozumowałem:
>
>3 - 5 to dla procesora de facto 3 + (-5), 3 to bitowo 00000011,
>-5 to 11111011 (działamy w U2).
>
>Zapisując to jedno pod drugim i rachując pisemnie od prawej do lewej (od
>najmłodszego bitu do najstarszego) i zakładając, że procesor liczy to tak
>samo, dostaję kolejno:
>
>- na pozycji 0 sumę 1 + 1 -> mamy przeniesienie z bitu 0 na 1
>- na pozycji 1 sumę 1 + 1 + 1 (przeniesienie) -> mamy przeniesienie z 1 na 2
>- na pozycji 2 sumę 0 + 0 + 1 (przeniesienie) -> brak przeniesienia z 2 na 3
>
>Ponieważ ostatnie działanie nie wygenerowało nowego przeniesienia, a dalej nie
>mamy już sytuacji, w której sumowalibyśmy dwie jedynki, nie ma bata, żeby
>wygenerowało nam się nowe przeniesienie, w szczególności przeniesienie z bitu
>3 na 4. Zdaniem mojego dyskutanta jednak występuje. Gdzie tu błądzę?
Najwyraźniej jednak nie ma zamiany na dodawanie, tylko jest od 00000011
odjęcie 00000101. Wtedy jak najbardziej będziemy pożyczać od bitu
trzeciego aż do przepełnienia.
Reszta przypadków idzie analogicznie.
>Zastanawiające jest to, że mój tok rozumowania we wszystkich przypadkach
>prowadzi do stwierdzenia będącego negacją stanu faktycznego. Wygląda na to, że
>nie myślę źle, tylko moje rozumowanie opiera się na jakiejś błędnej
>przesłance.
Czyżby jednak zamiana odejmowania na dodawanie nie była słusznym
posunięciem?
W każdym razie, http://www.z80.info/zip/z80cpu_um.pdf wcale nie mówi o
zamianie odejmowania na dodawanie, a wręcz przeciwnie, pokazuje na
przykład na stronie 78 odejmowanie i jego skutki dla sygnalizacji
przepełnienia.
--
\------------------------/
| K...@e...eu.org | http://www.nieruchomosci.pl/mieszkanie,38804171
| http://epsilon.eu.org/ |
/------------------------\
-
8. Data: 2011-06-19 21:06:12
Temat: Re: Do osób znających instrukcje procesora Z80
Od: Artur Muszyński <a...@u...wytnijto.com.pl>
W dniu 2011-06-19 01:07, Piotrek pisze:
>> ta przesłanka to założenie że implementacje odejmowania jest wrapperem
>> dla dodawania. Tak nie jest; operacja odejmowania ustawia flagi tak, aby
>> miały one sens dla odejmowania, a nie dla dodawania.
>
> Tak podejrzewałem (chociaż z książek/manuali/stron, które do tej pory
> przejrzałem na ten temat, nijak to nie wynikało). Orientujesz się może jak
> flagi C i H są ustawiane w przypadku odejmowania, tzn. byłbyś w stanie podać
> mi analogiczne reguły? Sensowne wydaje się przyjęcie, że dla odejmowania
> flaga C jest ustawiana przy pożyczce z bitu nr 9 (faktycznie
> nieistniejącego), o ile operację odejmowania potraktujemy jako pisemne
> odejmowanie dwóch liczb binarnych. Niestety, nadal nie umiem podać
> analogicznej reguły dla półprzeniesienia-teoretycznie następowałoby ono w
> przypadku pożyczki z bitu 4, ale nie do końca mi to pasuje.
Niewiele już pamiętam, ale wątpię, abym kiedykolwiek użył flagi H :-)
Jeśli to ma być projekt zabawowy, to ja bym na twoim miejscu odpuścił
sobie chwilowo ten problem.
W kwestii przeniesienia, to zależy, co się czyta.
Podstawowy schemat:
http://en.wikipedia.org/wiki/Adder-subtractor
wg mnie jest skopany pod tym względem, ale już tutaj:
http://tams-www.informatik.uni-hamburg.de/applets/ha
des/webdemos/20-arithmetic/40-addsub/add-sub.html
widać, że C będzie ustawione w twoim przypadku, tak samo, jak zrobi ALU
w Z80.
PS: Oprócz książek, warto jednak trochę poeksperymentować - ZX Spin ma
wbudowany assembler i debugger.
artur