W jaki sposób ALU w mikroprocesorze rozróżnia podpisany numer -7 oznaczony jako 1111 i niepodpisany numer 15, oznaczony również przez 1111?
W jaki sposób ALU w mikroprocesorze rozróżnia podpisany numer -7 oznaczony jako 1111 i niepodpisany numer 15, oznaczony również przez 1111?
Odpowiedzi:
Krótka i prosta odpowiedź brzmi: nie. Żaden współczesny główny procesor ISA nie działa tak, jak myślisz.
W przypadku procesora jest to tylko trochę wzorzec. To od Ciebie, programisty, zależy, co oznacza ten wzór bitowy.
Ogólnie rzecz biorąc, ISA nie rozróżniają różnych typów danych, jeśli chodzi o przechowywanie. (Ignorowanie rejestrów specjalnego przeznaczenia, takich jak rejestry zmiennoprzecinkowe w FPU.) To tylko bezsensowny wzorzec bitów do CPU. Jednak MSRF zrobić mają różne rodzaje instrukcji, które mogą interpretować wzorzec bitowy na różne sposoby. Na przykład, instrukcje arytmetyczne, takie jak MUL
, DIV
, ADD
, SUB
interpretuje wzór bitowy jako pewnego rodzaju numeru, natomiast instrukcji logicznych takich jak AND
, OR
, XOR
interpretować je jako tablica wartości logiczne. Tak więc to od programisty (lub autora interpretera lub kompilatora, jeśli używasz języka wyższego poziomu), zależy, czy wybierzesz prawidłowe instrukcje.
Na przykład mogą istnieć osobne instrukcje dla liczb podpisanych i niepodpisanych. Niektóre ISA mają również instrukcje arytmetyczne z cyframi dziesiętnymi kodowanymi binarnie.
Zauważ jednak, że napisałem powyżej „współczesny główny nurt ISA”. W rzeczywistości istnieją niezależne lub historyczne ISA, które działają inaczej. Na przykład zarówno oryginalny 48-bitowy ISA CISC IBM AS / 400, jak i obecny oparty na POWER 64-bitowy ISA RISC systemu o nazwie teraz IBM i, rozróżniają wskaźniki i inne wartości. Wskaźniki są zawsze oznaczone i zawierają informacje o typie oraz zarządzanie prawami. Procesor wie, czy wartość jest wskaźnikiem, czy nie, i tylko uprzywilejowane jądro systemu i / OS może dowolnie manipulować wskaźnikami. Aplikacje użytkownika mogą manipulować posiadanymi przez siebie wskaźnikami w celu wskazania pamięci, którą posiadają, za pomocą niewielkiej liczby bezpiecznych instrukcji.
Było też kilka historycznych projektów ISA, które obejmowały przynajmniej pewną ograniczoną formę rozpoznawania typu.
char
, który jest 16-bitowy typ unsigned. Oczywiście nadal nie ma niepodpisanych instrukcji arytmetycznych w kodzie bajtowym Java, ponieważ wszelkie char
wartości są automatycznie promowane do int
(arytmetyka 32-bitowa).
Krótka wersja: nie wiadomo. Nie można tego powiedzieć.
Jeśli 1111
reprezentuje -7, to masz reprezentację wielkości znaku , gdzie pierwszy bit jest znakiem, a pozostałe bity są wielkością. W takim przypadku arytmetyka jest nieco skomplikowana, ponieważ dodawanie niepodpisane i dodawanie podpisane używają innej logiki. Tak że prawdopodobnie mają SADD
a UADD
kod operacji, a jeśli wybierzesz niewłaściwy masz nonsensownych wyników.
Częściej jednak 1111
reprezentuje -1 w tak zwanej reprezentacji uzupełnienia do dwóch . W tym przypadku ALU po prostu nie dba o to, czy numery są podpisane, czy niepodpisane! Na przykład weźmy operację 1110 + 0001
. W arytmetyce ze znakiem oznacza to „-2 + 1”, a wynik powinien wynosić -1 ( 1111
). W arytmetyce bez znaku oznacza to „14 + 1”, a wynik powinien wynosić 15 ( 1111
). ALU nie wie więc, czy chcesz podpisany, czy niepodpisany wynik, i nie obchodzi go to. Po prostu dodaje to tak, jakby było niepodpisane, a jeśli chcesz później traktować to jako liczbę całkowitą ze znakiem, to zależy od ciebie.
EDYCJA: Jak słusznie wskazują Ruslan i Daniel Schepler w komentarzach, niektóre operandy wciąż wymagają osobnych podpisanych i niepodpisanych wersji, nawet na maszynie z dwójką. Dodawanie, odejmowanie, mnożenie, równość i takie wszystko działa dobrze, nie wiedząc, czy liczby są podpisane, czy nie. Ale podział i wszelkie porównania większe niż / mniejsze niż muszą mieć osobne wersje.
EDYCJA EDYCJA: Istnieją również inne reprezentacje, takie jak uzupełnienie , ale w zasadzie nigdy nie są one używane, więc nie powinieneś się o nie martwić.
<
<=
>=
>
są różne dla operandów podpisanych i niepodpisanych, ==
a jednocześnie !=
są niezależne od podpisania .
Jedną z wielkich zalet matematyki z uzupełnieniem do dwóch, z której korzystają wszystkie współczesne architektury, jest to, że instrukcje dodawania i odejmowania są dokładnie takie same dla operandów podpisanych i niepodpisanych.
Wiele procesorów nie ma nawet instrukcji mnożenia, dzielenia lub modułu. Jeśli tak, muszą mieć osobne podpisane i niepodpisane formularze instrukcji, a kompilator (lub programista w asemblerze) wybierze odpowiednią.
Procesory mają również generalnie różne instrukcje dotyczące podpisanych lub niepodpisanych porównań. Na przykład x86 może postępować zgodnie ze CMP
z JL
(skok jeśli mniej niż) jeżeli porównanie powinna zostać podpisana, lub JB
(Przełącz jeśli poniżej) jeżeli porównanie powinno być podpisane. Znów kompilator lub programista wybrałby odpowiednią instrukcję dla typu danych.
Kilka innych instrukcji często występuje w podpisanych i niepodpisanych wariantach, takich jak przesunięcie w prawo lub załadowanie wartości do szerszego rejestru, z rozszerzeniem znaku lub bez.
smulh
i umulh
które zwracają tylko górne bity mnożenia oraz instrukcje podpisane i niepodpisane, które zwróć wynik w rejestrze dwa razy szerszym niż operandy źródłowe.
Tak nie jest. Procesor polega na zestawie instrukcji, aby powiedzieć mu, jakiego rodzaju danych szuka i gdzie je wysłać. Nic w zerach i zerach w samym operandzie nie może z natury sygnalizować ALU, czy dane to char, float, int, sign int itp. Jeśli ten 1111 idzie do obwodu elektrycznego, który oczekuje uzupełnienia 2s, to idzie należy interpretować jako uzupełnienie 2s.
char
na poziomie sprzętowym. Może kiedyś, w czasach mechanicznych drukarek. Ale dzisiaj char
to tylko liczba, jeśli chodzi o sprzęt. Powodem, dla którego różne liczby odpowiadają różnym kształtom liter na ekranie, jest to, że te liczby są używane do wybierania różnych map bitowych lub różnych procedur rysowania z dużego stołu (tj. Z „czcionki”).
Chciałbym dodać dodatek do już udzielonych odpowiedzi:
W większości innych odpowiedzi zauważono, że w arytmetyki dopełniającej dwójki wynik jest taki sam dla liczb podpisanych i niepodpisanych:
-2 + 1 = -1 1110 + 0001 = 1111
14 + 1 = 15 1110 + 0001 = 1111
Istnieją jednak wyjątki:
Division:
-2 / 2 = -1 1110 / 0010 = 1111
14 / 2 = 7 1110 / 0010 = 0111
Comparison:
-2 < 2 = TRUE 1110 < 0010 = TRUE
14 < 2 = FALSE 1110 < 0010 = FALSE
"Typical" (*) multiplication:
-2 * 2 = -4 1110 * 0010 = 11111100
14 * 2 = 28 1110 * 0010 = 00011100
(*) Na wielu procesorach wynik mnożenia dwóch liczb n-bitowych ma szerokość (2 * n) bitów.
Do takich operacji procesory mają różne instrukcje dotyczące arytmetyki podpisanej i niepodpisanej.
Oznacza to, że programista (lub kompilator) musi użyć innych instrukcji dla arytmetyki podpisanej i niepodpisanej.
Na przykład procesor x86 ma instrukcję nazwaną div
do wykonania niepodpisanego podziału i instrukcję nazwaną idiv
do wykonania podpisanego podziału.
Istnieją również różne instrukcje „warunkowe” (skoki warunkowe, set-bit-on-condition), a także instrukcje mnożenia dla arytmetyki podpisanej i niepodpisanej.