Układ przyjmuje dane wejściowe, gdy sygnał zegara jest wysoki, i przekazuje je na wyjście przy opadającym zboczu sygnału zegara. Innymi słowy, przerzutnik Master-Slave JK jest urządzeniem "synchronizowanym", ponieważ przekazuje dane wyłącznie w zależności od zegara. Zwykle przerzutniki typu Master-Slave muszą być konfigurowane z dwóch oddzielnych przerzutników SR, jak w przypadku układu 7473. Na szczęście dostępnych jest wiele układów z podwójnymi przerzutnikami, takich jak 7467, 7473, 74,107, 74,110, 74,111 i CMOS 4027.

Liczniki cyfrowe

Liczniki cyfrowe i rejestry przesuwne mogą być zaprojektowane poprzez kaskadowanie przerzutników. Mogą działać asynchronicznie lub synchronicznie.

Liczniki asynchroniczne

Liczniki asynchroniczne to proste kaskadowanie przerzutników w trybie przełączania, które są wyzwalane jeden po drugim. Oznacza to, że wyjście Q (lub Q) na jednym etapie generuje impuls zegarowy dla następnego etapu i tak dalej. Chociaż generowane impulsy licznika są symetryczne, początkowy impuls zegarowy, jak pokazano na Rysunku 3.15, nie jest symetryczny. Nie stanowi to jednak problemu, ponieważ liczy się tylko zbocze impulsy (rosnące lub opadające). W rzeczywistości, w pokazanym poniżej przykładzie, rosnące zbocze zegara przełącza pierwszy przerzutnik. Następnie, dzięki odwróconym wejściom zegara, kolejne przerzutniki przełączają się na opadające zbocze.

Wyjścia mają postać liczb binarnych (w przypadku ilustracji – 4-bitowych). Zamiast używać przerzutników wyzwalanych opadającym zboczem, przerzutniki wyzwalane rosnącym zboczem mogą być napędzane przez wyjścia Q. Różnica między licznikiem "w górę" a licznikiem "w dół" polega jedynie na wybranych wyjściach. Wyjścia Q generują liczenie w górę, a liczenie w dół uzyskiwane jest na wyjściu Q (Rysunek 3.16).

Oczywiście, jak można sobie wyobrazić, opóźnienie propagacji na każdym etapie będzie się kumulować w miarę postępu przez licznik (Rysunek 3.17). Z tego powodu bardziej odpowiednią konstrukcją jest licznik synchroniczny.

Liczniki synchroniczne

Jak pokazano wcześniej, głównym problemem liczników asynchronicznych jest opóźnienie propagacji. Problem ten w dużej mierze zostaje rozwiązany poprzez synchronizację przerzutników, tak aby wszystkie zmiany zachodziły jednocześnie – a nie jedna po drugiej. Jednakże nie jest to takie proste. Można by pomyśleć, że wystarczy połączyć przerzutniki i zasilać je z tego samego zegara, aby uzyskać licznik synchroniczny. Niestety, jest to błędne rozumowanie, co teraz zostanie zilustrowane przy użyciu prostego przykładu 3-bitowego z Rysunku 3.18.

Widać tutaj, że choć pierwsze dwa ciągi bitów są prawidłowe, trzeci jest błędny. Wynika to z faktu, że Qc zmienia się za wcześnie, ponieważ w tym momencie JKc = 1 (Tabela 3.2). Widać wyraźnie, że potrzebna jest dodatkowa logika. Aby upewnić się, że zarówno Qa = 1, jak i Qb = 1, zanim Qc może zostać przełączone, generowana jest prawidłowa sekwencja, jak pokazano na Rysunku 3.19. Oczywiście tę technikę można rozszerzyć na większe liczniki i przykłady 4-bitowe, jak pokazano na Rysunku 3.20.

Jak w przypadku liczników asynchronicznych, liczniki synchroniczne mogą liczyć w górę lub w dół. Wystarczy wybrać odpowiednie wyjścia. W zaprezentowanym poniżej projekcie zastosowano dodatkową logikę, aby umożliwić wybór trybu "w górę"/"w dół" (Rysunek 3.21). Takie liczniki mogą być rozszerzone do niemal dowolnej liczby bitów. Przykładem jest synchroniczny licznik 4-bitowy 74F161A.

Liczniki pierścieniowe

Oprócz liczników w górę i w dół istnieją również liczniki pierścieniowe. Są to liczniki, które generują powtarzającą się sekwencję pół-symetrycznych impulsów. Poprzez połączenie szeregu przerzutników D i podłączenie ostatniego wyjścia Q do początkowego wejścia D, generowane będą pojedyncze impulsy. Wejście Set w pierwszym przerzutniku i wejścia Reset w kolejnych muszą być połączone w celu zapewnienia początkowego stanu cyfrowego 1, który następnie będzie krążyć w "pierścieniu" wokół licznika (Rysunek 3.22).

Inną popularną formą jest licznik Johnsona, znany także jako licznik kodu termometrowego. Tutaj nie trzeba ustawiać początkowego stanu, ponieważ wyjścia Q i Q ostatniego przerzutnika są sprzężone z wejściami J i K pierwszego przerzutnika (Rysunek 3.23). Takie liczniki można rozszerzyć na dowolną liczbę bitów.

Rejestry przesuwne

Rejestry przesuwne, jak sama nazwa wskazuje, to zestawy rejestrów (przerzutników), które pozwalają na przesunięcie wstępnie określonego stanu binarnego w jednym kierunku lub w przeciwnym. Istnieje wiele trybów, w których rejestry przesuwne mogą być skonfigurowane. Serial In—Serial Out (SISO), Serial In—Parallel Out (SIPO), Parallel In—Serial Out (PISO) i Parallel In—Parallel Out (PIPO). Są one bardzo skuteczne w przesuwaniu wartości binarnych w lewo (do mnożenia) i w prawo (do dzielenia).

Zwykle każdy etap zawiera przerzutnik D. Powszechnie używane 8-bitowe rejestry przesuwne SIPO to 74LS395 i 74LS164 (Rysunek 3.25). Funkcja Tri-State oznacza, że wyjście może być w stanie logicznego 1, logicznego 0 lub po prostu w stanie wysokiej impedancji, co jest przydatne przy łączeniu z systemami szynowymi.

W przypadku rejestrów przesuwanych istnieją dwie funkcje: SHIFT i ROLL. Bity mogą być przesuwane w lewo lub w prawo, a te, które zostaną przesunięte poza koniec rejestru przesuwnego, zostaną utracone. Z kolei bity, które są zwinięte (rolled), są przekazywane z powrotem na wejście rejestru, co tworzy rodzaj pamięci szeregowej. Zdolność do zwijania prowadzi do koncepcji licznika pierścieniowego.

Rejestry przesuwne jako liczniki pierścieniowe

Poprzez sprzężenie zwrotne rejestr przesuwający można łatwo przekształcić w licznik pierścieniowy. Równocześnie wejścia D w trybie równoległym mogą zostać użyte do wstępnego ustawienia wartości początkowej (np. 1000), co stanowi podstawę konwerterów szeregowo-równoległych używanych w systemach szynowych (RS232, RS485, Ethernet itp.).

Jak działa matematyka binarna i jej zastosowania w komputerach?

Matematyka binarna stanowi podstawę cyfrowych systemów komputerowych. W rzeczywistości komputerów, wartości są przechowywane w postaci mantysy i wykładnika, co eliminuje konieczność używania jawnego przecinka dziesiętnego. Zamiast typowych dla ludzi równań matematycznych, takich jak 2×1062 \times 10^6, w komputerach używa się notacji, w której liczba 2×10^6 jest zapisywana jako 2E62E6, a 4.5×10⁻⁷ jako 45E845E-8. Takie podejście pozwala na przechowywanie dwóch liczb całkowitych, które reprezentują mantysę oraz wykładnik, co jest znacznie bardziej efektywne w przechowywaniu i obliczeniach komputerowych.

W zależności od zadeklarowanego typu danych (np. CHAR, INT, LONG), wartości są przechowywane w różnych długościach słów binarnych, takich jak 8, 16, 32 bity, przy czym mantysa i wykładnik są przechowywane osobno. Na przykład, liczba 10.6 może zostać wyrażona jako 10.6×10110.6 \times 10^{ -1}, co w postaci binarnej wygląda następująco:

Mantysa: 01101010
Wykładnik: 10000001

Zauważ, że „1” na początku wykładnika oznacza liczbę ujemną, ponieważ wykładnik zapisany jest w uzupełnieniu do dwóch (komplement dwójkowy). Takie podejście umożliwia efektywne przechowywanie liczb zmiennoprzecinkowych w pamięci komputera, szczególnie przy większych wartościach, jak w przypadku 32-bitowej reprezentacji typu danych FLOAT, gdzie 24 bity są przeznaczone na mantysę (1 bit na znak i 23 bity na dane), a 8 bitów na wykładnik (1 bit na znak i 7 bitów na dane).

Procesy konwersji między różnymi systemami liczbowymi (binarne, ósemkowe, dziesiętne, szesnastkowe) są kluczowe w zrozumieniu działania komputerów. Przykładem może być konwersja liczby dziesiętnej 1284 na inne systemy:

  • Binarnie: 100111110100

  • Ósemkowo: 2374

  • Szestnastkowo: 504

W takich operacjach konieczne jest opanowanie umiejętności konwersji między systemami liczbowymi, co stanowi fundament przy programowaniu niskopoziomowym, np. w assemblerze czy podczas manipulacji pamięcią.

W matematyce binarnej pojawiają się również pojęcia uzupełnienia do dwóch, które jest podstawowym mechanizmem służącym do przechowywania liczb ujemnych w systemie binarnym. Przykładowo, dla liczby 5001, jej reprezentacja w uzupełnieniu do dwóch, a następnie konwersja z powrotem do systemu szesnastkowego jest kluczowym procesem dla zrozumienia, jak komputer przetwarza liczby.

Rozważając bardziej zaawansowane operacje, takie jak odejmowanie za pomocą uzupełnienia do dwóch (np. odejmowanie 5710 od 12010), komputer nie wykonuje tradycyjnej operacji odejmowania. Zamiast tego wykonuje operację dodawania liczby odwrotnej do liczby, od której odejmujemy, a następnie oblicza wynik, co przyspiesza obliczenia i redukuje skomplikowanie obwodów logicznych.

Warto również rozważyć konwersję liczb zmiennoprzecinkowych do postaci binarnej, jak to ma miejsce przy przechowywaniu wartości takich jak 23.84 w systemie binarnym w pamięci komputera. Wartość ta jest reprezentowana w systemie binarnym, ale w rzeczywistości jej przechowywanie odbywa się za pomocą określonych algorytmów, które dzielą liczbę na część całkowitą i ułamkową. Takie operacje wymagają zrozumienia kontekstu przechowywania danych w pamięci oraz operacji matematycznych na tych danych, które są realizowane przez procesor.

Oprócz tego, istotne jest zrozumienie, że każda operacja arytmetyczna, w tym mnożenie czy dzielenie, jest realizowana na poziomie bitów. W procesorach, takich jak te oparte na architekturze Von Neumanna, operacje są wykonywane przez jednostkę arytmetyczno-logiczną (ALU), która wykonuje operacje matematyczne, takie jak dodawanie, odejmowanie, mnożenie i dzielenie. Zrozumienie tego procesu jest kluczowe dla tworzenia algorytmów oraz dla optymalizacji działań na poziomie sprzętu.

Warto również zauważyć, że współczesne komputery wykorzystują różne architektury procesorów. Przykładem mogą być różne typy komputerów: CISC (Complex Instruction Set Computer), które są tradycyjnymi systemami von Neumanna, czy RISC (Reduced Instruction Set Computer), które charakteryzują się prostszymi, szybszymi instrukcjami, ale wymagają większego nakładu pracy po stronie oprogramowania. Inne typy to SIMD (Single Instruction Multiple Data), MISD (Multiple Instruction Single Data), a także MIMD (Multiple Instruction Multiple Data), które pozwalają na pełne równoległe przetwarzanie danych. Wszystkie te architektury mają swoje specyficzne zastosowania w kontekście matematyki binarnej i przetwarzania danych.

Wszystkie te elementy, choć mogą wydawać się trudne, są fundamentem funkcjonowania współczesnych komputerów. Aby efektywnie programować lub projektować systemy komputerowe, konieczne jest zrozumienie, jak działają operacje matematyczne na poziomie bitów i jak komputer reprezentuje i przetwarza dane w różnych formatach.

Jak działają podstawowe operacje arytmetyczne i logiczne w układach cyfrowych?

Podstawowe układy cyfrowe, takie jak sumatory, odejmowniki, komparatory i jednostki arytmetyczno-logiczne (ALU), stanowią fundament działania współczesnych komputerów. Są to elementy, które pozwalają na wykonywanie zarówno prostych, jak i złożonych operacji na danych binarnych. Poznanie ich zasad działania jest kluczem do zrozumienia, jak komputery przetwarzają informacje i realizują obliczenia.

Sumator półpełny (half adder) to jeden z najprostszych układów, który dodaje dwa bity, generując wynik w postaci sumy oraz przeniesienia (carry). Podstawowy układ tego typu można zrealizować za pomocą bramek logicznych AND, OR oraz NOT. Suma jest generowana jako wynik operacji XOR (exclusive OR), natomiast przeniesienie to wynik AND dwóch bitów wejściowych. Przykładowa tabela prawdy dla sumatora półpełnego pokazuje, jak operacje te przebiegają na poziomie binarnym.

Podobnie jak sumatory, odejmowniki (substractory) działają na tej samej zasadzie, ale z jedną różnicą — jedno z wejść bramki AND jest odwrócone, co powoduje, że otrzymujemy różnicę oraz pożyczkę (borrow), a nie sumę i przeniesienie. Odejmowanie w układach cyfrowych często odbywa się przez dodanie odwrotności liczby (komplement dwóch), co jest bardziej efektywne niż bezpośrednie odejmowanie. Warto zauważyć, że w nowoczesnych komputerach rzadko używa się oddzielnych układów odejmujących, zamiast tego stosuje się metodę komplementu i dodawania. Przykłady układów pełnych odejmowników (full subtractors) ukazują, jak kilka takich urządzeń może działać równolegle, umożliwiając odejmowanie liczb binarnych o wielu bitach.

Kolejnym ważnym elementem układów cyfrowych są komparatory. Te układy służą do porównywania dwóch wartości binarnych, co jest niezbędne m.in. w procesach decyzyjnych mikroprocesorów. Komparatory umożliwiają określenie, czy jedna wartość jest większa, mniejsza lub równa innej, co jest niezbędne w realizacji operacji porównań, jak i w procesach sterowania. Ich działanie jest oparte na analizie bitów wejściowych, gdzie każdemu wynikowi przypisana jest odpowiednia akcja: większa, mniejsza lub równa. Dzięki tej funkcji możliwe jest także podejmowanie decyzji w programach sekwencyjnych mikroprocesorów.

Z kolei układy kodujące i dekodujące (encoders i decoders) pełnią rolę w konwersji danych pomiędzy różnymi systemami liczbowymi. Często w cyfrowych systemach konieczne jest zamienienie wartości dziesiętnych na binarne lub odwrotnie. Układy kodujące zamieniają wartości dziesiętne (np. 0-9) na binarne (np. 0000 do 1001), a dekodery pozwalają na powrót do postaci dziesiętnej. W tym kontekście warto wspomnieć o kodzie BCD (Binary Coded Decimal), który jest szczególnie użyteczny w systemach wyświetlających liczby na segmentowych wyświetlaczach, jak w zegarach cyfrowych.

Kiedy omawiamy układy arytmetyczno-logiczne (ALU), dochodzimy do jednego z najważniejszych elementów współczesnych komputerów. ALU jest odpowiedzialne za wykonywanie podstawowych operacji logicznych i arytmetycznych, takich jak AND, OR, dodawanie, a także negacja. Układ ALU zazwyczaj składa się z wielu takich prostych jednostek, które współpracują w ramach n-bitowych operacji, umożliwiając realizację bardziej złożonych obliczeń. Współczesne ALU są znacznie bardziej zaawansowane, lecz zrozumienie podstawowych zasad działania tych układów pozwala lepiej zrozumieć ich rolę w komputerze.

Pomimo że wszystkie te układy cyfrowe można zrealizować w postaci układów logicznych, które są łatwe do zaprojektowania, ich zastosowanie w rzeczywistych komputerach opiera się na znacznie bardziej złożonych mechanizmach. Komputery muszą operować na dużych zbiorach danych w czasie rzeczywistym, dlatego wykorzystywane są techniki takie jak kaskadowanie układów logicznych, programowanie w niskopoziomowych językach, a także zaawansowane algorytmy optymalizacyjne.

Ponadto, w kontekście projektowania układów cyfrowych, warto zwrócić uwagę na rosnącą rolę symulacji komputerowych. Programy do symulacji obwodów logicznych pozwalają na testowanie i optymalizację projektów przed ich fizycznym wdrożeniem, co znacznie zwiększa efektywność procesów inżynierskich. Oprogramowanie takie jak LogiSim czy GEDA umożliwia tworzenie, analizowanie i testowanie układów logicznych bez potrzeby budowania fizycznych prototypów, co jest niezwykle przydatne w nauce i inżynierii.

Zrozumienie podstawowych zasad działania układów cyfrowych nie tylko pozwala na lepsze projektowanie i optymalizację urządzeń elektronicznych, ale także stwarza fundament pod dalsze zgłębianie bardziej zaawansowanych tematów, takich jak architektura procesorów czy projektowanie mikroprocesorów i układów FPGA.