.. _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``.