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> ) ) }