Posts mit dem Label C werden angezeigt. Alle Posts anzeigen
Posts mit dem Label C werden angezeigt. Alle Posts anzeigen

Montag, 30. Januar 2012

Automatische variable Arrays


Ich habe kürzlich etwas Neues über die Programmiersprache C gelernt. Bisher war ich immer der Ansicht, dass Arrays, deren Größe zur Kompilierzeit nicht feststehen, auf dem Heap allokiert (->malloc) werden müssen. Seit ISO C99 bietet der Sprachumfang variable automatische Arrays, die wie alle automatischen Variablen auf dem Stack liegen.

Folgende Funktion

void func(uint a) { 
uint size=a+123;   
int array[size];   
}                   

ist gültig. Natürlich kann es hier zum Stacküberlauf kommen, es sollte daher eher mit etwas kleineren Feldern gearbeitet werden. Auf jeden Fall handelt man sich so kein Speicherleck ein, da das Array nach Funktionsende wieder freigegeben wird. Auch die Allokierung auf dem Stack ist schneller als auf dem Heap, da der Stackpointer dazu nur um die Arraygröße erhöht werden muss.

Weitere Infos findet man in den GCC-Docs. In diesem Zusammenhang möchte ich auch noch auf alloca() hinweisen. Diese Funktion allokiert ebenfalls ein variables Array auf dem Stack, ist aber scheinbar nicht ISO-C sondern eine BSD-Extension.

Der Unterschied zwischen alloca() und einem automatischen variablem Array liegt in der Gültigkeit des Speichers:
Der mit alloca() reservierte Speicher wird für die Laufzeit seiner Funktion belegt, das variable Array ist gültig innerhalb seiner Klammerebene.

Samstag, 17. Dezember 2011

Z80 in C programmieren

Ich bin wieder fleißig gewesen und habe am Z80-Computer gearbeitet. Ich plane die erste Erweiterungskarte für das System. Darauf wird sich eine IDE-Schnittstelle befinden, die ich ja bereits für die andere Z80-Platine erstellt hatte. Dann ein Controller zum Anschluss von Maus und Tastatur. Ich habe hier ein paar Trockenübungen auf einem Steckbrett gemacht: Tastatur auslesen und Numlock blinken lassen funktioniert, das sollte also kein Problem mehr sein. Eine PS/2-Maus hat das gleiche elektrische Interface, aber die Softwareseite habe ich mir noch nicht näher angeschaut und weiß daher nicht, wie schwierig das zu implementieren ist.
Weiterhin wird sich auf dem Erweiterungsboard der AY-3-8912 befinden. Das ist ein 8-Bit Sound-Chip mit drei "Stimmen". Er kam in einigen 8-Bit Computern und Arcadespielen zum Einsatz. Ich habe noch keinen in der Hand gehabt, aber bereits den Schaltplan für die elektrische Anbindung an den Z80 erstellt. In den nächsten Tagen sollte er eintreffen, er ist bereits bestellt.

Nun zum eigentlichen Thema dieses Posts:
Ich habe mich heute mit dem C-Compiler SDCC beschäftigt, der Code für "Small Devices" erzeugen kann, wie Z80, 8051, 68HC08 und 8-Bit PIC-Controller von Microchip. Eigentlich habe ich mit größeren Schwierigkeiten gerechnet, bis ich etwas Gescheites zum Laufen zu bringen, aber es hat relativ schnell geklappt.
Die erste Frage war, wie man in C auf die IO-Ports des Z80 zugreifen kann. Im Assembler macht man das mit IN/OUT-Befehlen:
IN A, (32)   (Lesen von Port 32)
OUT (32), A  (Schreiben auf Port 32)
Diese Befehle werden Spracherweiterungen mit dem schönen Namen Storage Class Language Extension zugeordnet, wie ich nach einigem Suchen herausfand.
Mit
__sfr __at (32) uart_rxtx;
definiert man eine Variable, die man lesen und schreiben kann. Der Code, der daraus erzeugt wird, ist dann das entsprechende IN/OUT. sfr steht übrigens für Special Function Register.
Ich schreibe mir also folgenden Code in schönstem ANSI-C:

__sfr __at (32) uart_rxtx;                
__sfr __at (33) uart_st;                  
                                          
void sendstr(const char *s) {             
while( *s ) {                            
while( uart_st&2 );                     
uart_rxtx = *s;                         
++s;                                    
}                                        
}                                         
                                          
int main(void) {                          
sendstr("Z80 Computer\r\n");             
sendstr("Programmiert in C!\r\n");       
while(1);                                
}                                         


Kompiliert wird das mit
sdcc -mz80 test.c
Heraus kommt test.ihx im Intel-Hex-Format, mein Programmer schluckt aber nur einfache Binärdaten. Das Hex-File kann man mit
makebin.exe -p test.ihx test.bin
in eine einfache Binärdatei wandeln. Und es funktioniert :-)
So ganz habe ich noch nicht durchdrungen, was da alles vor sich geht. Es wird noch gewisser Startup-Code hinzugefügt, unter Anderem in Form der Datei crt0.s, wo Interruptvektoren und der Stackpointer initialisiert werden. Jetzt als Standalone-Programm läuft das mit dem SDCC-Startup-Code. Wie das eines Tages mal aussieht, wenn ich ein kleines OS geschrieben habe, von dem aus ich solch ein Binary ausführe, kann ich nicht so wirklich einschätzen. Ich werde es sehen :-)