2016-11-16 45 views
7

w C i C++ kod, w szczególności dla systemów wbudowanych, ja regularnie natknąć się na zadaniach, które mają następujący kształt:Cel późniejszego wykorzystania lub, a i związek operatorów przypisania na rejestrach

A |= B; 
A &= B; 

nie wiem, czy istotne, ale A i B są tutaj rejestrami. Zobacz przykład tutaj: http://processors.wiki.ti.com/index.php/Interrupt_Nesting_on_C28x#Example_Code następujące linie pojawiają się:

IER |= 0x002; 
IER &= 0x002; 

Jednak te kolejne zadania wydają się identyczne zadania

A = B; 

wyjątkiem faktu, że teoretycznie pojedynczy, ten pierwszy może w niektórych przypadkach zostać przerwany między oboma wierszami, ale wydaje się, że nie odgrywa to ważnej roli w większości kodów.

Czy istnieje korzyść z używania tego pierwszego z tych ostatnich, lub czy istnieje inna różnica, której nie widzę?

+5

Wyświetlany kod i łącze do niego dotyczy systemu wbudowanego. Ustawianie i kasowanie bitów może spowodować różne rzeczy w sprzęcie. Możliwe, że jest podzielony w taki sposób, aby wywoływać różne zdarzenia sprzętowe. –

+0

Również w C++ należy wziąć pod uwagę takie czynniki, jak przeciążanie operatorów. –

+2

'IER' w twoim przykładzie to rejestr procesora, więc może być użyty w każdym cyklu. Może to jest powód. – SingerOfTheFall

Odpowiedz

6

Oczywiście, sekwencja dwóch poniższych poleceń:

A |= 0x02; 
A &= 0x02; 

jest identyczna:

A = 0x02; 

ile A nie jest zmienny, ale rejestr sprzętu. W takim przypadku należy zapoznać się z instrukcją MCU/CPU (lub zmapowanym urządzeniem peryferyjnym), aby sprawdzić, dlaczego dokładnie ta sekwencja jest wymagana.


UPDATE

Zmienna vs rejestru Hardware

W komentarzach powyżej, OP zapytał jak odróżnić zmiennych i rejestruje.

To całkiem proste. Wszystko, co musisz zrobić, to spojrzeć na definicję. Podczas gdy typowe zmienna będzie definiowana jako coś takiego:

unsigned char A; 

Hardware definicja rejestr będzie wyglądać podobnie do:

#define A (*(volatile uint16_t *)(0x1234)) 

Tutaj A jest definiowana jako wartość rejestru sprzętowego, odwzorowane na adres w 0x1234 . Każdy mikrokontroler lub procesor ma swój własny, unikalny zestaw rejestrów sprzętowych i może różnić się nie tylko między różnymi rodzajami architektur i modeli, ale także między różnymi producentami. Jeśli kod źródłowy nie jest dobrze udokumentowany, jedynym sposobem na stwierdzenie, o jaki konkretny rejestr sprzętowy chodzi, jest przejrzenie arkusza danych sprzętowych. Ponadto niektóre zaawansowane architektury mogą rejestrować sprzęt z niektórych urządzeń peryferyjnych w przestrzeni adresowej procesora, dzięki czemu można uzyskać dostęp do rejestrów sprzętowych zewnętrznych komponentów w ten sam sposób.

Uwaga na słowo kluczowe volatile.Z wiki:

Ten parametr zapobiega optymalizacji kompilatora z dala późniejsze odczytuje lub zapisuje, a więc nieprawidłowo ponowne wartość nieświeże lub pomijając zapisy. Wartości lotne powstają przede wszystkim w dostępie sprzętowym (we/wy odwzorowane w pamięci), gdzie odczytywanie lub zapisywanie w pamięci jest używane do komunikacji z urządzeniami peryferyjnymi oraz w wątkach, w których inny wątek mógł zmodyfikować wartość.

-2

A | = 0x02; jest to samo, co A = 0x02;

& = 0x2 uspokaja równy zero (a = 0) założeniu

, gdy oba A i B są jeden bajt value.But istnieją przypadki, w których nie jest równa jeden bajt w tych scenariuszy wszystkich te operatory mają różne właściwości.

Podejmuję przykład 4-bajtowej wartości.

A = 0x12345600

A | = 0x2 równa 0x12345602 natomiast & = 0x2 równa 0x12345600 i A = 0x2 równa 0x00000002

+2

"A | = 0x02; jest taki sam jak A = 0x02;" Tylko jeśli A wynosi zero. W pytaniu nic nie wskazuje na to, że tak jest. Również '0x12345600 & 0x2' daje 0. – Lundin

1

W przypadku, gdy zmienna jest rejestrem sprzętu, który wydaje się w takim przypadku zmienne to volatile. Napisanie trochę, a następnie wyczyszczenie, nie jest wtedy tym samym, co napisanie wartości.

Rejestry sprzętowe nie zawsze zachowują się jak zwykłe zmienne pamięci RAM. Nie ma pewności, że zapisanie zera trochę ustępuje. W szczególności rejestry flag i statusów mogą mieć określone warunki, takie jak "flaga ta jest czyszczona przez zapis do bitu, a następnie odczyt do rejestru". W innych przypadkach flagi można wyczyścić po prostu czytając rejestr.

Jest to bardzo często używane w przypadku rejestrów flag/statusu dla urządzeń komunikacji szeregowej, takich jak SPI lub UART.

Należy również pamiętać, że nie ma gwarancji, że A = B; spowoduje wykonanie pojedynczej instrukcji. Bardziej prawdopodobne jest to, że: "obciążenie B", "magazyn B w A". Jeśli potrzebujesz rzeczy do bycia atomowymi, musisz zawsze rozmontować kod, aby zobaczyć, co tak naprawdę skończyło się.

1

Istnieją sytuacje, w których rejestry sprzętowe, w których pewne sekwencje bitów są niezbędne, mają "specjalne" zachowanie, chociaż trudno zobaczyć, co to może być w tym konkretnym przypadku.

Nie lekceważ prawdopodobieństwa znalezienia kodu w Internecie jako nonsensu, nawet jeśli pochodzi on od strony sprzedawcy układu. Patrząc na dokumentacji wydaje likley że autor zapoznał się następująco:

enter image description here

i został mylić przez odniesienie do OR IER/I IER - oni włączać i wyłączać przerwania ale tak robi instrukcji MOV Ier atomowo. to właśnie zrobi bezpośrednie zadanie.

Jest przykładem później na tej samej stronie:

IER |= M_INT2; 
IER &= MINT2;       // Set "global" priority 

Gdzie argumenty różnią; więc być może autor ma po prostu uogólniony wzór i trzyma się go.