345 lines
22 KiB
TeX
345 lines
22 KiB
TeX
%
|
||
% !TEX TS-program = xelatex
|
||
% !TEX encoding = UTF-8 Unicode
|
||
% !TEX spellcheck = el-GR
|
||
%
|
||
% Low-Level HW Digital Systems II coursework report
|
||
%
|
||
%
|
||
% authors:
|
||
% Χρήστος Χουτουρίδης ΑΕΜ 8997
|
||
% cchoutou@ece.auth.gr
|
||
|
||
|
||
% Options:
|
||
%
|
||
% 1) mainlang=<language>
|
||
% Default: english
|
||
% Set the default language of the document which affects hyphenations,
|
||
% localization (section, dates, etc...)
|
||
%
|
||
% example: \documentclass[mainlang=greek]{AUThReport}
|
||
%
|
||
% 2) <language>
|
||
% Add hyphenation and typesetting support for other languages
|
||
% Currently supports: english, greek, german, frenc
|
||
%
|
||
% example: \documentclass[english, greek]{AUThReport}
|
||
%
|
||
% 3) short: Requests a shorter title for the document
|
||
% Default: no short
|
||
%
|
||
% example: \documentclass[short]{AUThReport}
|
||
%
|
||
\documentclass[a4paper, 11pt, mainlang=greek, english]{AUThReport}
|
||
|
||
\CurrentDate{\today}
|
||
|
||
% Greek report document setup suggestions
|
||
%---------------------------------
|
||
% Document configuration
|
||
\AuthorName{Χρήστος Χουτουρίδης}
|
||
\AuthorAEM{8997}
|
||
\AuthorMail{cchoutou@ece.auth.gr}
|
||
|
||
%\CoAuthorName{CoAuthor Name}
|
||
%\CoAuthorAEM{AEM}
|
||
%\CoAuthorMail{CoAuthor Mail}
|
||
|
||
% \WorkGroup{Ομάδα Χ}
|
||
|
||
\DocTitle{Εργασία}
|
||
\DocSubTitle{Πολλαπλασιασμός αριθμών κινητής υποδιαστολής}
|
||
|
||
\Department{Τμήμα ΗΜΜΥ. Τομέας Ηλεκτρονικής}
|
||
\ClassName{Ψηφιακά Συστήματα HW σε Χαμηλά Επίπεδα Λογικής II}
|
||
|
||
\InstructorName{Βασίλης Παυλίδης}
|
||
\InstructorMail{ }
|
||
|
||
\CoInstructorName{Ευάγγελος Τζουβάρας}
|
||
\CoInstructorMail{ }
|
||
|
||
|
||
% Local package requirements
|
||
%---------------------------------
|
||
%\usepackage{tabularx}
|
||
%\usepackage{array}
|
||
%\usepackage{commath}
|
||
|
||
\usepackage{amsmath, amssymb, amsfonts}
|
||
\usepackage{graphicx}
|
||
\usepackage{subcaption}
|
||
\usepackage{float}
|
||
|
||
|
||
% Requires: -shell-escape compile argument
|
||
\usepackage{minted}
|
||
\usepackage{xcolor}
|
||
|
||
\newminted{verilog}{
|
||
fontsize=\small,
|
||
breaklines,
|
||
autogobble,
|
||
%frame=lines,
|
||
%framesep=5pt,
|
||
baselinestretch=1.1,
|
||
tabsize=2,
|
||
%bgcolor=LightGray,
|
||
numbersep=8pt,
|
||
gobble=0
|
||
}
|
||
|
||
\newcommand{\icode}[1]{\mintinline{verilog}{#1}}
|
||
|
||
|
||
\newcommand{\repo}{https://git.hoo2.net/hoo2/HWDigSys-II}
|
||
\newcommand{\repoNopipeline}{https://git.hoo2.net/hoo2/HWDigSys-II/src/branch/no-pipeline}
|
||
\begin{document}
|
||
|
||
% Request a title page or header
|
||
\InsertTitle
|
||
|
||
\section{Εισαγωγή}
|
||
|
||
Η παρούσα εργασία αφορά στην υλοποίηση ενός πολλαπλασιαστή αριθμών κινητής υποδιαστολής μονής ακρίβειας (IEEE-754 single-precision) σε γλώσσα περιγραφής υλικού SystemVerilog.
|
||
Η σχεδίαση του κυκλώματος ακολουθεί μια αρθρωτή και κλιμακούμενη προσέγγιση, βασισμένη σε δομή pipeline τριών σταδίων.
|
||
Το κύριο ζητούμενο ήταν η διαχωρισμένη υλοποίηση της κανονικοποίησης, της στρογγυλοποίησης και της διαχείρισης εξαιρέσεων, με δυνατότητα ελέγχου διαφορετικών τρόπων στρογγυλοποίησης.
|
||
\par
|
||
Στόχος της εργασίας είναι η κατανόηση της εσωτερικής λειτουργίας των αριθμητικών μονάδων κινητής υποδιαστολής, η υλοποίηση τους σε επίπεδο RTL και η επαλήθευση της σωστής λειτουργίας τους μέσω εκτενούς ελέγχου με test benches.
|
||
Η εργασία απαιτεί κατανόηση τόσο της γλώσσας SystemVerilog όσο και του προτύπου IEEE-754, και συνδυάζει αρχιτεκτονική σχεδίαση, ψηφιακή λογική και επαλήθευση μέσω προσομοίωσης.
|
||
|
||
\subsection{Παραδοτέα}
|
||
Τα παραδοτέα της εργασίας αποτελούνται από:
|
||
\begin{itemize}
|
||
\item Την παρούσα αναφορά.
|
||
\item Τον κατάλογο \textbf{src/}, που περιέχει τον κώδικα της SystemVerilog με τα ζητηθέντα modules.
|
||
\item Τον κατάλογο \textbf{sim/}, που περιέχει το ζητηθέν test bench αλλά και επιμέρους tests για τα υπόλοιπα modules (πλην του exception handler).
|
||
\item Το \href{\repo}{σύνδεσμο} με το αποθετήριο που περιέχει όλο το project στο vsim, τους κώδικες της SystemVerilog και της αναφοράς καθώς και τα παραδοτέα.
|
||
\end{itemize}
|
||
Στην εργασία \textbf{δεν} υλοποιήθηκαν τα εξής:
|
||
\begin{itemize}
|
||
\item \textit{Όλοι οι 144} συνδυασμοί των corner cases για το test bench με βάση τους τυχαίους αριθμούς και τον έλεγχο μέσω multiplication.sv.
|
||
Αντ' αυτού δημιουργήθηκαν test cases που ελέγχουν τόσο την “κανονική” λειτουργία όσο και αρκετά corner cases αλλά οι τιμές τους εισήχθηκαν \textit{με το χέρι}.
|
||
\item Το μέρος με τα \textit{immediate assertions}.
|
||
\end{itemize}
|
||
|
||
\section{Προσέγγιση Υλοποίησης}
|
||
Για την εργασία χρησιμοποιήσαμε μια \textbf{αρθρωτή} προσέγγιση.
|
||
Καθώς η πολυπλοκότητα έμοιαζε αρκετά μεγάλη, σε συνδυασμό με τη μικρή προσωπική εμπειρία σε ψηφιακή σχεδίαση με verilog, προτιμήσαμε να ακολουθήσουμε μια \textbf{test driven} προσέγγιση ανά module.
|
||
Έτσι χωρίσαμε την ανάπτυξη στα modules που πρότεινε η εκφώνηση και για αυτά δημιουργήσαμε test benches.
|
||
Τα βασικά tests που θα χρειαζόταν να υλοποιηθούν πρώτα ήταν για τα \textit{normalize} και \textit{round}.
|
||
Το \textit{exception handler} θα μπορούσε να εκμαιευτεί με “αφαίρεση” των παραπάνω από το συνολικό test bench του \textit{fp\_mult}.
|
||
Όλα αυτά τα αρχεία μπορούν να βρεθούν στον κατάλογο \textit{sim/}.
|
||
\par
|
||
Τα test αυτά αν και κάπως τετριμμένα, έπαιξαν πολύ σημαντικό ρόλο στην υλοποίηση καθώς μας δώσανε τη δυνατότητα να χωριστούν τα interfaces των modules και να πιστοποιήσουν ότι η αναγκαία λειτουργικότητα είναι παρούσα.
|
||
Κάτι που φυσικά μας βοήθησε στην απομόνωση των σφαλμάτων κλπ...
|
||
\par
|
||
Έχοντας υλοποιήσει λοιπόν τα test προβήκαμε στην υλοποίηση των ίδιων των modules.
|
||
Αρχικά υλοποιήσαμε τα \textit{normalize} και \textit{round} και έπειτα το \textit{fp\_mult}.
|
||
Με αυτά τα τρία να περνούν τα επιμέρους tests προχωρήσαμε στην υλοποίηση του \textit{exception handler}.
|
||
Για αυτό το module δεν υλοποιήσαμε πρώτα tests καθώς υπήρχαν τα συνολικά tests και το μόνο modul-άκι που “άλλαζε” ήταν αυτό.
|
||
\par
|
||
Τέλος με όλη τη λειτουργικότητα έτοιμη, προβήκαμε στην τελευταία αλλαγή, που ήταν η μετατροπή της λογικής για χρήση \textbf{pipeline τριών σταδίων}.
|
||
Μιας και τα αρχεία για τα tests για το pipeline είναι διαφορετικά από τα αρχικά, ο αναγνώστης μπορεί \href{\repoNopipeline}{εδώ} να βρει αυτή την ενδιάμεση έκδοση.
|
||
|
||
\subsection{Pipeline}
|
||
|
||
Η αρχική υλοποίηση όπως είδαμε είχε combinational logic.
|
||
Επομένως το αποτέλεσμα του πολλαπλασιασμού θα ήταν διαθέσιμο σε κάθε clock του ρολογιού του \textit{fp\_mult\_top}.
|
||
Παρόλα αυτά ο διαχωρισμός σε 3 στάδια μειώνει αρκετά το βάθος, χωρίς να μεγαλώνει την ανάγκη για extra clock ticks.
|
||
Αντ' αυτού μειώνει το συνολικό latency.
|
||
Τα στάδια που χρησιμοποιήθηκαν είναι με τη σειρά τα εξής:
|
||
\begin{enumerate}
|
||
\item \textbf{Normalize}: Όπου καλείται το normalize\_mult.
|
||
\item \textbf{Round}: Όπου καλείται το round\_mult και το
|
||
\item \textbf{Exception handler}: Όπου καλείται το exception\_mult
|
||
\end{enumerate}
|
||
\par
|
||
Για το pipeline εργαστήκαμε με γνώμονα τη διατήρηση όλης της απαραίτητης πληροφορίας στα στάδια, ούτως ώστε ο χρήστης να μπορεί σε κάθε clock να τροφοδοτεί το module με διαφορετικούς αριθμούς για πολλαπλασιασμό.
|
||
Όλα τα σήματα από την είσοδο τροφοδοτούνται από το ένα στάδιο στο επόμενο.
|
||
Η μετάδοση αυτή σταματάει μόνο αν τα σήματα δεν είναι απαραίτητα για τη λειτουργία του επόμενου module.
|
||
Με αυτό τον τρόπο για παράδειγμα όλη η απαραίτητη πληροφορία για το κάθε module, περνάει από το ένα στάδιο στο επόμενο σε κάθε clock.
|
||
Για την ακρίβεια, μετά τον αρχικό υπολογισμό του πρόσημου καθώς και του αποτελέσματος του πολλαπλασιασμού για τον εκθέτη και τη mantissa:
|
||
\begin{itemize}
|
||
\item Οι \textbf{αριθμοί} προς πολλαπλασιασμό φτάνουνε μέχρι τον exception handler.
|
||
\item Ο \textbf{εκθέτης} και η \textbf{mantissa} φτάνει μέχρι τον exception handler, όπου και συνθέτει τον τελικό αριθμό πριν την είσοδο.
|
||
\item To υπολογισμένο \textbf{πρόσημο} του τελικού αριθμού φτάνει μέχρι το round module.
|
||
\item Τα \textbf{guard} και \textbf{sticky} bits φτάνουν από το normalize μέχρι το round module.
|
||
\item To \textbf{inexact} bit από το round μέχρι το exception handler.
|
||
\end{itemize}
|
||
\par
|
||
Ενώ επιλέξαμε να υποστηρίξουμε με pipeline όλη σχεδόν την πληροφορία, ένα σήμα δεν ακολουθεί την οδό των σταδίων.
|
||
Πρόκειται για το \textbf{round}.
|
||
Ενώ για τα υπόλοιπα θεωρήσαμε πως ο χρήστης πρέπει να μπορεί να τα αλλάζει σε κάθε clock του ρολογιού, αυτό υποθέσαμε ότι θα επιλέγεται κατά την έναρξη και θα \textbf{παραμένει αμετάβλητο κάθ' όλη τη διάρκεια λειτουργίας}.
|
||
Για το λόγο αυτό, δεν χρειάστηκε να το “περάσουμε” από τα στάδια.
|
||
|
||
\section{Λεπτομέρειες Υλοποίησης}
|
||
|
||
\subsection{\texttt{fp\_mult.sv} --- Floating Point Multiplier (Top Module)}
|
||
|
||
Το module \texttt{fp\_mult} υλοποιεί έναν πλήρως καταχωρημένο πολλαπλασιαστή αριθμών κινητής υποδιαστολής μονής ακρίβειας (IEEE-754).
|
||
Αποτελείται από ένα pipeline 3 σταδίων:
|
||
|
||
\begin{itemize}
|
||
\item \textbf{Stage 0 (Decode)}:
|
||
Εξάγει πρόσημο, εκθέτες και mantissas από τις εισόδους \texttt{a}, \texttt{b}.
|
||
Υπολογίζει το αρχικό γινόμενο mantissas και το bias-adjusted εκθέτη.
|
||
Η λειτουρία αυτή βρίσκεται σε ένα section με combinational logic.
|
||
\begin{verilogcode}
|
||
sign = a[31] ^ b[31];
|
||
exp_a = a[30:23];
|
||
exp_b = b[30:23];
|
||
s0_exponent = exp_a + exp_b - 127;
|
||
|
||
mant_a = (exp_a == 0) ? {1'b0, a[22:0]} : {1'b1, a[22:0]};
|
||
mant_b = (exp_b == 0) ? {1'b0, b[22:0]} : {1'b1, b[22:0]};
|
||
s0_mantissa = mant_a * mant_b;
|
||
\end{verilogcode}
|
||
\item \textbf{Stage 1 (Normalize)}:
|
||
Κανονικοποιεί το αποτέλεσμα, προσαρμόζοντας την mantissa και τον εκθέτη.
|
||
Παράγει επίσης guard και sticky bits για στρογγυλοποίηση.
|
||
\item \textbf{Stage 2 (Round)}:
|
||
Εφαρμόζει τον επιλεγμένο τρόπο στρογγυλοποίησης και υπολογίζει την τελική mantissa και εκθέτη καθώς και το σήμα inexact.
|
||
\item \textbf{Stage 3 (Exception Handling)}:
|
||
Εντοπίζει καταστάσεις όπως NaN, infinities, overflow/underflow, μηδενικά και υπολογίζει την τελική έξοδο \texttt{z} και το flag \texttt{status}.
|
||
\end{itemize}
|
||
|
||
Υποστηρίζει ασύγχρονη επαναφορά (\texttt{rst}) και συγχρονισμό μέσω ρολογιού (\texttt{clk}).
|
||
|
||
\subsection{\texttt{normalize\_mult.sv} --- Normalize Stage}
|
||
|
||
Το module αυτό δέχεται ένα 48-bit mantissa και έναν 10-bit εκθέτη. Ελέγχει εάν χρειάζεται shift για κανονικοποίηση της mantissa (ώστε να ξεκινά από MSB=1) και αντίστοιχα προσαρμόζει τον εκθέτη.
|
||
|
||
\begin{itemize}
|
||
\item \texttt{mantissa\_out}: Κανονικοποιημένη mantissa (23 bits)
|
||
\item \texttt{guard\_bit, sticky\_bit}: Χρήσιμα για την ακρίβεια στη στρογγυλοποίηση
|
||
\item \texttt{exponent\_out}: Νέος εκθέτης μετά την κανονικοποίηση
|
||
\end{itemize}
|
||
|
||
\subsection{\texttt{round\_mult.sv} --- Round Stage}
|
||
|
||
Το module εφαρμόζει έναν από τους υποστηριζόμενους τρόπους στρογγυλοποίησης σύμφωνα με το IEEE-754 standard:
|
||
|
||
\begin{itemize}
|
||
\item Round to Nearest Even
|
||
\item Round Toward Zero
|
||
\item Round Toward $\inf$
|
||
\item Round Toward $-\inf$
|
||
\item Near-Up
|
||
\item Away from Zero
|
||
\end{itemize}
|
||
|
||
Για κάθε διαφορετικό mode με βάση το round υλοποιεί διαφορετική προσέγγιση.
|
||
Για παράδειγμα για IEEE nearest\ event έχουμε:
|
||
\begin{verilogcode}
|
||
if (guard_bit && (sticky_bit || mantissa_extended[0])) begin
|
||
mantissa_rounded = mantissa_extended + 1;
|
||
end
|
||
\end{verilogcode}
|
||
Ενώ για IEEE pinf:
|
||
\begin{verilogcode}
|
||
if (!sign_in && (guard_bit | sticky_bit)) begin
|
||
mantissa_rounded = mantissa_extended + 1;
|
||
end
|
||
\end{verilogcode}
|
||
Η υλοποίηση των modes έγινε με διαφορετικές συναρτήσεις, μέσα στο module.
|
||
Οι είσοδοι περιλαμβάνουν την mantissa, τον εκθέτη, το πρόσημο και τα bits \texttt{guard} και \texttt{sticky}.
|
||
Οι έξοδοι είναι η νέα mantissa και ο εκθέτης μετά τη στρογγυλοποίηση, καθώς και το σήμα \texttt{inexact}.
|
||
|
||
\subsection{\texttt{round\_modes.sv} --- Round Mode Helpers}
|
||
|
||
Ορίζει ένα enumeration τύπο \texttt{round\_mode\_t} για τους 6 υποστηριζόμενους τρόπους στρογγυλοποίησης, που χρησιμοποιούνται κυρίως κατά τον χειρισμό overflow και underflow στην εξαίρεση.
|
||
\begin{verilogcode}
|
||
typedef enum logic [2:0] {
|
||
RND_IEEE_NEAREST_EVEN = 3'd0,
|
||
RND_IEEE_ZERO = 3'd1,
|
||
RND_IEEE_PINF = 3'd2,
|
||
RND_IEEE_NINF = 3'd3,
|
||
RND_NEAR_UP = 3'd4,
|
||
RND_AWAY_ZERO = 3'd5
|
||
} round_mode_t;
|
||
\end{verilogcode}
|
||
|
||
\subsection{\texttt{exception\_mult.sv} --- Exception Handling}
|
||
|
||
Αυτό το module χειρίζεται corner cases και ειδικές τιμές:
|
||
|
||
\begin{itemize}
|
||
\item Ανίχνευση και χειρισμός NaNs, infinities, zero
|
||
\item Overflow/underflow μετά τη στρογγυλοποίηση
|
||
\item Ορισμός της τελικής τιμής \texttt{z}
|
||
\item Ορισμός των status flags: \texttt{zero\_f}, \texttt{inf\_f}, \texttt{nan\_f}, \texttt{tiny\_f}, \texttt{huge\_f}, \texttt{inexact\_f}
|
||
\end{itemize}
|
||
|
||
Χρησιμοποιεί ένα \texttt{enum interp\_t} για την κατηγοριοποίηση αριθμών (ZERO, INF, NORM, MIN\_NORM, MAX\_NORM) και δύο συναρτήσεις:
|
||
\begin{itemize}
|
||
\item \texttt{num\_interp()}: Επιστρέφει το είδος του αριθμού (π.χ., αν είναι infinity ή zero)
|
||
\item \texttt{z\_num()}: Επιστρέφει την bitwise αναπαράσταση ενός αριθμού βάσει του είδους του
|
||
\end{itemize}
|
||
|
||
Η λογική ελέγχει τους συνδυασμούς εισόδων και εφαρμόζει τις κατάλληλες ενέργειες βάσει πίνακα (table 4) και του rounding mode.
|
||
Ο βασικός κορμός είναι μια switch case όπου γίνεται το dispatch όλων των corner cases:
|
||
\begin{verilogcode}
|
||
a_class = num_interp(a);
|
||
b_class = num_interp(b);
|
||
|
||
case ({a_class, b_class})
|
||
{ZERO, ZERO}, {ZERO, NORM}, {NORM, ZERO}: // ...
|
||
{ZERO, INF}, {INF, ZERO}: // ...
|
||
{INF, INF}, {NORM, INF}, {INF, NORM}: // ...
|
||
default: // {NORM, NORM} ...
|
||
endcase
|
||
\end{verilogcode}
|
||
Ειδικά στο default βρίσκεται η λογική του extra rounding όταν έχουμε NaN, Inf, κλπ.
|
||
|
||
\section{Επαλήθευση και Επικύρωση}
|
||
Όπως αναφέραμε παραπάνω οι επαλήθευση έγινε σταδιακά.
|
||
Σε κάθε αρχείο στον κατάλογο \textit{sim/} υπάρχουν tests που επιβεβαιώνουν την ορθή λειτουργία του κάθε module.
|
||
Για να τρέξουμε τα test χρησιμοποιήσαμε το vsim.
|
||
Για παράδειγμα για τα test του round\_mult:
|
||
\begin{verbatim}
|
||
vlog sim/round_mult_tb
|
||
vsim -voptargs=+acc work.round_tb
|
||
run 400ns
|
||
\end{verbatim}
|
||
Όλες οι εκτελέσεις εμφανίζουν μηνύματα στην κονσόλα με τα αποτελέσματα.
|
||
\par
|
||
Τα τελικά tests που ανήκουν στο fp\_mult\_top\_tb έχουν ελέγχους που ακολουθούν κάποια test vectors όπως παρακάτω:
|
||
\begin{verilogcode}
|
||
initial begin
|
||
$display("Starting fp_mult test...\n");
|
||
|
||
// Test cases
|
||
tests[0] = '{32'h3f800000, 32'h40000000, 32'h40000000, "+1.0 * +2.0 = +2.0"};
|
||
tests[1] = '{32'h40400000, 32'h40400000, 32'h41100000, "+3.0 * +3.0 = +9.0"};
|
||
tests[2] = '{32'hc0400000, 32'h40400000, 32'hc1100000, "-3.0 * +3.0 = -9.0"};
|
||
tests[3] = '{32'hbf800000, 32'h40000000, 32'hc0000000, "-1.0 * +2.0 = -2.0"};
|
||
// ...
|
||
end
|
||
\end{verilogcode}
|
||
Με βάση αυτά τα vectors, παράγονται μηνύματα που έχουν τη μορφή:
|
||
\begin{verbatim}
|
||
# [8] +12.34 * -0.0001 = -0.001234
|
||
# A=414570a4 B=b8d1b717 => Z=baa1be2b (expected baa1be2b) PASS
|
||
\end{verbatim}
|
||
Ένα στιγμιότυπο από την έξοδο φαίνεται στην εικόνα \ref{fig:output}.
|
||
\begin{figure}[!ht]
|
||
\centering
|
||
\includegraphics[width=0.9\textwidth]{img/ConsoleOutput.png}
|
||
\caption{Στιγμιότυπο εξόδου.}
|
||
\label{fig:output}
|
||
\end{figure}
|
||
|
||
|
||
\section{Συμπεράσματα}
|
||
|
||
Μέσα από την παρούσα εργασία υλοποιήθηκε με επιτυχία μια πλήρως καταχωρημένη αριθμητική μονάδα πολλαπλασιασμού αριθμών κινητής υποδιαστολής, σύμφωνα με το πρότυπο IEEE-754.
|
||
Η υλοποίηση με χρήση pipeline τριών σταδίων προσέφερε βελτιωμένη απόδοση και σαφή διαχωρισμό λειτουργιών, καθιστώντας τη σχεδίαση πιο ευέλικτη και επεκτάσιμη.
|
||
Ο διαχωρισμός σε modules με αυστηρά ορισμένα interfaces διευκόλυνε την ανάπτυξη και τον έλεγχο των επιμέρους λειτουργιών, ενώ η προσέγγιση βασισμένη σε επαλήθευση (test-driven development) διασφάλισε την ορθότητα κάθε σταδίου.
|
||
\par
|
||
Αν και δεν καλύφθηκαν όλοι οι δυνατοί συνδυασμοί corner cases, η λογική του κυκλώματος και οι ενδείξεις των αποτελεσμάτων επαληθεύουν ότι η λειτουργία του multiplier είναι σε μεγάλο βαθμό ορθή.
|
||
Η εργασία παρείχε μια ουσιαστική εμπειρία στην πρακτική υλοποίηση σύνθετων αριθμητικών μονάδων σε χαμηλό επίπεδο, αναδεικνύοντας τις προκλήσεις αλλά και τις δυνατότητες της σύγχρονης ψηφιακής σχεδίασης.
|
||
|
||
\end{document}
|