Sprawozdanie - Marcin Krzych

Transkrypt

Sprawozdanie - Marcin Krzych
Języki Formalne i Kompilatory
Sprawozdanie z wykonania projektu
Kierunek
Informatyka Stosowana, rok III
Autor
Marcin Krzych
Data
20.06.2008
Temat projektu
Symulator mikrokontrolera 8051. Technologia wykonania: Java, platforma:
Mac OS X. Interpretacja programów napisanych w assemblerze na
mikrokontroler 8051.
1 Cel programu
Symulator mikrokontrolera 8051 ma za zadanie interpretować wpisane przez użytkownika rozkazy
w asemblerze i przedstawiać ich rezultat wykonania poprzez możliwość obejrzenia zawartości jego
pamięci.
2 Gramatyka
Pełny zapis gramatyki użytej do wygenerowania skanera i parsera znajduje się na końcu
dokumentu. Gramatyka zapisana jest w formacie wejściowych dla generatora JavaCC 1.
3 Opis i schemat struktury logicznej programu
3.1 Skaner, Parser
Skaner i parser zostały wygenerowane przy pomocy narzędzia JavaCC na podstawie stworzonego
przeze mnie pliku konfiguracyjnego z opisem gramatyki. Analizowany łańcuch znaków jest czytany
tylko 1 raz. Na jego podstawie parser generuje listę rozkazów, po której porusza się interpreter.
Funkcjonalność skanera i parsera są opisane w klasach pakietu net.krzymar.uc8051:
●
Parser
●
ParseException
●
ParserConstants
●
ParserTokenManager
●
SimpleCharStream
●
Token
●
TokenMgrError
3.2 Interpreter
Interpreter jest modułem, który pisałem sam. Porusza się on po dynamicznej liście stworzonej przez
1 https://javacc.dev.java.net/
parser i interpretuje wpisane do niej rozkazy. Interpretację można przeprowadzić dla całego
programu od razu, bądź też przechodzić przez program krokowo.
Klasą opisującą interpreter jest klasa pakietu net.krzymar.uc8051:
●
uc8051Interpreter
3.3 Mikrokontroler
Mikrokontroler opisany jest poprzez klasy:
●
uc8051 – klasa ta ujmuje mikrokontroler jako całość
●
uc8051DataMemory – dostarcza opis pamięci mikrokontrolera i operacji, które można na
niej wykonać
3.4 GUI
Graficzny interfejs użytkownika został zrealizowany przy pomocy SWING.
4 Informacje o stosowanych
i programach narzędziowych
pakietach
zewnętrznych
Symulator mikrokontrolera 8051 wykonano z wykorzystaniem technologii platformy Mac OS X
10.4:
●
Java
Projekt realizowany był w NetBeans 6.12. Aplikacja oparta jest o Swing Application Framework
ułatwiający tworzenie GUI.
Do wygenerowania skanera i parsera wykorzystano JavaCC.
Projekt uruchomiono z sukcesem na 3 platformach:
●
Mac OS X 10.4
●
Windows XP Proffesional + JRE 1.6
●
Kubuntu Linux + JRE 1.6
5 Informacje
o
zastosowaniu
rozwiązania problemu
specyficznych
metod
Lista rozkazów budowana przez parser dla interpretera składa się z obiektów klasy Instruction.
Każdy obiekt zawiera nazwę instrukcji i listę parametrów z którymi ta instrukcja ma
być wykonana.
6 Krótka instrukcja obsługi
Domyślnie program uruchamia się z oknem do wprowadzenia treści programu w assemblerze,
który ma zostać potem zinterpretowany. Można dokonać zapisu takiego programu, a potem w
przyszłości jego odczytu - funkcjonalność taka dostępna jest z poziomu menu programu „Plik” lub
z przycisków paska narzędziowego.
Po napisaniu treści programu przystępujemy do jego interpretacji. Możemy dokonać tego na 2
sposoby:
2 http://www.netbeans.org/
●
naciśnięcie przycisku Symuluj dokonujemy parsowania całego programu i jego całościowej
interpretacji.
●
najpierw wciskamy przycisk Parsuj, a potem przechodzimy przez program interpretując go
instrukcja po instrukcji przyciskiem Krok w przód
Warto zapoznać się z przypisanymi do menu skrótami klawiszowymi, ktore znacząco
przyśpieszają i ułatwiają pracę. Skróty są podane obok pozycji w menu programu
7 Zestaw przykładowych wyników końcowych
7.1 Poprawna symulacja programu
7.2 Prezentacja wyników działania programu
7.3 Błąd parsowania
8 Możliwe rozszerzenia programu
Funkcjonalnością, którą planowałem, a której na skutek ograniczeń czasowych nie zdążyłem
wykonać jest wizualizacja stanów na portach mikrokontrolera. Dzięki temu oprócz możliwości
sprawdzenia zawartości pamięci – możliwy byłby również podgląd portów, poprzez które
mikrokontroler komunikuje się z urządzeniami zewnętrznymi, takimi jak dodatkowa pamięć,
przetworniki AC/CA, sterowniki silników, itp.
Innym ciekawym pomysłem jest utworzenie rozbudowanego mechanizmu pomocy dla programu,
gdzie można by zawrzeć krótki kurs obsługi programu, opis jego funkcjonalności,
specyfikację mikrokontrolera, kurs z przykładami assemblera na ten mikrokontroler, itp.
9 Ograniczenia programu
Brak implementacji interpretaci wszystkich rozkazów mikrokontrolera. Z powodu ograniczonej
ilości czasu na projekt dokonałem selekcji i interpretowane są tylko najważniejsze rozkazy. Klasa
intepretera przygotowana jest na poprawienie tej funkcjonalności.
10 Inne informacje
Przy realizacji podobnego projektu warto zastanowić się nad wybraniem narzędzia ANTLR
zamiast JavaCC. ANTLR jest narzędziem o znacznie większych możliwościach.
11 Dodatki
11.1 Opis gramatyki w formacie JavaCC
Poniższy kod został uproszczony o fragmenty mówiące generatorowi, aby przy parsingu kodu
budował listę instrukcji dla interpretera.
/* token list */
SKIP : { " " }
SKIP : { "\n" | "\r" | "\r\n" }
TOKEN : { < PLUS_T : "+" > }
TOKEN : { < RX_T : "R"["0"-"7"] > }
TOKEN : { < A_T : "A" > }
TOKEN : { < B_T : "B" > }
TOKEN : { < AT_T : "@" > }
TOKEN : { < DPTR_T : "DPTR" > }
TOKEN : { < PC_T : "PC" > }
TOKEN : { < HEX_T : "#"(["0"-"9","a"-"f","A"-"F"])+ > }
TOKEN : { < NUMBER : (["0"-"9"])+ | "-"(["0"-"9"])+ > }
TOKEN : { < ADD_T : "ADD" > }
TOKEN : { < ADDC_T : "ADDC" > }
TOKEN : { < SUBB_T : "SUBB" > }
TOKEN : { < INC_T : "INC" > }
TOKEN : { < DEC_T : "DEC" > }
TOKEN : { < MUL_T : "MUL" > }
TOKEN : { < DIV_T : "DIV" > }
TOKEN : { < DA_T : "DA" > }
TOKEN : { < ACALL_T : "ACALL" > }
TOKEN : { < LCALL_T : "LCALL" > }
TOKEN : { < RET_T : "RET" > }
TOKEN : { < RETI_T : "RETI" > }
TOKEN : { < AJMP_T : "AJMP" > }
TOKEN : { < LJMP_T : "LJMP" > }
TOKEN : { < SJMP_T : "SJMP" > }
TOKEN : { < JC_T : "JC" > }
TOKEN : { < JNC_T : "JNC" > }
TOKEN : { < JB_T : "JB" > }
TOKEN : { < JBC_T : "JBC" > }
TOKEN : { < JMP_T : "JMP" > }
TOKEN : { < JZ_T : "JZ" > }
TOKEN : { < JNZ_T : "JNZ" > }
TOKEN : { < CJNE_T : "CJNE" > }
TOKEN : { < DJNZ_T : "DJNZ" > }
TOKEN : { < NOP_T : "NOP" > }
TOKEN : { < MOV_T : "MOV" > }
TOKEN : { < MOVC_T : "MOVC" > }
TOKEN : { < MOVX_T : "MOVX" > }
TOKEN : { < PUSH_T : "PUSH" > }
TOKEN : { < POP_T : "POP" > }
TOKEN : { < XCH_T : "XCH" > }
TOKEN : { < XCHD_T : "XCHD" > }
TOKEN : { < ANL_T : "ANL" > }
TOKEN : { < ORL_T : "ORL" > }
TOKEN : { < XORL_T : "XORL" > }
TOKEN : { < CLR_T : "CLR" > }
TOKEN : { < CPL_T : "CPL" > }
TOKEN : { < SWAP_T : "SWAP" > }
TOKEN : { < RL_T : "RL" > }
TOKEN
TOKEN
TOKEN
TOKEN
TOKEN
TOKEN
TOKEN
TOKEN
:
:
:
:
:
:
:
:
{
{
{
{
{
{
{
{
<
<
<
<
<
<
<
<
RLC_T : "RLC" > }
RR_T : "RR" > }
RRC_T : "RRC" > }
SETB_T : "SETB" > }
COLON_T : ":" > }
SEMICOLON_T : ";" > }
COMMA_T : "," > }
IDENTIFIER_T : (["a"-"z","A"-"Z"])+(["a"-"z","A"-"Z","0"-"9"])+ > }
/* productions */
void Start( uc8051Interpreter ucI ) :
{}
{
(
Instruction( ucI )
)*
<EOF>
}
void Instruction( uc8051Interpreter ucI ) :
{}
{
(
<IDENTIFIER_T><COLON_T>
|
addInstructions( ucI )
|
substractInstructions( ucI )
|
incrementInstructions( ucI )
|
decrementInstructions( ucI )
|
<MUL_T> <A_T><B_T>
|
<DIV_T> <A_T><B_T>
|
<DA_T> <A_T>
|
<ACALL_T> <IDENTIFIER_T>
|
<LCALL_T> <IDENTIFIER_T>
|
<RET_T>
|
<RETI_T>
|
<AJMP_T> <IDENTIFIER_T>
|
<LJMP_T> <IDENTIFIER_T>
|
<SJMP_T> <IDENTIFIER_T>
|
<JC_T> <IDENTIFIER_T>
|
<JNC_T> <IDENTIFIER_T>
|
<JB_T> <HEX_T><COMMA_T>t2=<IDENTIFIER_T>
|
<JBC_T> <HEX_T><COMMA_T>t2=<IDENTIFIER_T>
|
<JMP_T> <AT_T><A_T><PLUS_T><DPTR_T>
|
<JZ_T> <IDENTIFIER_T>
|
<JNZ_T> <IDENTIFIER_T>
|
cjneInstructionGroup( ucI )
|
<DJNZ_T> <RX_T><COMMA_T>t2=<NUMBER>
|
<NOP_T>
|
moveInstructions( ucI )
|
<PUSH_T> <RX_T>
|
<POP_T> <RX_T>
|
<XCH_T> <A_T><COMMA_T>
(
<RX_T>
|
<AT_T><RX_T>
)
|
<XCHD_T> <A_T><COMMA_T><AT_T><RX_T>
|
logicalOperations( ucI )
|
<CPL_T> <A_T>
)
}
void addInstructions( uc8051Interpreter ucI ) :
{}
{
<ADD_T> <A_T><COMMA_T>
(
<RX_T>
|
<AT_T><RX_T>
|
<HEX_T>
)
|
<ADDC_T> <A_T><COMMA_T>
(
<RX_T>
|
<AT_T><RX_T>
|
<HEX_T>
)
}
void substractInstructions( uc8051Interpreter ucI ) :
{}
{
<SUBB_T> <A_T><COMMA_T>
(
<RX_T>
|
<AT_T><RX_T>
|
<HEX_T>
)
}
void incrementInstructions( uc8051Interpreter ucI ) :
{}
{
<INC_T>
(
<A_T>
|
<RX_T>
|
<AT_T><RX_T>
|
<DPTR_T>
)
}
void decrementInstructions( uc8051Interpreter ucI ) :
{}
{
<DEC_T>
(
<A_T>
|
<RX_T>
|
<AT_T><RX_T>
)
}
void cjneInstructionGroup( uc8051Interpreter ucI ) :
{}
{
<CJNE_T>
(
RX_T><COMMA_T><HEX_T><COMMA_T><IDENTIFIER_T>
|
<A_T><COMMA_T>
(
<RX_T><COMMA_T><IDENTIFIER_T>
|
<HEX_T><COMMA_T><IDENTIFIER_T>
)
|
<AT_T><RX_T><COMMA_T><HEX_T><COMMA_T><IDENTIFIER_T>
)
}
void moveInstructions( uc8051Interpreter ucI ) :
{}
{
<MOV_T>
(
<RX_T>
(
<COMMA_T>
(
<A_T>
|
<RX_T>
|
<HEX_T>
|
<AT_T><RX_T>
)
|
<A_T>
(
<COMMA_T>
(
<RX_T>
|
<AT_T><RX_T>
|
<HEX_T>
)
)
|
<DPTR_T><COMMA_T><HEX_T>
|
<AT_T>
(
<RX_T><COMMA_T><A_T>
|
<DPTR_T><COMMA_T><A_T>
)
)
|
<MOVC_T> <A_T><COMMA_T><AT_T>
(
<A_T>
(
<PLUS_T>
(
<DPTR_T>
|
<PC_T>
)
)
|
<RX_T>
|
<DPTR_T>
)
}
void logicalOperations( uc8051Interpreter ucI ) :
{
Token t,t2;
}
{
<ANL_T>
(
<A_T><COMMA_T>
(
<RX_T>
)
|<RX_T>
(
<COMMA_T>
(
<A_T>
|
<HEX_T>
)
)
)
|
<ORL_T>
(
<A_T><COMMA_T><RX_T>
|
<RX_T><COMMA_T>
(
<A_T>
|
<HEX_T>
)
)
}

Podobne dokumenty