IC35 SDK Anmerkungen
Für die Richtigkeit der Angaben kann natürlich keine
Gewähr übernommen werden!
Da wir so einige Fragen zum IC35-SDK erhalten haben, an dieser Stelle
Anmerkungen zur IC35 Software-Entwicklung anhand eines Beispiel-Projekts
Irtrans,
Übertragung von Daten über die Infrarot-Schnittstelle des IC35
im RAW Protokoll (ohne IRDA).
Ich habe eine Anwendung, bei der ich ab und zu Meldungen (ASCII-Strings)
auf eine Laufschrift-Anzeige übertragen muss. Es handelt sich um eine
unidirektionale Schnittstelle, Übertragungsrate 9600 Baud. Da es die
bekannten Probleme mit der Beschaffung eines V24 Kabels gibt, habe ich
einen Infrarot-Umsetzer gebaut. Es werden einfach die IRDA-konformen Infrarot-Pulse
(zwischen 1.41 µsec und 3/16 der Bitlänge, entspricht ca. 19.5
µsec bei 9600 Baud) entsprechend der gewünschten Baudrate verlängert
(104 µsec bei 9600 Baud) . Das ist zwar keine gesicherte Verbindung,
aber da es nur wenige Daten sind, die zudem anschließend optisch
überprüft werden können, soll das kein Problem darstellen.
Benötigte Bauteile: IRDA-Tranceiver, Oszillator, Zähler,
NAND-Gatter, RS232 Wandler.
Schaltplan siehe unten.
Der Sourcecode für das Projekt Irtrans kann hier
heruntergeladen werden.
Aber jetzt zuerst zur Software Beschreibung.
Am einfachsten erstellt man ein IC35-Projekt, wenn man sich eine Kopie
des Beispiels VDemo aus dem IC35-SDK macht, das Directory umtauft
in diesem Fall in Irtrans, im Directory Irtrans dann die
Dateien VDemo.dsp und VDemo.rc in Irtrans.dsp und
Irtrans.rc
umbenennt.
Anschließend ersetzt man mit einem Text-Editor
in der Datei Irtrans.dsp alle Verweise auf VDemo durch Irtrans
(VDemo kommt 12 mal vor). Als nächstes öffnet man mit
Visual-C
das
Project Irtrans.dsp und schließt es gleich wieder.
Beim Speichern wird dann der Workspace Irtrans.dsw erzeugt.
Man hat nun auch bereits die zwei Dateien main.c und data.c
vor sich, in data.c kommen alle globalen Variablen, alle müssen
mit 0 statisch vorinitialisiert werden, z.B. S16 awDummy[10] = { 0};
, da Speicherplatz für Variable nur dann angelegt wird ! Falls man
keine globalen Variablen benötigt, kann man diese Datei entfernen.
Ansonsten muss mindestens eine (Dummy-) Variable darin vorkommen, sonst
beschwert sich der Compiler. Da man nur 2 KB Stack zur Verfügung hat,
sollte man alle größeren Datenfelder zu den globalen Variablen
legen.
Zu den Bänken:
Ein Z80 kann nur 64 KB adressieren, um solche Einschränkungen zu umgehen,
hat man Bankswitching-Verfahren entwickelt.
Offensichtlich wurde beim IC35 ein vom Compiler unterstütztes
Bankswitching in 16 K Bänken eingesetzt, d.h. Programm- und Daten-Bereich
sind in (unabhängige) 16 K Bänke aufgeteilt, wobei der Code-Bereich
(ROM) in den ersten beiden Bänken (0x0000 - 0x3fff und 0x4000 - 0x7fff)
liegt, der Daten-Bereich (RAM) über die anderen beiden Bänke
(0x8000 - 0xbfff und 0xc000 - 0xffff) adressiert wird.
Vermutlich läuft das ROM Bankswitching nur über den Bereich
0x4000 - 0x7fff, die IC35-SDK Bibliotheks-Funktionen werden fest über
den Bereich 0x0000 - 0x3fff angesprochen.
Analog verhält es sich mit dem RAM-Bereich (für globale Daten),
dieser wird über den Bereich 0x8000 - 0xbfff abgebildet, Stack etc.
liegt immer im Bereich 0xc000 - 0xffff.
Zuweisung der Bänke über den Projekt Maker:
Wenn man Programme selber entwickelt, muss man die Sourcen (*.c) (bzw.
eigentlich die zugehörigen Objekte) in eine ROM-Bank legen. Dazu erzeugt
man sich eine neue Bank (NEW BANK) und schiebt main.c in die so
erzeugte App. Bank 0, ebenso evtl. zusätzliche Source Files.
Erst wenn das Programm größer 16 KB wird, muss man eine zweite
Bank anlegen, ansonsten kann man die folgenden Zeilen ignorieren und bei
der Bank für globale Variable weiter lesen.
Entgegen der SDK-Dokumentation bekommt die erste Bank die Nummer 0
usw. . Die Zuordnung, welche Funktionen über Bankswitching gerufen
werden, macht ein extra Lauf beim Kompilieren (downcall). Dieses downcall
erkennt allerdings nur Funktionen, bei deren Definition die öffnende
spitze Klammer in der nächsten Zeile steht !!!, also
z.B.
void srand(U16 sStart)
{
Anhand der während des Kompilieren/Linkens erzeugten Datei func.map
kann man überprüfen, ob alle "externen" Funktionen als solche
erkannt wurden. Sie sollte dann in diesem Beispiel so aussehen:
srand*0X0001
wobei die Hex-Nummer die Bank bedeutet.
Übrigens, in main.c wird der Aufruf
srand(0xaffe);
ersetzt durch
downcall(0X0048,srand,0xaffe);
Als nächstes benötigt man evtl. eine
Bank für globale Variable (Default RAM Bank). Dazu klickt man
die Default RAM Bank an und schiebt data.c hinein.
Alle globalen Daten müssen in dieser Bank liegen und mit 0
vorinitialisiert sein, sonst beschwert sich der Compiler. Statische Daten
erlaubt der Compiler nicht.
Das Bankswitching ist vermutlich auch die Ursache für die Compiler
Probleme bei String-Funktionen (die im SDK üblichen Remarks: "xxx
should be a pointer to a character string array, not a constant").Diese
Funktionen haben offensichtlich Probleme bei der Verwaltung der aktuellen
Code-Bank (0x4000 - 0x7fff).
Problematisch wird es, wenn man (nicht zu 0) vorinitialisierte Daten
benötigt. So besteht z.B. die Spielstrategie für Mastermind aus
> 4 KByte (auf PC errechneter) Daten. Um sie in die Applikation zu bekommen
haben wir sie sozusagen in ein Bitmap gewandelt. Bitmaps beim IC35-SDK
bestehen aus X- und Y- Größe (in Pixel), gefolgt von X * Y /
8 Byte binärer Daten. Diese Daten haben wir in ein File try.img
geschrieben. Anschließend wurde in Visual-C eine neue Resource IMAGE
erzeugt, die das File try.img referenziert. Dieses File kann man
dann im Z80 Project Maker in die Resource Bank legen. Visual-C erzeugt
die Definitionen TRY_BANK und TRY_OFFSET in der Datei res.h. In
der Applikation können dann über
sHandle = open(TRY_BANK, TRY_OFFSET);
rc = read(sHandle, acSwTab, sizeof(acSwTab));
Daten aus der Resource Bank eingelesen werden.
Das Ganze hat den Nachteil, dass man mindestens 2 Bänke benötigt
(32 KB) und somit der knappe Applikationsspeicher strapaziert wird.
Eine andere Möglichkeit ist, nach dem Fertigstellen der Applikation
die Daten an das Ende des Programms zu patchen. Eine IC35 Applikation hat
eine minimale Länge von 16 KB, wobei die nicht benötigten Speicherzellen
am Ende des Programms mit 0 aufgefüllt sind. Diese kann man dann durch
initialisierte Daten ersetzen. Dazu macht man sich ein Windows-Programm
das die Datei <xxx.app> binär einliest, die letzen Bytes auf 0
überprüft, sie durch die initialisierten Daten ersetzt und anschließend
eine neue Datei erzeugt. Angenommen man benötigt 351 Bytes initialisierte
Daten:
#define IDATA_LENGTH 351
in data.c:
#ifndef _WINDOWS
uchar acSwTab[IDATA_LENGTH] = {0};
// make uninitialized data
#else
uchar acSwTab[IDATA_LENGTH] = { 1, 2, 3 (...) };
// use initialized data in Simulator
#endif
und in main.c:
#ifndef _WINDOWS
short sHandle;
sHandle = open(GetRomBank(), 0x8000 - IDATA_LENGTH);
read(sHandle, acSwTab, IDATA_LENGTH);
// initialize the data from ROM
close(sHandle);
#endif
Projekt Irtrans
Folgende Voraussetzungen:
Quellen unter c:\Source\Ic35\Sw\'<'Project Name'>' (hier Irtrans)
Header Files unter c:\Source\Ic35\Include (Kopieren von \Ic35sdk\Include)
Libraries unter c:\Source\Ic35\Lib (Kopieren von \Ic35sdk\Lib)
1. Customize von Visual-C wie im SDK angegeben:
1.1 Configure IC35 Project (IC35 Project Maker)
Command: C:\Ic35sdk\CCTools\Tool\Dsp2Mak.exe
Arguments: $(WkspDir)\$(WkspName)
Initial Directory: $(WkspDir)
Dieses Kommando wird benötigt, um ein
Makefile zu erzeugen.
1.2 Make IC35 Project
Command: C:\Programme\Microsoft Visual Studio\VC98\Bin\Nmake.exe (o.ä.)
Arguments: /nologo $(WkspName)_z80.mak
Initial Directory: $(WkspDir)
Dieses Kommando übersetzt und linked
das Projekt.
1.3 Name IC35 Project ( neuer Punkt )
Command: addhead.exe
Arguments: app.rom $(WkspName).app ic35.nam
Initial Directory: $(WkspDir)\Z80_Out
Mit diesem Kommando setzt man den Applikationsnamen
in den Header und erzeugt eine Datei mit der .app Extension für
den Download über die Sync-Station. Es ersetzt den im SDK angegebenen
Download über das nicht lieferbare RS232-Kabel.
2. Erstellen von Projekten
Am einfachsten ist es, wenn man sich eine Kopie von VDemo macht.
2.1 Kopieren
\Ic35sdk\Example\VDemo -> \Source\Ic35\SW\Irtrans
2.2 Umbenennen
Unter \Source\Ic35\SW\Irtrans:
VDemo.dsp -> Irtrans.dsp
VDemo.rc -> Irtrans.rc
2.3 Ersetzen
in Datei Irtrans.dsp: alle Einträge VDemo durch Irtrans
ersetzen (12)
2.4 Visual-C
Unter Visual-C Irtrans.dsp (als Project) öffnen, erzeugt
dann beim Speichern einen Workspace (Irtrans.dsw)
3. Erzeugen der Applikation
Nachdem man die Applikation mit dem Emulator ausgetestet hat, erzeugt man
den Target-Code für den IC35.
3.1 IC35 Project Maker
TOOLS -> Configure IC35 Project
Klicken auf NEW BANK erzeugt ein App. Bank 0
App. Bank 0 anklicken und in diese Bank dann main.c verschieben.
Default RAM Bank anklicken und data.c hineinschieben.
Falls bei einem erneutem Aufruf von TOOLS -> Configure IC35 Project
die Dateien nicht mehr in den Bänken stehen, ist das ein Zeichen dafür,
dass bei den
General Einstellungen die Pfade nicht stimmen.
3.2 Target Code übersetzen/linken
TOOLS -> Make IC35 Project
Unter Win95/98/ME® wartet der Compiler 2 mal auf Tastatur Eingabe
(beliebige Taste), zum Schluss muss man auch noch mit CTRL-C abbrechen,
unter NT® läuft der Compiler normal durch. Der Compiler erzeugt
ziemlich viele Warnungen, die aber ignoriert werden können.
Erzeugt wird die Datei App.rom im Subdirectory Z80_Out.
3.3 Namen in Header einfügen
Als nächstes muss im Header der Applikation der Applikationsname eingetragen
werden.
TOOLS -> Name IC35 Project
erzeugt in Subdirectory Z80_Out die Datei Irtrans.app
aus der Datei App.rom. Dazu muss mit einem Texteditor vorher
noch eine Datei Ic35.nam erzeugt werden, die den gewünschten
Namen der Applikation enthält, in diesem Fall Irtrans.
Die Datei Irtrans.app kann nun mit dem IC35 Manager heruntergeladen
werden.
4.Schaltplan Irtrans Modul
Michael Fitzek
Änderungsstand: 11.11.2001
© www.Moritz-Fitzek.de