Speicher Timing Zeitverlauf

Das Timing (einhalten der Setup- und Hold-Zeit) ist eine Fehlerquelle für ungültige Daten.

Bsp. eines Schreibe-Zyklus
Ein neuer Zylkus beginnt bei der fallenden Flanke
   Da Daten leicht verzögert ankommen, beginnt der neue Zyklus
nach der fallenden Flanke. Die Verzögerung darf nicht so gross sein,
dass die setup Zeit verletzt wird.
(t_setup = Zeit, in der Daten vor CLK anliegen müssen)
Ausführen des Befehls bei steigender Flanke
Hier ist es ein Schreibbefehl. Auch der Lesebefehl wird bei steigender Flanke
ausgeführt.
Der Befehl wird leicht verzögert ausgeführt.
Um den Befehl recht auszuführen, darf die Hold Zeit nicht verletzt werden.
(t_hold = Zeit, in der die Daten nach dem CLK noch anliegen müssen)

Bereits kurz nach der ausführenden Flanke sind die Daten wieder Weg und der neue Zyklus beginnt.

Timing_Speicher

FPGA
Speicher haben intern einen Takt. Dadurch entfällt das Timingproblem.

Speicherzeilen und Speichertiefe

Speicherbreite
Die Speicherbreit ist oft identisch mit der Busbreite.
Ist sie dies nicht, muss mit Byte-enable das Ansprechen geregelt werden.
Word
= Breite einer Bit-Zeile (32-Bit, 16-Bit, ..)
= Speicherbreite
.               1 Word hat m Bits.
Bit      = Einzelne Speicherzelle.

Speichertiefe
Die Tiefe hängt von der Anzahl Adressleitungen ab.
Führen zum Speicher n Adressleitunge,  so ist der Speicher
2^n  (Word-)Zeilen tief.
Bsp.         2 Adressleitungen = 4 Speicherzeilen (Words) auslesbar

Speichergrösse
Word-Grösse x Anzahl Zeilen = m x 2^n
Bsp. Word = 32 Bit,  16 Adressleitungen
Speichergrösse:  4 x 2^16 =
4 x 2^3 x 2^3 x 2^10 = 4 x 8 x 8 x 1’000 =
32 x 8’000 = 256 kBytes

Organisation_Speicherzelle

 

 

 

 

Byte enable

Grund
Entspricht die Speicherbreite nicht der Breite des Buses, so müssen die Bytes des Busses über enable aufgeteilt werden können.
Mit enable sagt man, ob man den ersten oder zweiten Teil der Busbreite will.

Bsp
32-Bit-System für einen Baustein nur 16 Bit (z.B. für ein IO-Port oder ein Speicherbaustein).
ByteEnable

Byte_enable_0:
Bezieht sich auf die höheren Bits des Datan-Signals im Bus:   Data[16] – Data[31]
Byte_enable_1:
Bezieht sich auf die tieferen Bits der aktuellen Busdaten:     Data[0] – Data[15].

Setzt man Byte_enable_0, so werden nur die 15 oberen Bits des akutellen Bussiganals geschrieben oder gelesen.

Aktuelle Busdaten und Speichervorgang
Hier liegen in einem Speicher bereits Daten an den Adressen a0, a1 und a2.
Auf dem Bus liegt ein aktuelles Datenpaket (data) von 32 Bit.
Teile (oder auch das ganze) Datenpaket sollen auf die belegten Speicheradressen geschrieben werden.

Byte_Enable_timing

Da auch der Befehl Lesen aktiviert ist, wird „zeitgleich“ von der bestehenden Adresse auch der Wert an den Datenausgang (q) gelegt.

Aubau einer Speicherzelle

Logik

Logik_FF

Ein FF besteht aus logischer Sicht aus zwei Invertern. Durch die zwei Inverter, erscheint der Eingangswert wieder am Ausgang. Der Wert wurde gespeichert. Tiefer betrachtet, ist die Basis eines FF ein Latch. Das Latch ist der Baustein, der durch Set-Reset am Ausgang ein Wert behält. Das Latch ist aber asynchron und deshal kein FF im engen Sinn. Das FF hat zusätzlich einen Clock. Dadurch werden erst (bei steigender Flanke) die Ausgänge gesetzt.

Hardware (mit Transistoren)

Hardware_FF

Pro Speicherzelle (FF) hat es zwei Bit-Lines. Eine ist die Inversion der anderen.
Auf der Bit-Line wird das aktuelle Bit gesetzt (siehe erstes Bild für Logik).
Die Word-Linien, ist die Verbindung einer Reihe von Speicherzellen.
Unterschied Transistoren <-> Kondensatoren als Speicherelement
FF können mit Transistoren (z.B. in SRAM, s = static = stabil) oder mit Kondensatoren (z.B. DRAM, d = dynamisch = instabil) aufgebaut sein. Die Transistoren behalten ihren Wert (Zustand ‚1‘ oder ‚0‘), sind sie einmal geschalten, was bei den Kondensatoren nicht gilt. Die Kondensatoren entladen sich (‚1‘ – > ‚0.7‘ -> ‚0.5‘), weshalb ihr Wert immer wieder neu gesetzt (refresh) werden muss.
Das Refrehen wird zeilenweise gemacht.
Bsp. Bei einem 16-Bit-Memory, wird in einem Refresh-Zyklus 16 FF neu gesetzt.

Gute Website zu detaillierteren Informatioenen zum digitalen Speichern („How RAM works“).

Memory an Prozesssor anbinden

Takt anpassen
Die Geschwindigkeit des Prozessors ist oft langsamer als der Speicher.
Hier braucht es eine Synchronisation durch einen Takt-Generator.
Das Timing (einhalten der Setup und Holdzeit) war traditionell die grösste Fehlerquelle für ungültige Daten.

Word Grösse
Bei 32-Bit Prozessoren ist ein Word 32 Bit breit. Der Bus hat dieselbe Breite. Am einfachsten ist es, wennd der Speicher ebenfalls 32 breit ist. Dann entspricht ein Word einer Speicher-Zeile. Ansonsten braucht es Anpassungen (siehe Byte-enable).

Schreib- und Leserichtung
Traditionell hat der Prozessor nur ein Bus, der in beide Richtungen kommuniziert.
Bei FPGAs hat es immer zwei Busse, einer fürs Lesen und einer fürs Schreiben.

Zugriffe auf Speicher (Port)
Normalerweise gibt es einen Port. Über diesen gehen die Lese- wie auch die Schreibzyklen.
Im FPGA hat es zwei Ports. Beide können für beides gebraucht werden und können unterschiedliche Busbreiten haben.

 

VHDL IO Debuggen

Signalüberprüfung
Zum Debuggen können den Top-Level-Ports spezifische Wert zugewiesen werden:

GPIO_0 <= '0';
GPIO_0 <= '1';

Am KO kann dann der Wert überprüft werden oder man kann die Pins ausläuten, um zu sehen, ob sie funktionieren. Problem: Pins können auch sonst auf ‚0‘ oder ‚1‘ per default sein.

Besser: Clock-Zuweisung. (Problem auch hier: ClK könnte per default herauskommen.) Am sichersten: CLK auf eigene Frequenz einstellen, so ist man sicher, dass es der gewünschte Pin ist.

GPIO_0 <= CLK_50;


Instanzen anpassen

Im Top-Level könnendie IO der Instanzen mit open auf inaktiv gesetzt werden.

inst_counter: counter
    PORT MAP( clk          => CLOCK_50,
              verification => open,   -- GPIO_0   
              zero_out      => open   -- GPIO_1                
        );

 

 

 

 

 

.gitignore Hilfe

.gitignore bezieht sich nur auf <untracked files>.  Sie sind rot.
New Files (grün) sind bereits <add> und gitignore sieht sie nicht mehr.

File aus add-Liste nehmen

git reset HEAD <file>
git reset HEAD **/**/db/*

Die Files werden wieder rot und gelten als ausserhalb des commits.

Test Funktionsweise .gitignore
Ordner und Endungen, die in .gitignore stehen, sollten unter den <untracked files> erscheinen.
Wichtig: Änderungen in .gitignore müssen zuerst <add> werden, damit sie wirken.

Ordner ignorieren
In gitignore: <bla>/<bli>/<blo>/
Git kann Ordner nicht ignorieren, nur Dateien. Deshalb ist / am Ende zwingend.

Ordner relativ ignorieren

**/**/<blo>/

Die Anzahl Stufen müssen stimmen.
Achtung:
Bei allgemeinen Namen, können ungewollt andere Ordner betroffen sein. Deshalb lieber zwei Namen angeben, sodass es eindeutig wird.

Etwas aus ignoriertem Ordner hinzufügen

Cyclone_IV/synthese/db/*
! Cyclone_IV/synthese/db/<datei.xxx>

Ordner/* der Stern ist zwingend, damit nicht alles per se ignoriert wird. Nur so können unterhalb Dateien wieder zugefügt werden.

Git: wichtigste Befehle

Herunterladen

git fetch upstream

Herunterladen und zusammenführen mit local

git pull [origin master]  // fetch und merge


Dateien auf Github hochladen

git push [origin master]   // origin  bedeutet remote auf github
git push [ <ziel> <von wo>]

Unterscheidung remote/local
Github ist ein entferntes Verzeichnis auf dem Internet. Deshalb bezieht sich der Begriff remote auf Github. Steht nichts vor dem Branch-Name, so ist es local.

$git branch -a
*master     // local branch
develop     // local branch
remotes/origin/HEAD  -> origin/master
remotes/origin/master
remotes/origin/develop


Ordner umbenennen

git mv <old name> <new name>

 

Lokale Datei aus aktuellem Verzeichnis nehmen

Das Git-Verzeichnis befindet sich immer in einem Zustand. Dies ist eine spezifische Commit-Nummer. Will man eine Datei nicht mehr nachverfolgen, bedeutet dies, dass man die Datei aus diesem Arbeitsverzeichnis nimmt.

git remove <file>   Dieser Befehl ist das Gegenteil von

git add <file>

Git remove  bezieht sich nur auf das aktuelle Verzeichnis. Ist die Datei bereits eingechecked, so ist sie in alten Versionen noch da.

git_remove


Push auf Repository rückgängig machen

git log
git revert <beginn der aktuellen commit-nummer>

Der aktuelle Commit findet man mit git log. Danach kann man diesen commit mit revert rückgängig machen. Es besteht wieder der Zustand vor diesem commit.
git_log

Add  rückgängig machen

git reset HEAD <Verzeichnis>

Hat man lokal zuviel zum Committen getan, geht mit diesem Befehl die Datei zurück in untracked (und wird wieder rot).

Ordner aus Repository entfernen   (remote)

git rm -r --cached <directory>       
git commit -m "Ordner aus Github genommen" 
git push origin master

Hier wird der Ordner aus dem Repository genommen (dort gelöscht), aber lokal gelassen. Grund dafür ist die Zeile –cached.


Ordner aus Git entfernen (lokal und remote)

git rm -r <directory>
git status: deleted  <directory>
git add <directory>
git commit -m "löschen eines Ordners lokal und auf Github" 

Der Ordner existiert lokal nicht mehr. Soll er auch auf Github nicht mehr existieren, muss die Lösch-Meldung gepushed werden.


Alte Datei von Repository holen

git checkout <commit-nr> <pfad>/<file>

Achtung: Die Datei wird lokal genau nach Pfad abgelegt. Liegt dort eine aktuelle Datei, wird diese überschrieben. Man muss zuerst die akutelle Datei umbenennen.


Website mit wichtigsten Befehlen

C++: Fehlerhandling

Errorfunktion selber schreiben

void error( std::string message){
    std::cout << message << "\n";
} 


// im code anderer Funktion
if (input < 0) {
   error("ungültiger Wert. \n");
}

Dient zum Überprüfen falscher Argumente
.

Exceptions (Klasse verarbeitet Fehler)
Exceptions trennen den Fehlererkennung  (in Funktion) vom  Verarbeitungsort (main).

– Es wird ein Klasse pro Fehlertyp definiert
.  Aufgabe der Klasse: Fehlermeldung werfen
– Im main werden die Fehlermeldungen global gesamelt

// Notwendige Infrastruktur: Leere Fehlerklasse
class Zero_Input{  };

// Fehlerdetektion in Funktion
int get_value(){
     if (cin == ""  || cin == "0"){
         throw Zero_Input{};
     }
}

// Fehlerbehandlung aufgrund der Klassen
int main()
try{ 
      <code main>
   }
catch( Zero_Input ){
      std::cerr<< "Ops. Leerer Input \n";
      return 1;
}

– main() ist ohne geschweifte Klammern !
– Fehlerausgabe auf std:cerr nicht auf std::cout
Returnwert hat einen Wert unterschiedlich von 0

c++: vector as new type in -std=c++11

Eine sichere Alternative zum Array!

#include <vector>
std::vector <int> messungen = { 12, 10, 11, 12, 10 };
std::vector <string> klasse_1b = { "eva", "tim", "lin", "noe" };
std::vecrot <Class> token_table = { "n", 5, "+", 2, "*", 4 };


Wertzuweisung

messungen[1] = 11;
token_table[2] = { "*", 3 }

 

Vektor per Referenz übergeben
Damit nicht alle Werte des Vektors übergeben werden müssen, wird nur die Adresse übergeben (siehe Pointer).

void print( const vektor <int>& messungen){
.   // code
}

Zur Referenzübergabe gehört sowohl das & (Adresse mitgeben).

Mit 0 oder leeren Strings initialisieren

std::vector <int> messungen( 5 );
std::vector <string> klasse_1b( 4 );

Achtung: geht nur, wenn man mit -std=c++11 kompiliert.

for eines Vektors

for (int i : messungen){
.    (if i = 5 ) {
.        //
.     }
}

Das verkürzte For für einen Vektor gibt zu Beginn den Datentyp an und nach dem Doppelpunkt die Länge des Vekorts. Dann geht das For durch jedes Elements des Vektors.

for eines Vektors aus einem Klassen-Datentyp

for (Token t: token_table){
.    (if t.nummer == 5) {
.        //
.     }
}

Wieder zuerst der Datentyp (Token) und dann den Vektor.
Bei der interenen Auswertung, muss gesagt werden, auf welchen Variabelntyp der Klasse sich die Auswertung bezieht. (Bei der Klasse Token hat jeder Index zwei Variablen: string operation und int nummer.)

 

Funktionen für Vektorbearbeitung

int anzahl = messungen.size();
messungen.sort();


Daten in Vector einlesen

vector <int> data;
int current_element;

while ( cin ){
    cin >> current_element
     data.push_back ( current_element );
}

– Die Funktion push_back() hängt neue Daten hinten an.
– Sie vergrössert die Vektorgrösse damit immer um 1