KONCEPCJA REFAKTORYZACJI KODU W JĘZYKU VHDL Przemysław Sołtan Politechnika Koszalińska, Wydział Elektroniki, ul. Śniadeckich 2, 75-543 Koszalin e-mail: [email protected] Streszczenie W pracy zaproponowano koncepcję realizacji refaktoryzacji kodu programu zapisanego w języku VHDL. Refaktoryzacja, czyli zmiana struktury kodu bez zmiany jego zachowania, jest korzystną i często stosowaną metodą automatycznego tworzenia, modyfikacji i optymalizacji kodów programów obiektowych JAVA, C++, itd. Specyfika języka VHDL wymusza jednak stosowania odmiennych od znanych mechanizmów refaktoryzacji, uwzględniających m.in. typy danych nie występujące w językach programowania obiektowego (np. sygnały, porty, entity, architektury) oraz brak podstawowych struktur danych – klas. Stosowanie refaktoryzacji projektów VHDL pozwala nie tylko na zmiany nazw zmiennych różnych typów, funkcji i procesów, zamianę instrukcji, wyszukiwanie nieużywanego kodu, modyfikacje mapowania portów w komponentach, lecz nawet na podział procesów przy równoległym przetwarzaniu, co w dużym stopniu wpływa na efektywność syntezy logicznej projektu VHDL. Zaproponowana koncepcja jest oparta o abstrakcyjne drzewo składni języka VHDL i jest realizowana w postaci autorskiej biblioteki VDT. Aplikacja VDT opracowana jest w języku JAVA i współpracuje z platformą ECLIPSE. 1. WPROWADZENIE Współczesne środowiska projektowe VHDL wspierają projektantów udostępniając im mechanizmy automatycznej generacji kodu, a część zagadnień związanych z semantyką kodu jest rozpatrywana na etapie jego symulacji. Brak jest jednak drugiego podejścia, jakim jest refaktoryzacja istniejącego już kodu oraz badania jego semantyki podczas procesu edycji. Termin refaktoryzacja definiuje się jako mechanizm zmiany struktury kodu bez zmiany jego zachowania. Przykładem może być zmiana nazwy zmiennej, zamiana części kodu, czy też ekstrakcja fragmentu kodu do nowej zewnętrznej funkcji lub komponentu. Ręczna refaktoryzacja kodu jest procesem czasochłonnym, a tym samym podatnym na występowanie błędów podczas jego realizacji. Z tego względu warto zautomatyzować ten proces poprzez tworzenie niezawodnych i wydajnych narzędzi wspierających projektantów w realizacji tego zadania. Jest to niezbędnym warunkiem, aby refaktoryzacja mogła stać się powszechnie przyjętą techniką tworzenia i pielęgnacji programów. Projekt VHDL (przed refaktoryzacją) PARSER (drzewo AST) Polecenie refaktoryzacji Biblioteka do refaktoryzacji Projekt VHDL (po refaktoryzacji) Aktualizacja widoku Widok Użytkownika Edytor Rys. 1. Proces programowej refaktoryzacji kodu VHDL. W tym celu należy opracować mechanizmy: analizy kodu źródłowego, budowania modelu oraz zintegrowanego z nim edytora umożliwiającego pobieranie poleceń refaktoryzacji od użytkownika systemu. Schemat blokowy takiego systemu został przedstawiony na rys. 1. W niniejszej pracy przedstawiono refaktoryzację w kontekście języka VHDL. Odmienność przekształceń refaktoryzacji języka VHDL względem innych języków polega na braku obiektowych aspektów języka wykorzystywanych przy refaktoryzacji. Mechanizmy obiektowe jako pierwszy opisał w 1992 roku Opdyke [1], brak jest jednak prac dotyczących zagadnień języka VHDL. Zastosowanie języka VHDL jako języka opisu sprzętu wymaga innego podejścia do zagadnienia refaktoryzacji ze względu na różnorodność typów danych oraz występowanie fragmentów kodu równoległego przetwarzania. 2. PRZYKŁAD PROSTEGO PRZEKSZTAŁCENIA REFAKTORYZACJI Elementarnym przykładem zastosowania mechanizmów refaktoryzacji jest zmiana nazwy jednego z elementów w kodzie projektu. W przypadku obiektowych języków programowania takich jak Smalltalk, Java czy też C++ mamy do czynienia z takimi podstawowymi elementami jak zmienne, funkcje oraz klasy. W przypadku języka VHDL dostępnych jest o wiele większa liczba elementarnych typów nazw [2]. Wyszczególnić można takie elementy jak nazwy: zmiennych, sygnałów, portów, entity czy też architektur. Każdy z elementów wymaga wykonania odmiennych działań. entity entityOldName is entityNewName port(in1 : in bit; out1 : out bit); end entityOldName ; architecture architectureName1 of entityOldName is begin -- code end architectureName1; architecture architectureName2 of entityOldName is begin -- code end architectureName2; ------------------------------------------entity entityTestName is port(in1 : in bit; out1 : out bit); end entityTestName; ENTITY ARCHITECTURE ... ARCHITECTURE COMPONENT PORT MAP ... architecture architectureTestName of entityTestName is component entityOldName port(in1 : in bit; out1 : out bit); end component ; begin comp1: entityOldName port map (in1,out1); -- rest of port map component end architectureTestName; Rys. 2. Przykładowy kod VHDL (zmiana nazwy entity). Na rysunku rys. 2. przedstawiono przykładowy kod z uwzględnieniem elementów, które należy zmienić przy zmianie nazwy entity przykładowej jednostki projektowej. Proces zmiany nazwy entity wymusza realizację kilku elementarnych operacji: - wskazanie elementu określającego starą nazwę entity (entityOldName); - określenie nowej nazwy entity (entityNewName); - sprawdzenie, czy nowa nazwa nie koliduje z już istniejącymi nazwami; wyszukanie bloku danego entity (zmiana nazwy); wyszukanie architektur dla danego entity (zmiana nazwy); wyszukanie w blokach architektur komponentów danego entity (zmiana nazwy); wyszukanie wszystkich mapowań komponentów danego entity (zmiana nazwy). Może wydawać się, że do wykonania takiej prostej operacji jak zmiana nazwy entity wystarczy zwykła operacja zamiany łańcuchów tekstu dostępna w środowiskach edycyjnych. Wymaga to jednak od projektanta podejmowania decyzji, czy dany łańcuch tekstowy jest powiązany z danym elementem, którego nazwę zamierzamy zmienić. Ma to szczególne znaczenie, przy deklarowaniu elementów o takich samych nazwach (np. takich samych nazwach portów różnych komponentów). Sytuacja jeszcze bardziej się komplikuje, gdy mamy do czynienia z wieloma plikami należącymi do tego samego projektu. Może to powodować błędy i utratę integralności otrzymanego projektu po dokonaniu modyfikacji. Z tego względu cały proces można zautomatyzować i w ten sposób odciążyć projektanta od podejmowania części decyzji. Wymaga to jednak analizy kodu na poziomie syntaktycznym i tworzenia modelu projektu przy pomocy składniowego drzewa AST. 3. DRZEWO AST Abstrakcyjne drzewo składni AST (ang. Abstract Syntax Tree) służy do syntaktycznej analizy kodu źródłowego napisanego w języku VHDL. AST definiuje węzły reprezentujące istniejące elementy dostępne w specyfikacji VHDL Syntax (IEEE Std 1076-1993). AST E ENTITY (name: entityOldName ) P PORT (name:in1,type:in,type2:bit) P PORT (name:out1,type:out,type2:bit) A ARCHITECTURE (name:architectureName1,entity: entityOldName ) A ARCHITECTURE (name:architectureName2,entity: entityOldName ) E ENTITY (name:entityTestName) P PORT (name:in1,type:in,type2:bit) P PORT (name:out1,type:out,type2:bit) A ARCHITECTURE (name:architectureTestName,entity:entityTestName) C COMPONENT (name: entityOldName ) P PORT (name:in1,type:in,type2:bit) P PORT (name:out1,type:out,type2:bit) entityNewName I INSTANCE (name:comp1, type: entityOldName ) M MAP (from:in1, to:in1) M MAP (from:out1, to:out1) Rys. 3. Drzewo AST dla przykładu zmiany nazwy entity. Kod implementujący drzewo AST zawiera metody umożliwiające poruszanie się po strukturze drzewa w celu przeanalizowania kodu źródłowego. Dodatkowo należy zaimplementować kod umożliwiający: wyszukiwanie, wstawianie, usuwanie, przenoszenie oraz zmianę poszczególnych węzłów drzewa. Przykładowe drzewo AST przedstawiono na rys. 3. Każdy z węzłów przechowuje informacje o określonym typie przechowanych danych oraz węźle rodzica i węzłach podrzędnych. 4. ZŁOŻONA REFAKTORYZACJA KODU VHDL Metody refaktoryzacji kodu nie dotyczą tylko zmiany nazw poszczególnych zmiennych. Można realizować inne przekształcenia np. zamiany kodu instrukcji if na instrukcję case, wyszukiwanie nieużywanego kodu, modyfikacje mapowania portów w komponentach, czy też podział procesów przy równoległym przetwarzaniu. Złożone modyfikacje nie powinny wpływać na funkcjonowanie modelu VHDL, ale mogą mieć wpływ na efektywność kodu w procesie syntezy. Wskazane jest więc opracowanie katalogu wzorców refakoryzacji [3] dla języka VHDL opartych o opis wzorca, motywację, mechanizm i przykłady. Jest to dobry kierunek dalszych badań nad mechanizmami refaktoryzacji kodu w języku VHDL. Realizacja złożonych refaktoryzacji wymusza także implementacje dodatkowych funkcji takich jak: transakcyjność i praca na kopii roboczej modyfikowanych danych. Transakcyjność polegająca na analizie poprawności elementarnych operacji i zatwierdzeniu całości po pomyślnej realizacji każdej z nich. Praca na kopii roboczej daje możliwość wycofania zmian i określania różnic (tzw. delty) dokumentów przed i po refaktoryzacji kodu. EDYTOR Projekt VHDL PLIK1.vhd PLIK2.vhd MODEL BIBLIOTEKI AST STANDARD PLIK3.vhd IEEE Rys. 4. Projekt VHDL jako model. Na rys. 4. przedstawiono schemat struktury projektu rozpatrywanej jako model danych drzewa AST. Pliki projektu są powiązane z modelem wzajemną relacją. Oznacza to, że zmiana zawartości pliku za pomocą edytora wymusza aktualizacje modelu zawierającego drzewo AST. Podobnie zmiana któregoś z węzłów drzewa AST wymusza aktualizacje widoku w edytorze kodu. Dla plików należących do bibliotek relacja jest jednostronna – zbudowane drzewo AST na podstawie danych z biblioteki jest dostępne tylko do odczytu. 5. PLATFORMA ECLIPSE I PROJEKT VDT (VHDL DEVELOPMEN TOOLKIT) Autorski projekt VDT jest aktualnie w stadium eksperymentalnym. Zaprojektowana biblioteka zrealizowana w języku JAVA umożliwia tworzenie drzewa AST na podstawie plików źródłowych projektu VHDL. ECLIPSE PLATFORM VDT PROJECT CORE SCANNER PARSER AST MODEL WORKBENCH PDE UI EDITOR OUTLINE Rys. 5. Architektura eksperymentalnego systemu refaktoryzacji kodu VHDL zintegrowanego z platformą ECLIPSE. Część kodu odpowiedzialna za analizę kodu wygenerowano przy pomocy odpowiedniej gramatyki vhdl.jjt i programu JavaCC (Java Compiler Compiler) [4]. Otrzymany kod został zintegrowany z platformą ECLIPSE [5], wykorzystując jego funkcjonalność. Zaletą tego rozwiązania jest możliwość wykrywania błędów podczas edycji kodu – (skaner kodu działa w tle i w sposób dynamiczny wskazuje niepoprawne elementy składniowe). Na tym etapie następuje przyspieszenie projektowania, co jest nową jakością znaną z narzędzi IDE najnowszej generacji takich jak ECLIPSE. Architekturę eksperymentalnego systemu refaktoryzacji kodu przedstawiono na rys. 5. Wybór darmowej platformy ECLIPSE zaprojektowanej przez firmę IBM przy użyciu języka JAVA umożliwia wieloplatformowość, czyli pracę środowiska projektowego na różnych systemach operacyjnych. Za wyborem platformy przemawia także fakt bogactwa rozwiązań programistycznych wspierających środowisko przy użyciu tzw. wtyczek (ang. plug-in). W ten sposób w jednym pakiecie projektowym możliwe jest integrowanie różnych rozwiązań. Na rys. 6. zaprezentowano widok środowiska projektowego. Zaimplementowano analizę kodu wraz z systemem zgłaszania błędów syntaktycznych. Rys. 6. Edytor kody VHDL oparty o platformę ECLIPSE. Projekt eksperymentalnej biblioteki VDT posiada status otwartego oprogramowania (Open Source) i jest oparta o licencję CPL - http://www.eclipse.org/legal/cpl-v10.html, podobnie jak cała platforma ECLIPSE i jej podprojekty JDT dla JAVY i CDT dla C++ wspierające mechanizmy refaktoryzacji. Projekt VDT dostępny jest pod adresem http://kik.ie.tu.koszalin.pl/mvl/vdt. 6. KIERUNKI ROZWOJU PROJEKTU Rozwój metod refaktoryzacji opartych o model danych w postaci drzewa AST może być wspierany przez dodatkowe mechanizmy. Nieodłącznym elementem refaktoryzacji jest weryfikacja kodu przed i po jej wykonaniu. Oba testy powinny uzyskiwać taki sam wynik. Aby to sprawdzić należy przygotować odpowiednie testy – testBenches. Ten proces można wspomagać stosując autorską bibliotekę testów jednostkowych vhdlUnit [6]. Posiadając kontrolę nad kodem w postaci modelu danych można zaimplementować mechanizm iniekcji (wstrzykiwania) kodu testów. W ten sposób uzyskać częściowo zautomatyzowany mechanizm testowania. Innym ważnym czynnikiem jest możliwość generacji dokumentacji HTML powiązanych odnośnikami (mechanizm wzorowany na JavaDOC ze środowiska Java). Pożądaną właściwością jest stworzenie narzędzia wspierającego refaktoryzację dla języka Verilog i innych języków z jednoczesnym wykorzystaniem VHDL. Uzyskana kombinacja różnych języków w jednym projekcie prowadzi jednak do wzrostu złożoności kodu źródłowego. Do tego dochodzi jeszcze analiza schematów udostępnianych w różnych niestandardowych formatach (bde, sch, edif). Być może wskazane jest opracowanie wspólnego opisu ich odwzorowania w formacie XML wraz z konwerterami ich importu i eksportu (bde2xml, sch2xml, edif2xml). Wyzwaniem jest również zaprojektowanie takich mechanizmów, które ułatwią konwertowanie modeli niesyntezowalnych w ich wersje syntezowalne. Wymagać to może wykorzystania podczas przekształceń refaktoryzacji własnych modeli lub zewnętrznych modeli tzw. IPCore’ów. Zagadnienie refaktoryzacji przez projektantów platformy ECLIPSE [7] zostało potraktowane bardzo poważnie. Z tego względu w jego nowej wersji zaprojektowano specjalistyczną bibliotekę LTK – Eclipse Language Toolkit wspierającą mechanizmy refaktoryzacji dla innych języków programowania. Implementacja tego mechanizmu do języka VHDL jest częścią dalszych badań prowadzonych przez autora niniejszej publikacji. 7. PODSUMOWANIE Refaktoryzacja jako nowa dziedzina w analizie i przetwarzaniu kodu źródłowego ma kluczowe znaczenie, ponieważ ułatwia zarządzanie coraz bardziej złożonym kodem tworzonych projektów. Dodatkowo, mechanizmy stosowane w środowisku ECLIPSE umożliwiają wykrywanie błędów syntaktycznych na poziomie edycji kodu, a nie w fazie kompilacji realizowanej podczas symulacji, czy syntezy. W pracy zaprezentowano tylko jeden prosty przykład dokonywania refaktoryzacji kodu. Wskazane jest opracowanie katalogu wzorców refakoryzacji dla języka VHDL opartych o opis wzorca, motywację, mechanizm i przykład. Jest to dobry kierunek dalszych badań i rozwoju eksperymentalnego projektu VDT jako praktycznej realizacji mechanizmów refaktoryzacji kodu VHDL. LITERATURA I ŹRÓDŁA [1] Opdyke B., „Refactoring Object-Oriented Frameworks”, University of Illinois at UrbanaChampaign, 1992 [2] Rushton A., Vhdl for logic synthesis, John Wiley & Sons, 1998 [3] katalog wzorców refaktoryzacji - http://www.refactoring.com [4] projekt JavaCC – http://www.experimentalstuff.com/Technologies/JavaCC [5] platforma ECLIPSE - http://www.eclipse.org [6] P. Sołtan, „Koncepcja realizacji testów jednostkowych w języku VHDL”. Prace VII Konferencji Krajowej „Reprogramowalne układy cyfrowe”, RUC’2004, Szczecin, 2004, pp. 117-124. [7] Shavor S., D’Anjou J., Fairbrother S., Kehn D., Kellerman J., McCarthy P., „Eclipse Podręcznik programisty”, Helion, 2005 CONCEPT OF REFACTORING IN VHDL Przemysław Sołtan Technical University of Koszalin, Department of Electronics, Ul. Sniadeckich 2, 75-453 Koszalin e-mail: [email protected] Abstract In this paper, the conception of the refactorization of programs represented in VHDL language is proposed. Refactorization (refactoring), which means the purposed introduce of changes in the program source code without changes in its behavior, is the powerful and often used method for automatic generation, modification and optimization of object sources represented in Java, C++ and other programming languages. However, the specific of the VHDL language needs to use specific and unknown refactoring mechanisms, which takes to account the data types absented in the above programming languages (for example, signals, ports, entities, architectures, etc.) and do not operate with the main object data structures – classes. The proposed conception is based on the abstract syntax tree of the VHDL language and is realized as the VDT Java application with the original author’s library. The application is destined for operating in the ECLIPSE platform.