Zadanie 3: Kalkulator¶
Data ogłoszenia: 01.12.2020
Termin oddania: 12.01.2021
Archiwum z plikami: z3_calc.tar.gz
, zawiera:
calc_template.py
: szablon rozwiązaniacalc_sw.py
: wzorcowa implementacja w Pythoniecalc_gentest.py
: generator testów (używany przez oba testy)calc_test_sim.py
: testuje rozwiązanie w symulacjicalc_wrapper.py
: syntezuje rozwiązanie na Zynq (uruchamiamy bez argumentów, otrzymujemy bitstream wbuild/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ładniowonapis
ERR DIVIDE
, jeśli nastąpiło dzielenie przez zeronapis
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
.