Core Generator (wersja 1)

Zadanie: Należy rozbudować poprzedni projekt w następujący sposób:

System powinien buforować dane odbierane z portu RS232, a następnie po zebraniu określonej liczby (row_max) znaków wydrukować je z powrotem do portu RS232 w formie „pseudograficznej” (używając jako „pixela” znaku o takim samym kodzie jak drukowany). Oprócz tego projekt powinien buforować znaki przychodzące z wejścia RS232 w czasie kiedy drukowana jest linia (i nie można ich na bieżąco drukować). Długość bufora: 64 znaki. Przekroczenie bufora powinno być sygnalizowane zapaleniem się LEDy LD0. Parametry portu RS232 oraz funkcja monitorowania odebranych znaków (przed buforowaniem) powinny pozostać tak jak w poprzednim ćwiczeniu. Parametr row_max powinien być łatwy do modyfikacji (np. ustalany jako stała). Akceptowane wartości: 2 do 15.

 

Poniżej podano przykład wydruku kilku linii (row_max=8):

 

 

        bbb                 ddd            fff          hhh

         bb                  dd           ff ff          hh

         bb                  dd           ff  f          hh

 aaaa    bbbbb    cccc     dddd   eeee    ff      ggg gg hh

    aa   bb  bb  cc  cc   dd dd  ee  ee  fffff   gg  gg  hhhhh

 aaaaa   bb  bb  cc      dd  dd  eeeeee   ff     gg  gg  hh  hh

aa  aa   bb  bb  cc      dd  dd  ee       ff     gg  gg  hh  hh

aa  aa   bbb bb  cc  cc  dd  dd  ee  ee   ff      ggggg  hh  hh

 aaa aa bbb bb    cccc    ddd dd  eeee   ffff        gg hhh  hh

                                                 gg  gg

                                                  gggg

 

 

 

 

   AA   BBBBBB     CCC  DDDDD    EEEEEE  FFFFFF   GGGG   HH  HH

  AAAA   BB  BB   CC CC  DD DD    EE  E   FF  F  GGG GG  HH  HH

 AA  AA  BB  BB  CC   C  DD  DD   EE      FF     GG      HH  HH

 AA  AA  BB  BB  CC      DD  DD   EE E    FF F   GG      HH  HH

 AA  AA  BBBBB   CC      DD  DD   EEEE    FFFF   GG      HHHHHH

 AAAAAA  BB  BB  CC      DD  DD   EE E    FF F   GG GGG  HH  HH

 AA  AA  BB  BB  CC   C  DD  DD   EE      FF     GG  GG  HH  HH

 AA  AA  BB  BB   CC CC  DD DD    EE  E   FF     GGG GG  HH  HH

 AA  AA BBBBBB     CCC  DDDDD    EEEEEE  FFFF     GGGG   HH  HH

 

 

 

 

 

 

   11     2222    3333      44   555555    666   777777   8888

  111    22  22  33  33    444   55       66     77  77  88  88

 1111        22      33   4444   55      66          77  88  88

   11        22      33  44 44   55      66         77   88  88

   11       22    3333  44  44   55555   66666      77    8888

   11      22        33 4444444      55  66  66    77    88  88

   11     22         33     44       55  66  66    77    88  88

   11    22  22  33  33     44   55  55  66  66    77    88  88

  1111   222222   3333     4444   5555    6666     77     8888

 

 

 

 

Znaki o kodach poniżej 32 powinny być drukowane przy użyciu gwiazdek jako „pixeli”. Nie należy wprowadzać kontrolnej funkcji tych znaków (np. końca linii itp.). Przykład linii zawierającej znaki o kodach 0-31:

 

 

  ****   ****     *****  *****   *****                    ***

  *  *  **  **      *** *     * *******  ** **     *     *****

  ****  **  **     ** * * * * * ** * ** *******   ***    *****

  *     **  **    **  * *     * ******* *******  *****    ***

  *      ****    ****   *     * ******* ******* ******* *******

  *       **    **  **  * *** * **   ** *******  *****  *******

 **     ******  **  **  *  *  * *** ***  *****    ***    *****

***       **    **  **  *     * *******   ***      *       *

**        **     ****    *****   *****     *             *****

 


Wejścia i wyjścia układu:
clk_i - zegar 50MHz,
rst_i - reset asynchroniczny,
RXD_i - wejście danych RS232,

TXD_o - wyjście danych RS232,

ld0 – wyjście sygnalizacji przepełnienia bufora FIFO (LED LD0),
led7_an_o – wyjście sterujące anodami wyświetlaczy LED,

led7_seg_o – wyjście sterujące segmentami wyświetlaczy LED.

Do realizacji projektu potrzebne będą dwa moduły funkcjonalne wygenerowane przez Core Generator. Pamięć ROM posłuży do przechowywania kształtów znaków zaś pamięć FIFO posłuży do implementacji 64-znakowego bufora FIFO buforującego port wejściowy RS-232. Definicje znaków 8x16 pixeli są dostępne w pliku: chargen.coe



Generacja modułu pamięci ROM:

Wybieramy: Project -> New Source

Następnie otwiera się okienko Select Source Type w którym wybieramy:
IP (CORE Generator & Architecture Wizard).
Podajemy nazwę pliku dla nowego komponentu (generowanego przez Core Generator), np. char_mem i klikamy Next:

 


 


Następnie otwiera się okienko wyboru nowego komponentu Select IP:


 


W okienku tym wybieramy Block Memory Generator v2.8 oraz klikamy Next. Następnie wyświetla się okienko podsumowania: New Source Wizard – Summary. Należy potwierdzić naciskając Finish.

Następnie uruchamia się Core Generator i otwiera się okienko konfiguracji nowego komponentu:


 


W tym okienku (1/4) zmieniamy Memory Type na Single Port ROM.
Znajdujący się w lewym dolnym roku przycisk View Data Sheet otworzy szczegółową dokumentację projektowanego komponentu.

Następnie klikamy Next.

 


 


W tym okienku (2/4) zmieniamy Read Width na 8 (definicja znaku ma w poziomie 8 pixeli) oraz Read Depth na 4096 (jest 256 znaków po 16 bajtów każdy).

Następnie klikamy Next.

 


 


W tym okienku (3/4) zaznaczamy Load Init File oraz wprowadzamy ścieżkę do pliku chargen.coe z definicjami znaków (można ułatwić to sobie za pomocą przycisku Browse).

Następnie klikamy Next.

 


 


W tym okienku (4/4) nic nie zmieniamy. Warto zapamiętać pomocnicze informacje zawierające podsumowanie właściwości projektowanego komponentu (pole Information) oraz blokowy schemat połączeń. Szczególnie istotna jest informacja: Total Port A Read Latency (From Rising Edge of Read Clock): 1 Clock Cycle(s)

Należy potwierdzić naciskając Finish.

Spowoduje to rozpoczęcie generacji komponentu – należy trochę poczekać.

Po zakończeniu generacji komponent zostanie dołączony do listy plików projektu.

Poniżej podano sposób przechowywania kształtów znaków w pamięci ROM (na przykładzie literki R):

Adres

b7

b6

b5

b4

b3

b2

b1

b0

kod_ascii*16+0

0

0

0

0

0

0

0

0

kod_ascii*16+1

0

0

0

0

0

0

0

0

kod_ascii*16+2

0

1

1

1

1

0

0

0

kod_ascii*16+3

0

1

0

0

0

1

0

0

kod_ascii*16+4

0

1

0

0

0

1

0

0

kod_ascii*16+5

0

1

0

0

0

1

0

0

kod_ascii*16+6

0

1

0

0

0

1

0

0

kod_ascii*16+7

0

1

1

1

1

0

0

0

kod_ascii*16+8

0

1

0

1

0

0

0

0

kod_ascii*16+9

0

1

0

0

1

0

0

0

kod_ascii*16+10

0

1

0

0

1

0

0

0

kod_ascii*16+11

0

1

0

0

0

1

0

0

kod_ascii*16+12

0

1

0

0

0

1

0

0

kod_ascii*16+13

0

0

0

0

0

0

0

0

kod_ascii*16+14

0

0

0

0

0

0

0

0

kod_ascii*16+15

0

0

0

0

0

0

0

0

Adres – adres w pamięci ROM.

kod_ascii – kod ASCII wyświetlanego znaku.

Adres dla pamięci ROM najłatwiej jest wygenerować łącząc 8-bitowy wektor kodu znaku ASCII z 4-bitowym wektorem numeru linii w znaku (0-15) za pomocą operatora &. Należy pamiętać o tym, że po wydrukowaniu każdej linii ze znakami należy wysłać dwa znaki: CR (kod: 13) oraz LF (kod: 10) w celu przejścia do nowej linii.

W celu ułatwienia dołączenia komponentu do hierarchii aktualnego projektu w katalogu projektu powstają pliki *.vho zawierające szkielet deklaracji komponentu oraz przykład jego użycia (tworzenia instancji). Możemy te elementy łatwo przenieść do naszego projektu – wtedy zaprojektowany komponent zajmie właściwe miejsce w hierarchii.

Przykładowy plik VHO:

-- The following code must appear in the VHDL architecture header:
------------- Begin Cut here for COMPONENT Declaration ------ COMP_TAG
component char_mem
       port (
       clka: IN std_logic;
       addra: IN std_logic_VECTOR(11 downto 0);
       douta: OUT std_logic_VECTOR(7 downto 0));
end component;

-- Synplicity black box declaration
attribute syn_black_box : boolean;
attribute syn_black_box of char_mem: component is true;
-- COMP_TAG_END ------ End COMPONENT Declaration ------------
-- The following code must appear in the VHDL architecture
-- body. Substitute your own instance name and net names.
------------- Begin Cut here for INSTANTIATION Template ----- INST_TAG
your_instance_name : char_mem
             port map (
                    clka => clka,
                    addra => addra,
                    douta => douta);
-- INST_TAG_END ------ End INSTANTIATION Template ------------
-- You must compile the wrapper file char_mem.vhd when simulating
-- the core, char_mem. When compiling the wrapper file, be sure to
-- reference the XilinxCoreLib VHDL simulation library. For detailed
-- instructions, please refer to the "CORE Generator Help".

Tekst zaznaczony na czerwono należy skopiować do obszaru definicji sygnałów lokalnych. Tekst zaznaczony na niebiesko (po ustaleniu nazwy instancji komponentu oraz sygnałów podłączonych) należy skopiować do obszaru opisu systemu. Po dokonaniu powyższych modyfikacji ikonka komponentu powinna zająć właściwe miejsce w hierarchii plików projektu.

Modyfikacja parametrów komponentu i jego ponowna generacja są możliwe za pomocą ikonek Manage Cores i Regenerate Core zaznaczonych na poniższym rysunku.

 


 



Generacja modułu pamięci FIFO

W celu wygenerowania modułu bufora FIFO postępujemy podobnie jak poprzednio.

Wybieramy: Project -> New Source

Następnie otwiera się okienko Select Source Type w którym wybieramy:
IP (CORE Generator & Architecture Wizard).
Podajemy nazwę pliku dla nowego komponentu (generowanego przez Core Generator), np. fifo_mem i klikamy Next:


 


Następnie otwiera się okienko wyboru nowego komponentu Select IP:

 


 


W okienku tym wybieramy Fifo Generator v4.4 oraz klikamy Next. Następnie wyświetla się okienko podsumowania: New Source Wizard – Summary. Należy potwierdzić naciskając Finish.

Następnie uruchamia się Core Generator i otwiera się okienko konfiguracji nowego komponentu:


 


W tym okienku (1/6) wybieramy opcję: Common Clock (CLK) – Block RAM.
Znajdujący się w lewym dolnym roku przycisk View Data Sheet otworzy szczegółową dokumentację projektowanego komponentu.

Następnie klikamy Next.


 


W tym okienku (2/6) zmieniamy Write Width na 8, Write Depth na 64 (zakładana pojemność FIFO) oraz Read Width na 8.
Proszę zwrócić uwagę na informację na dole (zależy ona od poprzednio wybranych opcji i oznacza liczbę cykli zegara od wydania komendy odczytu do wystawienia danych na wyjście FIFO):
Read Latency (From Rising Edge of Read Clock): 1

Następnie klikamy Next cztery razy (przechodzimy przez kolejne ekrany nic nie zmieniając). Ostatni ekran (6/6) powinien wyglądać następująco:


 


Warto zapamiętać pomocnicze informacje zawierające posumowanie właściwości projektowanego komponentu (pole Information) oraz blokowy schemat połączeń.

Należy potwierdzić naciskając Finish.

Spowoduje to rozpoczęcie generacji komponentu – należy trochę poczekać.

Podobnie jak w poprzednim przypadku należy teraz podłączyć wygenerowany komponent do projektu (można wykorzystać wygenerowany plik *.vho).

Ważne informacje dotyczące komponentu FIFO można znaleźć także w następującym dokumencie: UG175


Weryfikacja układu

Należy zweryfikować układ praktycznie poprzez zaprogramowanie płytki testowej. W razie potrzeby należy wykonać symulację funkcjonalną. Weryfikacja praktyczna polega na sprawdzeniu działania systemu poprzez wyświetlenie kilku linii w trybie „pseudograficznym” oraz sprawdzeniu mechanizmu wykrywania przepełnienia bufora (np. przytrzymanie klawisza przez dłuższy czas powinno spowodować przepełnienie bufora). Układ testować za pomocą programu MINICOM (program jest domyślnie skonfigurowany na 9600bps, 8 bitów danych, 1 bit stopu, bez parzystości).


Nadawanie i odbiór sygnałów w standardzie RS232

Nadawanie i odbiór sygnałów w standardzie RS232 odbywa się w sposób szeregowy, oddzielnie na dwóch liniach w kierunkach do i od urządzenia. W czasie braku transmisji sygnał na danej linii jest w stanie wysokim. Rozpoczęcie transmisji inicjowane jest przez tzw. bit startu będący "0" logicznym, który powinien trwać przez okres równy odwrotności prędkości transmisji, w naszym przypadku wynoszący 1/9600 [sekund]. Wszystkie następne informacje są przesyłane z identycznym okresem trwania. Następnie nadawane są szeregowo dane począwszy od najmniej znaczącego bitu aż do bitu najbardziej znaczącego (D0-D7). Później występuje bit parzystości, będący operacją logiczną XOR na danych D0-D7. Bit parzystości jest opcjonalny i w przypadku niniejszego zadania nie występuje. Zakończenie transmisji sygnalizowane jest bitami stopu, w ilości zazwyczaj od 1 do 2. Przykład sygnału, zgodnego z wymaganiami zadania, przenoszącego kod 01010011 przedstawiony jest na poniższym rysunku.

Transmisja RS-232
Rys.1 Przykładowa transmisja kodu 01010011 przez RS-232


Informacje dodatkowe o standardzie RS232:
http://www.fizyka.umk.pl/~ptarg/labview/folie/RS232.pdf
http://pl.wikipedia.org/wiki/RS-232


Plik ucf do zadania, płytka Digilent Spartan-3, układ Spartan-3 3S200 FT256-4:

# Clock:
NET "clk_i" LOC = "T9" ; # 50 MHz clock
# Push-buttons:
NET "rst_i" LOC = "L14" ; # pressed high BTN3
# RS232:
NET "TXD_o" LOC = "R13" ; # RS 232 TXD
NET "RXD_i" LOC = "T13" ; # RS 232 RXD
# Seven-segment LED display:
NET "led7_an_o<3>" LOC = "E13" ; # leftmost digit, active low
NET "led7_an_o<2>" LOC = "F14" ; # active low
NET "led7_an_o<1>" LOC = "G14" ; # active low
NET "led7_an_o<0>" LOC = "D14" ; # rightmost digit, active low
NET "led7_seg_o<7>" LOC = "E14" ; # segment 'a', active low
NET "led7_seg_o<6>" LOC = "G13" ; # segment 'b', active low
NET "led7_seg_o<5>" LOC = "N15" ; # segment 'c', active low
NET "led7_seg_o<4>" LOC = "P15" ; # segment 'd', active low
NET "led7_seg_o<3>" LOC = "R16" ; # segment 'e', active low
NET "led7_seg_o<2>" LOC = "F13" ; # segment 'f', active low
NET "led7_seg_o<1>" LOC = "N16" ; # segment 'g', active low
NET "led7_seg_o<0>" LOC = "P16" ; # segment 'dp', active low
# LD0 LED:
NET "ld0" LOC = "K12" ; # high on
#