1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
<?xml version="1.0" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="description" content="Uebersicht der Speicherverwaltung mit MMC am c't-Bot" />
<meta name="author" content="Timo Sandmann" />
<meta name="keywords" content="c't-Bot,mmc,virtueller Speicher, fat" />
<meta name="date" content="2007-01-06" />
<title>c't-Bot - VM-Dokumentation</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<h1>Dokumentation zur virtuellen Speicherverwaltung</h1>
<br />
<a class="menu" href="#uebersicht">Eine allgemeine Übersicht</a><br />
<a class="menu" href="#vm">Der virtuelle Speicher im Detail</a>
<ul>
<li><a class="menu" href="#alloc">Die Speicherallokierung</a></li>
<li><a class="menu" href="#example">Ein kleines Beispiel</a></li>
<li><a class="menu" href="#mmc">Die Schnittstelle zur Hardware</a></li>
<li><a class="menu" href="#cache">Einige Erläuterungen zum Cache</a></li>
</ul>
<a class="menu" href="#fat">Der Zugriff auf ein FAT16-Dateisystem</a><br />
<a class="menu" href="#stat">Etwas Statistik zur Leistungsbewertung</a><br />
<a class="menu" href="#defines">Eine Übersicht aller Konfigurationsparameter</a><br />
<a name="uebersicht"></a><h2>Eine allgemeine Übersicht</h2>
<p>Das Speichersystem ist wie folgt organisiert: <br />
Man fordert eine beliebige Menge an Speicher an und bekommt eine virtuelle Adresse in 32 Bit zurück.
Diese Adresse entspricht der Adresse auf der MMC / SD-Card, was den Benutzer aber nicht weiter interessieren muss. Zum Arbeiten mit den Daten
erhält man eine "echte" SRAM-Adresse, die auf einen 512 Byte großen Speicherbereich zeigt. Dieser Cacheeintrag wird
auf die MMC / SD-Card zurückgeschrieben, sobald der maximal für den <a href="#cache">Cache</a> zugeteilte Speicher komplett belegt ist, das
Ein- und Auslagern der Seiten auf die MMC / SD-Card macht die Speicherverwaltung also automatisch.<br />
Somit kann ein Verhalten beliebig viel (virtuellen) Speicher benutzen, siehe Abschnitt zum <a href="#vm">virtuellen Speicher</a>.
Außerdem kann derselbe Adressraum und Cache auch für den Zugriff auf FAT16-Dateien benutzt werden, Näheres dazu gibt es <a href="#fat">hier</a>.<br />
Die Bezeichnung "page" (oder "Seite") stellt durchgängig etwas logisches (virtuelles) dar, mit "Block" hingegen ist ein physischer Block auf dem verwendeten
Datenträger gemeint.<br />
Im Folgenden wird ausschließlich auf die Verwendung einer MMC / SD-Card als Speichermedium eingegangen, läuft der Code auf einem PC, so wird die
Speicherkarte mit Hilfe einer Datei emuliert, die Verwendung ist aber äquivalent (siehe auch <a href="../pc/mmc-emu_pc.c">pc/mmc-emu_pc.c</a>).
</p>
<a name="vm"></a><h2>Der virtuelle Speicher im Detail</h2>
<a name="alloc"></a><h3>Die Speicherallokierung</h3>
<p>Nach der Anforderung einer beliebige Menge an Speicher per<span class="function"> mmcalloc()</span>, bekommt man eine virtuelle Adresse des 32 Bit großen
Adressraums zurück.<span class="function"> mmc_get_data(uint32 virtuelle_Adresse)</span> liefert dann eine "echte" SRAM-Adresse auf einen 512 Byte
großen Puffer zurück, dessen Inhalt auf die MMC / SC-Card geschrieben wird, sobald er nicht mehr im SRAM gehalten werden kann.<br />
Die Funktion<span class="function"> mmc_get_end_of_page(uint32 virtuelle_Adresse)</span> hilft herauszufinden, bis wohin man diesen Pointer verwenden darf.
Benötigt man mehr Speicher, fordert man<span class="function"> mit mmc_get_data(uint32 virtuelle_Adresse)</span> einen neuen Pointer an.<br />
Zu beachten ist, dass nur soviel virtueller Speicher zur Verfügung steht, wie die intuitive Rechnung "letzter Sektor der MMC / SD-Card" minus
"<a href="#defines">Startadresse für den virtuellen Speicher</a>" ergibt. Ansonsten liefert<span class="function"> mmcalloc()</span> null zurück.
</p>
<a name="example"></a><h3>Ein kleines Beispiel</h3>
<p>Das folgende Beispiel demonstriert, wie sich der virtuelle Speicher benutzen lässt:<br />
<ins><div class="code">
<span class="keyword">uint32</span> v_addr = mmcalloc(2048, 1); <span class="comment">// wir wollen 2 KB Speicher</span><br />
<span class="keyword">uint8</span>* p_addr = mmc_get_data(v_addr); <span class="comment">// Pointer auf Puffer holen</span><br />
... <span class="comment">// irgendwas sinnvolles tun</span><br />
<span class="keyword">if</span> (i < 512) { <span class="comment">// Ziel liegt noch im gleichen Block</span><br />
p_addr[i] = my_data; <span class="comment">// Daten speichern</span><br />
i++;<br />
} <span class="keyword">else</span> { <span class="comment">// Blockende erreicht => zunaechst neuen Pointer holen</span><br />
v_addr += i;<br />
i = 0;<br />
p_addr = mmc_get_data(v_addr);<br />
p_addr[i] = my_data; <span class="comment">// Daten koennen nun gespeichert werden</span><br />
}
</div></ins><br />
Der zweite Parameter von<span class="function"> mmcalloc()</span> gibt an, ob man den angeforderten Speicher auf möglichst wenige Blöcke verteilt
haben möchte (also 512 Byte ausgerichtet), oder ob er einfach am nächsten freien Byte auf der Karte beginnen soll (1: aligned, 0: beliebig). Passt der
angeforderte Speicher noch komplett in einen bereits teilweise belegten Block, so wird er immer dort untergebracht.
</p>
<a name="mmc"></a><h3>Die Schnittstelle zur Hardware</h3>
<p>
Das folgende Diagramm zeigt die Beziehung der Funktionen des MMC-Codes und die entsprechenden Schnittstellen:
<br /><a href="mmc.jpg" onclick="popup=window.open('mmc.jpg','','dependent=yes,location=no,menubar=no,status=no,toolbar=no,scrollbars=yes'); popup.focus(); return false"><img src="mmc.jpg" width="200" alt="mmc-Code" /></a>
<br />Die grün gekennzeichneten Funktionen sind in den jeweiligen Header-Dateien deklariert und bilden zusammen
die Schnittstelle des MMC-Codes nach außen. Die rot Gekennzeichneten hingegen bleiben dem eigentlichen Code für MMC und virtual Memory vorbehalten.<br />
Die Abhängigkeiten untereinander sind durch die Pfeile dargestellt (in Aufrufrichtung).<br />
Den doppelt umrandeten Funktionen möge man besondere Aufmerksamkeit schenken - diese sind vorrangig in eigenen Verhalten zu verwenden. Die restlichen
(internen) Funktionen sind eher zur Dokumentation des Speichersystems an sich aufgeführt, für die Benutzung in Bot-Verhalten sind sie nicht so sehr
interessant.
</p>
<a name="cache"></a><h3 style="clear:both">Einige Erläuterungen zum Cache</h3>
<p>
Um den Zugriff auf die jeweiligen Daten möglichst performant zu halten, cached das Speichersystem eine vorgegebene Anzahl an 512 Byte großen
Blöcken im SRAM. Der Cache ist vollassoziativ, für das Zurückschreiben kommt das LRU-Verfahren zum Einsatz. Im Speicher wird er durch ein Array
vom Typ <i>vm_cache_t</i> (siehe auch <a href="../mmc-vm.c">mmc-vm.c</a>) repräsentiert, die maximale Größe lässt sich mit einem
<a href="#defines">Konfigurationsparameter</a> festlegen und wird bei Speichermangel automatisch reduziert. Es wird erst dann Cachespeicher belegt, wenn
auch Daten angefordert werden.<br />
Ein Aufruf der Funktion<span class="function"> mmc_flush_cache()</span> schreibt den kompletten Cache auf die Karte zurück,<span class="function">
mmc_page_write_back(uint32 virtuelle_Adresse)</span> hingegen nur die Seite, die zu der übergebenen Adresse gehört. Letztere Funktion tut dies
unabhängig davon, ob die Seite seit der Einlagerung verändert wurde oder nicht und ermöglicht so einen "tieferen" Eingriff in das
sonst automatisch arbeitende System.<br />
Ein Verhalten sollte also vor seiner Beendigung dafür sorgen, dass der Cacheinhalt gesichert wird, wenn die gespeicherten Daten erhalten bleiben sollen!
</p>
<a name="fat"></a><h2>Der Zugriff auf ein FAT16-Dateisystems</h2>
<p>
Die Unterstützung für FAT16-Dateien auf einer MMC / SD-Card ist wie folgt aufgebaut:<br />
<span class="function"> mmc_fopen(const char *filename)</span> öffnet eine Datei im FAT16-Dateisystem der Karte und gibt die virtuelle Startadresse
zurück, so dass man mit<span class="function"> mmc_get_data()</span> Zugriff auf die Daten bekommt. Der Dateiname muss dabei ganz am Anfang in der Datei
stehen.<br />
Achtung: Öffnet man eine Datei, die bereits mit<span class="function"> mmc_fopen()</span> geöffnet wurde, ist das Verhalten bzgl. dieser Datei derzeit
undefiniert!<br />
<span class="function"> mmc_clear_file(uint32 file_start)</span> leert eine Datei im FAT16-Dateisystem, die zuvor mit<span class="function">
mmc_fopen()</span> geöffnet wurde. Die Datei wird komplett mit Nullen überschrieben, nur der erste Sektor mit dem "Dateinamen" und der
Größe bleibt erhalten.<br />
<span class="function"> mmc_get_filesize(uint32 file_start)</span> gibt die Größe einer geöffneten Datei in Byte zurück.
</p>
<a name="stat"></a><h2>Etwas Statistik zur Leistungsbewertung</h2>
<p>
Wenn <a href="#defines">VM_STATS_AVAILABLE</a> definiert ist, lässt sich mit der Funktion<span class="function"> mmc_get_vm_stats()</span> eine Statistik
über die Leistung des Speichersystems erstellen.<span class="function"> mmc_print_statistic()</span> gibt solch eine Statistik in der Konsole aus, wenn der
Code auf einem PC läuft:
<ins><table class="console">
<tr><td>*** VM-Statistik ***</td></tr>
<tr><td>Groesse des Volumes:</td><td>32 MByte</td></tr>
<tr><td>Groesse des VM:</td><td>16 MByte</td></tr>
<tr><td>Belegter virt. Speicher:</td><td>0 KByte</td></tr>
<tr><td>Groesse des Caches:</td><td>1024 Byte</td></tr>
<tr><td>Auslastung des Caches:</td><td>100 %</td></tr>
<tr><td>Seitenzugriffe:</td><td>1375054</td></tr>
<tr><td>Seiteneinlagerungen:</td><td>33770</td></tr>
<tr><td>Seitenauslagerungen:</td><td>33768</td></tr>
<tr><td>Seitenzugriffe / s:</td><td>5288</td></tr>
<tr><td>Seiteneinlagerungen / s:</td><td>129</td></tr>
<tr><td>Seitenauslagerungen / s: </td><td>129</td></tr>
<tr><td>Cache-Hit-Rate:</td><td>97.544096 % </td></tr>
<tr><td>Messdauer:</td><td>260 s</td></tr>
</table></ins><br />
Die hier ersichtlichen Daten stellen die Leistung des Speichersystems dar, unmittelbar nachdem ein Bot das Standardlabyrinth im c't-Sim komplett mit dem Wandfolger-Algorithmus
durchfahren und dabei eine Umgebungskarte erstellt hat.<br />
Für die MCU gibt es derzeit noch keine entsprechende Ausgabemöglichkeit.
</p>
<a name="defines"></a><h2>Eine Übersicht aller Konfigurationsparameter</h2>
<ul>
<li><span class="function"> MMC_VM_AVAILABLE</span> schaltet den Speichermanager ein oder aus.</li>
<li><span class="function"> VM_STATS_AVAILABLE</span> ermöglicht die Berechnung und Ausgabe einer <a href="#stat">Statistik</a> über das Speichersystem, wenn definiert.</li>
<li><span class="function"> MMC_START_ADDRESS</span> gibt die physische Adresse (in Byte) an, wo der virtuelle Speicher beginnt. Sinnvoll ist z.B. die Hälfte der MMC- / SD-Card-Größe, der Speicherplatz davor kann dann für ein Dateisystem verwendet werden.</li>
<li><span class="function"> MAX_SPACE_IN_SRAM</span> definiert die Anzahl der 512 Byte großen Blöcke, die maximal gleichzeitig im SRAM gehalten werden.</li>
<li><span class="function"> VM_FILENAME_MAX</span> ist die maximale Länge eines Dateinamens in Zeichen.</li>
</ul>
<br /><br />
<p><a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-xhtml10" alt="Valid XHTML 1.0 Transitional" height="31" width="88" /></a></p>
</body>
</html>
|