wx Hex Editor

Dieser Hex-Editor zeichnet sich über mächtige Speicheroptionen aus:

  • Die Hexwerte können mit Speicheroffset gespeichert werden
  • Hexwerte können mit ASCII-Interpretation gespeichert werden
  • Hexwerte können als C-Array mit einer wählbaren Datengrösse (int8_t, int16_t, int32_t, ..) gespeichert werden

Dies erleichtert die Weiterverarbeitung der eingelesenen Daten.


Debuggen von Speicher

Der Inhalt des Speichers (z.B.) eines Arrays muss in ein File kopiert werden. Das File wird eingelesen.

wxHexEditor

Im Menu können unter VIEW unterschiedliche Fenster (Pannel genannt) aktiviert werden.

Linke Fenster
Zeigt die selektierten Daten in unterschiedlichen Formaten an (Pannel Dateninterpreter) und in der Mitte das Infopannel.

Hauptfenster oben

Mehrere Files  können parallel angezeigt werden.

Hauptfenster unten

Ist die Ascii Interpretation des Inhalts. Das Pannel wird TextControl genannt.

DebugNavitator XCode

Fensterübersicht
Das fünfte Fenster im Navigator dient dem Debuggen.
Das Fenster links (1) heisst Stack View. Es zeigt alle Aufrufe (Ablagen auf dem Stack) bis zum aktuellen Programmpunkt. Zu unterst im Stack ist das main(), dann folgen alle aufrufe. Theoretisch kann man die Grösse der Stack-Details durch die Bedienung zu unterst am Fenster einstellen (nur Aufrufe, auch Variablen, …). Bei der hier abgebildeten Funktion war dies nicht möglich.
Das Fenster unten links (2) nennt sich Variable View. Durch Klicken auf das Dreieck vor der Variable, erhält man mehr Details. Man kann über das Menü ganz unten festlegen, ob man nur die lokalen Variabeln (aktuelle Einstellung) oder alle oder AUTO sehen will.
Das Fenster (3) ist die Konsole.

Fenster_DebuggNavigator

Debugg-KnöpfeDebuggKnoepfe_DebuggNavigator

  • CONTINUE: Verlässt die aktuelle Debugging-Stelle. Das Programm läuft weiter bis zum nächsten Breakpoint.
  • STEP OVER: Aktuelle Zeile wird ausgeführt. Cursor geht zur nächsten Zeile.
  • STEP INTO: Sprung von der aktuellen Stelle in die Funktion. Man sieht wohin das Programm geht und wie die Variablen gesetzt werden
  • STEP OUT: Verlassen der aufgerufenen Funktion. Man kehrt an die Debugging-Stelle zurück.

Variablen währende dem Debuggen temporär setzen
Im zweiten Fenster (Variable View) können während dem das Debuggen läuft, also der Code ausgeführt wird, Variablen-Werte manuell gesetzt werden. Man sieht dann, wie sich das auf den Code auswirkt.

 

 

 

 

 

Debuggen mit Breakpoints

Grundsätzlich

  • Breakpoints werden bei Anweisungen gesetzt
  • Bei Deklarationen und Definitionen werden sie nicht gesetzt

Steuerung des Ablaufs

  • Stoppt das Programm bei einem BREAKPOINT, so ist diese Anweisung nocht nicht ausgeführt. Man sieht den Zustand VOR der Anweisung.
  • STEP OVER: Die aktuelle Zeile wird ausgeführt. Der Cursor springt zur nächsten Zeile.
  • STEP INTO: Das Programm geht IN die Anweisung. Man sieht den Funktionsauftruf , alle Variablen der Funktion und den Ablauf
  • STEP OUT: Der Aufruf wird verlassen und man kehrt zum Ort zurück, an dem der Aufruf stand.
    (Verlassen des Aufrufes kann sehr hilfreich sein, wenn die Funktion sehr lang ist oder ein for-loop auf 20 zählt und man nicht jede Anweisung durchklicken will.)
  • CONTINUE: Man verlasst die aktuelle Codestelle und springt bis zum nächsten Breakpoint.
    Die aktuelle Debugstelle wird verlassen.

Testbench: Debuggen per Konsole

Assert Statment
Führen einen Vergleich aus. Stimmt der Vergleich, so passiert nichts. Nur wenn der Vergleich falsch ist, dann wird der Report ausgegeben.

ASSERT (s_midi = "010110") REPORT "Midi-value wrong" SEVERITY NOTE;

Es gibt vier Levels von severity reports: NOTE, WARNING, ERROR, FAILURE.
Das letzte Level (failure) bricht die Simulation ab.

Ist das Testing textbasiert, so steht oft auf der rechten Seite der eingelesene Wert, den das Signal haben soll (aus Textfile):

ASSERT (s_midi = note_1) REPORT "Note 1 falsch" SEVERITY WARNING;

 

Asserts als Passed-Points
Will man nur wissen, ob die Simulation an einer gewissen Stelle durchgekommen ist, wird Assert false  (= immer ausgeben) für die Kommandoausgabe gebraucht.

ASSERT false REPORT "Read in finished" SEVERITY NOTE;

Textbasierte Testbench  Passed-Point
Falls die textio-Bibliothek eingebunden und  variable line_out: Line; definiert wurde, kann man mit der Funktion write()  Text auf die Konsole schreiben.

write(line_out, string'("Read in finished."));
writeline(OUTPUT, line_out);

Der Text muss (leider) zuerst in den Zeilenbuffer Line gespeichert werden, und dann per OUTPUT  der Konsole übergeben. Die Definition dieser Varialblen steht in der Datei std_logic_textio.vhd.

CUDA Speicher-Verwaltung

Über Pointers kann von einem Speicher (CPU), auf den anderen (GPU) zugewiesen werden.

  • Device-Pointer zeigen auf Speicher im GPU
    – Kann im host-code gebraucht, aber nicht dereferenziert werden
  • Host-Pointer zeigen auf den Speicher der CPU. Kann vom GPU Code gebraucht, aber nicht dereferenziert werden.

    Funktionen
    cudaMalloc( Wert, Grösse);
    cudaFree();
    cudaMemcpy();

Bsp. aus der Einführung

int main( void ) {
int a, b, c;                  // host: a, b, c
int*dev_a, *dev_b, *dev_c;    // device copies of a, b, c
intsize =sizeof(int);         

// allocate device copies of a, b, c
cudaMalloc( (void**)&dev_a, size );
cudaMalloc( (void**)&dev_b, size );
cudaMalloc( (void**)&dev_c, size );

a = 2;
b = 7;

// copy inputs to device
cudaMemcpy(dev_a, &a, size,cudaMemcpyHostToDevice);
cudaMemcpy(dev_b, &b, size,cudaMemcpyHostToDevice);

// launch add() kernel on GPU, passing parameters
add<<< 1, 1 >>>(dev_a,dev_b,dev_c);

// copy device result back to host copy of c
cudaMemcpy( &c,dev_c, size,cudaMemcpyDeviceToHost);

cudaFree(dev_a);
cudaFree(dev_b);
cudaFree(dev_c);
return 0;
}

 

Testbench Aufbau

In VHDL gehört die Simulation (schreiben einer Testbench) fix zur Entwicklung dazu. Die Testbench ist in VHDL geschrieben und liegt im Ordner vhdl.
Achtung: Nie in Quartus-Projekt einbinden.  Quartus kann waits und asserts nicht kompilieren.
Ausgeführt (kompiliert) wird die Testbench über die Konsole vom Simlationsprogramm (per Script):

Simulationsprogramm
Bei altera ist questasim die Vollversion des Simulationsprogramms.

work
Einbinden der Bibliothek

Ablage
Im Projektordner wird ein Ordner simulation angelegt. In diesen Ordner kommt – über das Einbinden der Bibliothek  work – der Unterordner Work.
In diesen legt man das Script zum Starten der Simulation compile.do .


Testbench Datei

– die entity hat keine Ports. Sie besteht nur aus Signalen
– die IOs jeder Componente werden an Signale gehängt
– die Testsignale (stimuli) werden in processen gesetzt
– Signale dürfen nur Signalen zugewiesen werden
– die Tests (Vergleichsergebnis von Signalen)
.  finden in den Prozessen statt. Die Processe haben keine Klammern

stimuli:   sind selbst entworfene Signalverläufe
waits:     bestimmen die zeitliche Abfolge unter den
.                  Signalen
reports: geben die Resultat aus
.                  (Konsole oder in File (textbasiertes Testing).
clk:         der clk muss simuliert (erzeugt) werden.
.                 Dies geschieht durch einen eigenen clk-prozess

clk_generator  : process
begin
.   wait for 1 * clk_halfp;
.       clock_sig <= '1';
.   wait for 1 * clk_halfp;
.       clock_sig <= '0';
end process;
entity ram_tb is
end ram_tb;


architecture struct of ram_tb is

---------------------------------------------------------------
-- component declaration
---------------------------------------------------------------
component ram
port(
.    address     : IN STD_LOGIC_VECTOR (15 DOWNTO 0);
.    clock       : IN STD_LOGIC  := '1';
.    data        : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
.    wren        : IN STD_LOGIC ;
.    q           : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
);
end component;


---------------------------------------------------------------
-- signal instantiation
---------------------------------------------------------------

signal address_sig : STD_LOGIC_VECTOR (15 DOWNTO 0);
signal clock_sig   : STD_LOGIC  := '1';
signal data_sig    : STD_LOGIC_VECTOR (7 DOWNTO 0);
signal wren_sig    : STD_LOGIC ;
signal q_sig       : STD_LOGIC_VECTOR (7 DOWNTO 0);

signal clk_halfp   : time := 10 ns;
signal clk_period  : time := 20 ns;

-- eventuell constanten mit resultaten definieren

begin
---------------------------------------------------------------
-- component instantiation
---------------------------------------------------------------

inst_1 : ram
port map (
.   address  => address_sig,
.   clock    => clock_sig,
.   data     => data_sig,
.   wren     => wren_sig,
.   q        => q_sig
);

---------------------------------------------------------------
-- Set stimuli in process with timing
---------------------------------------------------------------
test_1: process(all)
.    -- Initialwerte setzen

.    -- Signale an Komponenten legen (Stimulation)

.   -- Warten

.   -- Signal von Ausgang Komponente abfangen

.   -- Vergleichen des Outputs mit Erwartung

.   -- Ausgabe Testresulat

end; -- test_1

end; -- architektur

Wie man die Tests startet, wird unter dem Eintrag Testbench ausführen erklärt. Eine professioneller Form des Testens basiert auf textbasierten Scripts.

Hier wird die Syntax der Testbench-Fehler (assert, report, severity,..) beschrieben.

Textbasiertes Testing: Aufbau Inputfile

File mit Testwerten

1 00000001 00000001 00000002 0
1 FFFFFFFF FFFFFFFF 00000000 1
2 00000004 00000005 FFFFFFFE 1
2 FFFFFFFF FFFFFFFF 00000000 0

wr_ram 0001 00F1  11
wr_ram 0002 0015  11
wr_rm  0002 F632  10

rd_ram 0001 00F1  99
rd_ram 0002 F615  99

reset 00 00 00 00 00 00 00 00 00
check 00 00 00 00 00 00 00 00 00
singl 13 01 00 00 00 00 00 00 00
check 13 00 00 00 00 00 00 00 00

Die Daten werden entweder als string  mit der Funktion read(<von>,<zu>)  oder als Hex-Zahl hread(<von>,<zu>)  eingelesen (vgl. std_logic_textio.vhd).

Richtige Zahlenwerte eintragen
Weil die Zahlen als Hex interpretiert werden, entspricht eine 0  4 Bits. Und die Zahl 10  entspricht dem dezimalen Wert 15.

Aus diesem Grund enstehen folgende Anzahl Bits:
00  im File    ->      std_logic_vector(7 downto 0)  beim Einlesen in der Testbench
0   im File    ->     std_logic_vector(3 downto 0)
7  im File     ->     std_logic_vector(3 downto 0)
0F5  im File  ->     std_logic_vector(11 downto 0)


Aufbau der Token
Die Token können alle vom selben Datentyp sein und über alle Testtyps die gleiche Struktur beinhalten. Das vereinfacht ihre Verarbeitung.

<Testtyp>  <Wert1>   <Wert2>    <Ergebnis_Addition> <Ueberlaufbit>
1          00000001  00000001   00000002             0

Im zweiten Beispiel hängt die Funktion der Token von dem Testtyp ab.

<Testtyp>  <adress>  <value>   <byte enable>
wr_ram     0001      00F1      11
<Testtyp>  <address>  <result>  <byte enable>
rd_ram     0001       00F1      01

Tipp: Fixe Tokenstruktur mit Auslassungen

singl 14 01 00 00 00 00 00 00 00   // verwerfen
polyp 13 01 14 01 15 01 14 00 02

Zum Decodieren wird es schwer, wenn unterschiedliche Verarbeitungs-Strukturen je nach Testtyp aufgebaut werden müssen.

Zu empfehlen ist, dass alle Test-Werte in einer Linie stehen und beim Verarbeiten gewisse Token verworfen werden.

Umsetzung in VHDL

VHDL Latch

In Zustand hängen bleiben
Ein Latch ist ein Verharren in einem Zustand (latch = Zuschnappen, Schliessen). Dies geschieht z.B. wenn bei einer switch-case-Struktur nicht alle Fälle abgefragt werden. Trifft ein nicht definierter Fall ein, so verharrt das System in diesem.

Urachen im Code

// kein else nach if
// .................
begin
        if (cnt = 15) then
            pulse <= '1';
        end if;
 end process;
// kein others in case
// ....................
case state is
            when s0 =>   LEDR_0  <= '1';
            when s1 =>   LEDR_1  <= '1'; GPIO_0_0 <= '1';
            when OTHERS =>  LEDG_7 <= '1';
        
    end case;