.. _z3-calc: ===================== Zadanie 3: Kalkulator ===================== Data ogłoszenia: 01.12.2020 Termin oddania: 12.01.2021 Archiwum z plikami: :download:`z3_calc.tar.gz`, zawiera: - ``calc_template.py``: szablon rozwiązania - ``calc_sw.py``: wzorcowa implementacja w Pythonie - ``calc_gentest.py``: generator testów (używany przez oba testy) - ``calc_test_sim.py``: testuje rozwiązanie w symulacji - ``calc_wrapper.py``: syntezuje rozwiązanie na Zynq (uruchamiamy bez argumentów, otrzymujemy bitstream w ``build/top.bin``) - ``calc_run_hw.py``: uruchamia zsyntezowane rozwiązanie na serwerze, pozwalając na interakcję z portem szeregowym (podajemy ścieżkę do pliku ``.bin`` jako argument) - ``calc_test_hw.py``: testuje zsyntezowane rozwiązanie na serwerze (podajemy ścieżkę do pliku ``.bin`` jako argument) Napisać układ implementujący kalkulator z interfejsem przez port szeregowy. Jedynym interfejsem układu jest port szeregowy używający wyłącznie sygnałów ``rxd`` i ``txd``. Układ powinien odbierać wyrażenia do obliczenia na sygnale ``rxd`` i wypisywać wyniki (lub oznaczenia błędów) na sygnale ``txd``. Wejściem do układu są wyrażenia arytmetyczne, zapisane w formacie ASCII. Każde wyrażenie jest zakończone znakiem nowej linii (``0x0a``). Kalkulator powinien na każdą linię wejścia (niezależnie od tego, czy jest to poprawne wyrażenie czy błąd) odpowiedzieć jedną linią wyjścia. Wyrażenia mogą zawierać następujące tokeny: - liczby, zapisane dziesiętnie - binarne operatory dodawania (``+``), odejmowania (``-``), mnożenia (``*``), dzielenia (``/``), liczenia reszty z dzielenia (``%``) - unarny operator negacji (``-``) - nawiasy (``(``, ``)``) Tokeny mogą (ale nie muszą) być oddzielone od siebie białymi znakami (spacjami i/lub znakami tabulacji). Kalkulator powinien poprawnie implementować kolejność wykonywania działań. Wszystkie wyniki pośrednie powinny być przechowywane jako liczby 32-bitowe bez znaku, a ewentualne przepełnienia zawijane modulo ``2**32``. Kalkulator nie musi obsługiwać arbitralnie długich wyrażeń — wymagane jest jedynie, by działał poprawnie na wejściu długości max. 1023 znaków. Dłuższe wyrażenia mogą (ale nie muszą) być odrzucane. Implementacja logiki kalkulatora napisana w języku Python jest dostępna wyżej. Można ją wykorzystać jako bazę do swojego rozwiązania. Jako odpowiedź na linię wejścia kalkulator powinien wypisać jedną z następujących rzeczy i znak nowej linii (``0x0a``): - wynik obliczenia (liczbę zapisaną dziesiętnie, bez wiodących zer) - napis ``ERR LEX``, jeśli nie udało mu się podzielić linii wejścia na tokeny (nierozpoznany znak itp) - napis ``ERR PARSE``, jeśli wyrażenie było niepoprawne składniowo - napis ``ERR DIVIDE``, jeśli nastąpiło dzielenie przez zero - napis ``ERR OVERFLOW``, jeśli wyrażenie jest zbyt duże bądź zbyt skomplikowane dla kalkulatora (nie powinno wystąpić przy wyrażeniach o długości ≤1023 znaków) - napis ``ERR SERIAL``, jeśli wystąpił błąd odbierania danych z portu szeregowego (framing, overflow, itp) Nie trzeba pisać własnej obsługi portu szeregowego — można wykorzystać tą z laboratorium bądź z biblioteki ``nmigen-stdio``.