\ **************************************************** \ * * \ * BOOTMA-8.FTH * \ * * \ * Zutaten fuer FAT-Reparatur und Bootmanager unter * \ * Turbo-FORTH-83 * \ * * \ * Fred Behringer - Forth-Gesellschaft - 24.3.2011 * \ * * \ **************************************************** \ ==================================================== \ Ich habe im vorliegenden Artikel darauf verzichtet, \ die Programme auch fuer ein Arbeiten mit ZF einzu- \ richten. Sie sind hier nur fuer Turbo-Forth gedacht! \ ==================================================== hex \ 32-Bit-Assembler-Erweiterung \ ---------------------------- \ Im weiter unten folgenden Programm zur Anfertigung eines Disketten-Images \ wird neben Punktzahlen (32-Bit-Zahlen) viel mit 32-Bit-Maschinenbefehlen \ gearbeitet. Ein kompletter 32-Bit-Forth-Assembler wird dafuer aber nicht \ benoetigt. Ein paar Anpassungen des in Turbo-Forth ohnehin zur Verfuegung \ stehenden 16-Bit-Assemblers genuegen. Es wird von einer (PC-kompatiblen) CPU \ von mindestens dem Typ 80486 ausgegangen. Im Zweifelsfall gilt: Meine \ Experimente wurden mit einem AMD-K6-2/500 durchgefuehrt. only forth also assembler definitions : fs: 64 c, ; : gs: 65 c, ; : opsize: 66 c, ; : adrsize: 67 c, ; : eax opsize: ax ; : ecx opsize: cx ; : edx opsize: dx ; : ebx opsize: bx ; : esp opsize: sp ; : ebp opsize: bp ; : esi opsize: si ; : edi opsize: di ; \ Freischalten der Adressleitung a20 \ ---------------------------------- \ Mit himem.sys in der config.sys wird die Adressleitung 20 normalerweise \ freigeschaltet. Hat man aus irgendeinem Grunde keine himem.sys in der \ config.sys, dann kann man zur Freigabe des Zugriffs auf Adressen oberhalb \ ffff:ffff das folgende Wort free-a20 verwenden. forth definitions code free-a20 ( -- ) cli begin 64 # al in 02 # al and 0= until 0d1 # al mov 64 # al out begin 64 # al in 02 # al and 0= until 0df # al mov 60 # al out begin 64 # al in 02 # al and 0= until sti next end-code : a20? ( -- fl ) 0ffff 10 l@ 0. l@ <> 0= ; \ fl=-1 --> a20 gesperrt \ Segmente fs und gs (im PC ab 80486 vorhanden) bearbeiten \ -------------------------------------------------- \ cs ds es benoetigen im vorliegenden Artikel keine Sonderbehandlung. code fs@ ( -- cc ) 0f c, 0a0 c, next end-code \ f-Segment holen: fs push code gs@ ( -- cc ) 0f c, 0a8 c, next end-code \ g-Segment holen: gs push code fs! ( cc -- ) 0f c, 0a1 c, next end-code \ f-Segment setzen: fs pop code gs! ( cc -- ) 0f c, 0a9 c, next end-code \ g-Segment setzen: gs pop \ Datenverkehr ueber den gesamten 32-Bit-Systembereich \ ---------------------------------------------------- \ Achtung: Die folgenden Store- und Fetch-Befehle laufen ueber das spezielle \ Segment-Register fs . Will man die echten physikalischen Adressen erreichen, \ so muss man fs vorher (per 0 fs!) auf 0 setzen. Im Wort dump-32 wird das \ Segment fs vorher sichergestellt, waehrend des Dumpens mit fs=0 betrieben und \ nach Verlassen von dump-32 wieder restauriert. \ Fuer die folgenden Worte c@-32 bis !-32 bedeutet: \ Punktzahl-Eingaben werden immer so uebertragen, dass sie im RAM in \ Little-Endian-Form erscheinen. Beispiel: 12345678. geht in 78563412 ueber. \ (Dabei werden je zwei Hexziffern in einem Byte untergebracht. Bei 12 steht \ die 1 in den oberen vier Bits, auf dem Bildschirm links, die 2 in den \ unteren, usw.) Umgekehrt wird aus 78563412 im RAM nach Einholen auf den \ Stack (per @-32) und Ausdrucken (per ud.) wieder 12345678 . \ ad. = 32-Bit-Adresse, Stack-Eingabe als Punktzahl. \ c = Unteres Byte von 16-Bit-Zahl. Beispiel: 0034 von 1234 \ cc = Normale 16-Bit-Zahl. Beispiel: 1234, abgespeichert als 3412 \ d = 32-Bit-Wert, Ein- oder Ausgabe als Punktzahl code c@-32 ( ad. -- c ) \ Unmittelbares Byte c von Adresse ad. zum Stack ebx pop opsize: 0c1 c, 0c3 c, 10 c, ( 10 # ebx rol ) ax ax xor fs: adrsize: 8a c, 03 c, ( fs:[ebx] al mov ) 1push end-code code c!-32 ( c ad. -- ) \ Byte c vom Stack nach Adresse ad. speichern ebx pop opsize: 0c1 c, 0c3 c, 10 c, ( 10 # ebx rol ) ax pop fs: adrsize: 88 c, 03 c, ( al fs:[ebx] mov ) next end-code code cc@-32 ( ad. -- cc ) \ Doppelbyte cc von Adresse ad. zum Stack ebx pop opsize: 0c1 c, 0c3 c, 10 c, ( 10 # ebx rol ) fs: adrsize: 8B c, 03 c, ( fs:[ebx] ax mov ) 1push end-code code cc!-32 ( cc ad. -- ) \ Doppelbyte cc nach Adresse ad. speichern ebx pop opsize: 0c1 c, 0c3 c, 10 c, ( 10 # ebx rol ) ax pop fs: adrsize: 89 c, 03 c, ( ax fs:[ebx] mov ) next end-code code @-32 ( ad. -- d ) \ 32-Bit-Wert d von Adresse ad. zum Stack (32-Bit) ebx pop opsize: 0c1 c, 0c3 c, 10 c, ( 10 # ebx rol ) opsize: fs: adrsize: 8b c, 03 c, ( fs:[ebx] eax mov ) opsize: 0c1 c, 0c0 c, 10 c, ( 10 # eax rol ) eax push next end-code code !-32 ( d ad. -- ) \ 32-Bit-Wert d in 4 Bytes ab Adresse ad. legen ebx pop opsize: 0c1 c, 0c3 c, 10 c, ( 10 # ebx rol ) eax pop opsize: 0c1 c, 0c0 c, 10 c, ( 10 # eax rol ) opsize: fs: adrsize: 89 c, 03 c, ( eax fs:[ebx] mov ) next end-code \ Absicherung gegen RAM-Bereichs-Ueberschreitung \ ---------------------------------------------- \ Man achte auf fs (lineare Adressen erfordern 0 fs!). Dieser RAM-Test schleift \ beliebige Eingaben fuer ad. durch. Im weiter unten stehenden Forth-Wort \ getdiskimage wird vor der Fehlermeldung erst noch 161f00 hinzuaddiert, um \ sicherzustellen, dass das gesamte Disk-Image bis zu seinem Ende ins (wirklich \ vorhandene) RAM passt. Anschliessend erscheint wieder die Anfangsadresse auf \ dem Stack. : ramtest ( ad. -- ad./abort ) \ ad. = Punktzahl (doppeltgenau) fs@ -rot \ fs aufbewahren 2dup @-32 2swap \ (ad.) aufbewahren 5a5a5a5a. 2over !-32 2dup @-32 5a5a5a5a. d= -rot a5a5a5a5. 2over !-32 2dup @-32 a5a5a5a5. d= -rot 2swap and not >r 2swap 2over !-32 rot fs! r> cr abort" Bei dieser 32-Bit-Eingabe wird RAMmax ueberschritten!" ; \ Speicherbereich im 32-Bit-System dumpen \ --------------------------------------- \ Ohne das gleich folgende Wort dump-32 sind Analysen des vollen RAM-Bereichs \ kaum denkbar. Will man in einem 'RawWrite'- oder 'DiskCopy'-Verfahren das \ Disketten-Image im RAM (auf dem Kopierwege von Diskette zu Diskette) aendern \ oder/und anpassen, so kommt man mit diesem dump-32 und den obigen \ 32-Bit-@-und-!-Worten durch, und ich kann die weitere Aufbereitung dem Leser \ oder der Leserin ueberlassen. code 2tuck ( d1 d2 -- d2 d1 d2 ) eax pop ecx pop eax push ecx push eax push next end-code : d0<= ( d -- fl ) 0. d> not ; variable ascfilt \ Bei dump nur ASCII-Zeichen ausgeben ? ascfilt on \ Vorgabe: Ja variable fs-dump-32 \ Segment-Wert fuer dump-32 0 fs-dump-32 ! \ Vorgabe 0 (Speicher absolut linear) : ?ascii ( n1 -- n2 ) \ Nicht-ASCII-Zeichen --> Punkt ? ascfilt @ \ true = ja if dup 20 7e between not \ nicht ASCII ? if drop 2e then \ dann Punkt else dup 7 = \ Bell over 8 = or \ Del over a = or \ Linefeed over d = or \ cr over 1b = or \ esc over 0ff = or \ Bell usw. ? if drop bl then \ dann Blank then ; : dump^ ( -- ) ." 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF" ; : dump-32 ( ad. len. -- ) \ Stop: SPACE. Weiter: SPACE. Exit: CR CR cr >r >r >r >r fs@ fs-dump-32 @ fs! \ Mehr: + . Nochmal zurueck: - base @ hex r> r> r> r> 2over \ Anzeige in Hex 10 mu/mod 2drop >r 2swap r@ 0 d- r> dup 3 * dup 17 > if 1+ then 0a + (cursor) nip 0b swap at dump^ (cursor) nip at bold ." \/" 3c + (cursor) nip at ." V" attoff cr begin begin 2dup <# # # # # # # # # #> type space space \ Adresse anzeigen 8 0 do 2dup c@-32 0 <# # # #> type space 1. d+ loop space 8 0 do 2dup c@-32 0 <# # # #> type space 1. d+ loop space 10. d- 10 0 do 2dup c@-32 ?ascii emit 1. d+ loop cr 2swap 10. d- 2tuck d0<= stop? or \ Ende oder Abbruch ? until (cursor) dup 18 = if 0 0 at 0b spaces dump^ then at bold (cursor) -1 0 (frame) ." Weiter: + Zurueck: - Exit: RET" attoff at key dup ascii + = if drop 2swap 2drop 100. 2swap false else ascii - = if 2swap 2drop 100. 2swap 200. d- dark 0b 0 at dump^ cr false else 2drop 2drop base ! fs! true then then until 0c 0d (frame) cr ; \ ---------------------------------------------------------------------- hex \ Das folgende Wort (getdiskimage) ist die Vorstufe zu getdiskimage. In \ seinem Kern habe ich mich an (getdiskbootsect) aus dem Artikel 'Bootmanager \ und FAT-Reparatur: Vierter Fort(h)schritt (patchbares BIOS im RAM)' \ orientiert (siehe VD-Heft 2/2009). Fuer das Vorliegende wollte ich eine \ 3.5-Zoll-HD-Diskette 'am Stueck' ins RAM schreiben und von dort aus \ weiterverarbeiten und gegebenenfalls auch wieder in eine ebensolche oder \ dieselbe Diskette zurueckschreiben koennen. Meine Experimente mit dem \ erweiterten Interrupt 13h/42h brachten keinen Erfolg. Die Disketten liessen \ sich gar nicht erst ansprechen. Auch ein Versuch mit Int 25h verlief \ ergebnislos. Dabei hatte ich gedacht, mit meiner 4-Gigabyte-Erweiterung \ 'Real-Mode-32-Bit-Erweiterung fuer Turbo-Forth' aus dem Artikel im VD-Heft \ 2/1998 weiterzukommen [FB98]. Das vorliegende Programm arbeitet in 80d \ Bloecken, die jeweils noch auf Seite 0 und Seite 1 geschaltet werden koennen, \ zu je 18d Sektoren (das ist genau das Schema der 3.5-HD-Disketten, naemlich \ 80d Spuren (tracks) mit den Seiten (heads) 0 und 1 pro Spur zu je 18d \ Sektoren mit je 512d Bytes pro Sektor) im Real-Modus und kommt ohne \ 4-Gigabyte-Erweiterung im Sinne von [FB98] aus. \ (getdiskimage) uebertraegt den Inhalt einer 3.5-HD-Diskette sektorweise ins \ RAM, und zwar ab der in der 2Variablen imgbuf aufbewahrten Adresse. Diese \ Adresse kann (und muss) dem (das Low-Level-Wort (getdiskimage) enthaltenden) \ High-Level-Wort getdiskimage als Parameter mitgegeben werden. Das Wort \ ramtest liefert eine Absicherung gegen den moeglichen Fehler, in imgbuf eine \ Anfangs-Adresse anzugeben, die fuer den Disk-Image-Puffer nicht genuegend \ Platz uebrig laesst. \ imgbuf ist als Punktzahl (32 Bit) einzugeben! Der Wert 200000. waere ein \ guter Wert fuer den Beginn von Eigenexperimenten. Er liegt im RAM-Speicher \ als Adresse deutlich ueber 1 Megabyte und kann dort leicht an einem Stueck \ abgelegt werden, ohne anderen Vorhaben in die Quere zu kommen. Mit einfachen \ 16-Bit-Zahlen kaeme man, wie leicht ersichtlich, nicht durch. Der naechstgute \ Wert fuer Eigenexperimente waere dann 400000. (auch wieder Punktzahl). Mit \ 400000. bliebe dann das gesamte schon im ersten Experiment ermittelte \ Disk-Image im (erweiterten) RAM der Analyse zugaengig. Dann 600000. usw. Hat \ man mehr als 280 Megabyte RAM, dann koennte man das Disketten-Abbild \ natuerlich auch beispielsweise nach 10000000. legen - usw., alles hexadezimal \ gesehen. \ Zu beachten ist, dass in Code-Definitionen (auf einem PC-Kompatiblen) auch \ 32-Bit-Werte streng little-endian erscheinen muessen. Bei Punktzahlen in \ 16-Bit-Forth-Systemen (auf jeden Fall in Turbo-Forth) treten High- und \ Low-Anteil auf dem Stack (und auch in den 2Variablen und im RAM, was man per \ 12345678. pad 2! und dann pad 50 dump nachpruefen kann) in sich \ vertauscht auf. Genauer: Eine Tastatureingabe von 12345678. findet sich auf \ dem Stack (von den niedrigen Adressen her gesehen) als 43218765 wieder. Dabei \ beachte man dann noch, dass beim Ausdumpen (auf dem Bildschirm) die hoeheren \ Bits im Byte links stehen, dass die einzelnen Bytes (1 Byte = 2 Hexziffern) \ also (als Paar) so wiedergegeben werden, wie wir sie lesen, eben nicht in \ Little-Endian-Manier, sondern beispielsweise 43 zu lesen als 34, 21 als 12 \ usw. \ Im Uebrigen besteht auch die Moeglichkeit, im DOS-System (wo Turbo-Forth \ laeuft) eine RAM-Disk von guten 1.44d Megabyte einzurichten und dort eine \ (beliebige) Textdatei von 1.44 MB Laenge bereitzustellen. Das Abbild der \ Diskette (das Disk-Image) koennte man dann am Anfang dieser Datei beginnen \ lassen und haette zu ihrer Weiterverarbeitung die gesamte Datei-Organisation \ des DOS-Systems zur Verfuegung, in voller Laenge. Das waere dann also \ das, was man beispielsweise auch von Rawwrite erwarten wuerde. \ Es werden bei (getdiskimage) immer 18d Sektoren (eine Spur) von der Diskette \ in den (unterhalb von einem Megabyte, innerhalb eines 'normalen' Segmentes \ des DOS-Systems liegenden) Puffer trackbuf gelesen. Dann wird (jedesmal) der \ Inhalt von trackbuf ins 'Diskimage' (mit Anfangsadresse in der 2Variablen \ imgbuf) uebertragen. Das Ganze wiederholt sich 80d*2-mal (= Anzahl der Spuren \ auf einer 3.5-HD-Diskette mit jeweils Seite 0 und Seite 1). Die Nummer der \ jeweiligen Spur (mit 18d Sektoren) steht im Register ch. Die jeweilige Seite \ steht in dh und wird bei Uebertragung der jeweiligen Spur von Seite 0 auf 1 \ geschaltet und mit derselben Spur wiederholt. Spuren und Seiten sind ab 0 zu \ zaehlen, Sektoren werden (bei der in der Code-Definition (getdiskimage) \ verwendeten CHS-Auffassung ab 1 gezaehlt! ebx wird doppelbyteweise (je \ 16 Bit) per ebx inc ebx inc fortgeschaltet und enthaelt die Adresse des \ naechsten freien Bytes nach dem jeweils gerade uebertragenen Doppelbyte. \ Im RAM des urspruenglichen IBM-PCs (unterhalb der 1-Megabyte-Grenze) laesst \ sich keine ganze 3.5-HD-Diskette (1,44 MB) unterbringen. Also muss ein Puffer \ (unterhalb der 1-MB-Grenze) eingerichtet werden, der die Uebertragung der \ einzulesenden Disk portionsweise erledigt. Als 'Portionen' bieten sich die \ einzelnen Spuren der Diskette an, 80d an der Zahl. Pro Spur dann jeweils noch \ Seite 0 und 1. Pro Spur 18d Sektoren zu je 512d Bytes. Insgesamt sind das \ 80d * 2 * 18d * 512d = 50h * 2 * 12h * 200h = 168000h = 1474560d Bytes. \ Es folgt der 18d-Sektor-Puffer (unter dem Namen trackbuf). Bei Aufruf von \ trackbuf wird die Anfangsadresse dieses Puffers (als Punktzahl zu \ interpretieren) als Offset, bezogen auf das DSegment des gerade in Betrieb \ befindlichen Turbo-Forth-Systems, auf den Stack gelegt. 2410 allot here \ Platz fuer mindestens 18d Sektoren = 512d * 18d Bytes here 0f and - \ trackbuf an Paragraphenanfang 2400 - \ Anfang des Uebertragungs-Puffers constant trackbuf \ Liefert Anfangsadresse des Transfer-Puffers fuer 1 Spur hex \ Alle als Eingabe zu wertenden Zahlen in diesem Listing \ sind hexadezimal zu verstehen! \ Der RAM-Bereich zur Aufnahme des eigentlich interessierenden Puffers fuer \ das gesamte Disketten-Image kann mit der Eingabe xxxxxxxx. getdiskimage \ beliebig gewaehlt werden. Dabei wird im Vorliegenden keinerlei Ruecksicht auf \ irgendwelche RAM-Verwaltungen genommen. Allerdings wird bei der Eingabe (mit \ dem Wort ramtest) dafuer gesorgt, dass das Programm aussteigt, wenn versucht \ wird, RAM zu verwenden, das gar nicht vorhanden ist. Hier der Image-Puffer: 2variable imgbuf \ Enthaelt Anfangsadresse des Disk-Image-Puffers. Diese \ wird mit getdiskimage (als Punktzahl) eingegeben und \ steht auch nach dem Einlesen der Diskette (zur eventl. \ Bearbeitung des Disk-Images) weiterhin zur Verfuegung. 2variable imgbyte \ Enthaelt (als Punktzahl) die Adresse des zuletzt \ eingelesenen Doppelbytes. variable spur \ Letzte erreichte Spur variable seite \ Letzte erreichte Seite variable flag \ Fehler-Flag (0/1) fuer (getdiskimage) : 1 = Fehler \ Das Disketten-Laufwerk ist ein stark fehleranfaelliges Geraet, das viel \ Mechanik enthaelt. Im folgenden Wort (getdiskimage) habe ich deshalb eine \ Schleife mit drei Versuchen zur Abfrage eingebaut. Diese Schleife tritt bei \ jeder der 80d Spuren (zu je Seite 0 und Seite 1) einer einzulesenden \ 3.5-HD-Diskette in Aktion. Ob ein Fehler vorliegt, wird bei jeder Spur (pro \ Seite nach dem Lese-Interrupt 13h/2 durch Abfrage des Flag-Register-Bits cf \ ermittelt. Wenn es bis nach dem dritten Lese-Versuch nicht geklappt hat, \ bricht das Programm ab und hinterlaesst in den 2Variablen imgbuf und imgbyte \ und in den Variablen spur seite flag die bis dahin erreichten \ (Fehler-)Parameter. code (getdiskimage) ( -- ) ds push \ ds nach es uebertragen, es pop \ mit Stack als Zwischenstation. 3 # di mov \ Zaehler fuer drei Disketten-Leseversuche ansetzen. begin \ ------------- Bis zu 3 Leseversuche ------------- 0 # flag #) cmp 0<> \ ------------- Laufwerk initiieren ? ------------- if dl dl xor \ dl = 0 = Diskettenlaufwerk a: ah ah xor \ Funktion 0 von Int 13h aufrufen, also 13 int \ das Disketten-System zuruecksetzen. then \ ---------- Bemerkung hierzu siehe unten --------- \ --------- 1 Spur (18d Sektoren) einlesen -------- seite #) dh mov \ Seitennummer dieses Spurendurchgangs spur #) ch mov \ Spurennummer dieses Spurendurchgangs trackbuf \ 18d Sektoren (= 1 Spur = 9216d = 2400h Byte) einlesen # bx mov \ bx = Anfangs-Offset des Spur-Transfer-Puffers 1 # cl mov \ cl = Sektor 1 in der momentanen Spur (von 18d Sektoren) dl dl xor \ dl = 0 = Diskettenlaufwerk a: 2 # ah mov \ ah = 2 (Lesefunktion von Int 13h) 12 # al mov \ al = 12h = 18d Sektoren = 1 Spur von ch/dh einlesen 13 int \ Lese-Interrupt aufrufen. u>= if \ Wenn danach cf = 0 (kein Lesefehler), dann Aussprung di di xor \ aus der Schleife per di = 0 vorbereiten und 0 # flag #) mov \ flag = 0 (kein Fehler) setzen. else \ Wenn jedoch cf <> 0 (Lesefehler), di dec \ dann Zaehler fuer 3 Leseversuche dekrementieren 1 # flag #) mov \ und flag = 1 (Fehler) setzen. then 0 # di cmp 0= \ Aussprung aus der 3er-Schleife mit flag = 0 oder 1. until \ ------------------------------------------------- 0 # flag #) cmp 0= if \ di ist jetzt wieder frei verwendbar. trackbuf \ Anfang des Puffers zur Uebertragung der naechsten Spur # di mov \ nach di legen. imgbyte #) push \ Hi-Anteil der 2Variablen imgbyte auf den Stack legen. imgbyte 2 + #) push \ Lo-Anteil der 2Variablen imgbyte auf den Stack legen. ebx pop \ Disk-Image-Zeiger liegt jetzt little-endian in ebx. clc \ ------------------------------------------------- 1200 do \ trackbuf>imgbuf: 1200h = 4608d Doppelbytes = 9216 Bytes \ ------------------------------------------------- \ do-loop benoetigt cx als Zaehler. cl wird neu gesetzt. 0 [di] ax mov \ di = trackbuf (16 Bit). Keine edi-Erweiterung noetig. di inc \ ax uebertraegt ein Doppelbyte. Die Adresse di muss di inc \ sich also anschliessend um 2 erhoehen: di = di+2. adrsize: fs: \ Auf Segment fs bezogen und mit 32-Bit-Adressbreite. 89 c, 03 c, \ Das entspricht ax [ebx] mov (wegen adrsize). \ ------------------------------------------------- ebx inc \ ebx muss 1,44 Megabyte sammeln. bx allein wuerde nicht ebx inc \ genuegen. ax = 2 Bytes --> ebx = ebx + 2. loop \ ------------------------------------------------- ebx push \ Adresse des ersten freien Bytes nach dem zuletzt imgbyte 2 + #) pop \ eingelesenen Doppelbyte. Lo-Anteil davon forthrichtig imgbyte #) pop \ zur 2Variablen imgbyte legen, Hi-Anteil entsprechend. then \ ------------------------------------------------- next end-code \ -- Bemerkung zu int 13h/0 (Laufwerk initiieren) - \ Es klingt logisch, das Disketten-Laufwerk vor dem Lesen \ einer jeden weiteren Spur (davon enthaelt die 3.5-Disk \ 80d pro Seite, also 160d Stueck) 'vorsichtshalber' \ frisch zu initiieren. Das hatte ich urspruenglich so \ gemacht. Das vom Laufwerk dabei erzeugte Geraeusch war \ nicht zu ueberhoeren. Und man spuerte foermlich, wie \ der Laufwerk-Mechanismus bei jeder Spur nochmal \ 'nachfassen' musste. Die jetzt gefundene Loesung ist \ wesentlich besser: Das Laufwerksgeraeusch ist kaum noch \ wahrnehmbar, kaum merklich lauter als der Luefter. Die \ einzelnen Spuren fuegen sich geschmeidig aneinander - \ und verloren geht nichts, da ja im Fehlerfall erst zwei \ weitere Leseversuche vorgenommen werden, bevor das \ System einen Fehler vermeldet und aussteigt. : printparams ( -- ) \ Ausdruck von flag-Meldung imgbuf imgbyte seite spur cr cr ." =================================================" cr flag @ 1 = if ." Fehler beim Einlesen des Disketten-Abbildes" cr then flag @ 0 = if ." Die Diskette wurde ohne Lesefehler eingelesen" cr then ." -------------------------------------------------" cr ." Erstes eingelesenes Byte an RAM-Adresse : " imgbuf 2@ ud. cr ." Letztes eingelesenes Byte an RAM-Adresse : " imgbyte 2@ 1. d- ud. cr ." Letzte Seite; oder erste, die Fehler hat : " seite @ u. cr ." Letzte Spur ; oder erste, die Fehler hat : " spur @ u. cr ." -------------------------------------------------" cr ." Falls Sp/S = 0/0 : Wirklich Diskette im Laufwerk?" cr ." =================================================" cr cr ; : getdiskimage ( imgbuf -- ) 0 fs! \ Disk-Image im RAM auf f-Segment = 0 beziehen. 161f00. d+ \ Laenge der Diskette (in Bytes) hinzuaddieren. ramtest \ Passt das Disk-Image ueberhaupt ins RAM? 161f00. d- \ Wieder zum Anfang des Disk-Image-Puffers gehen. 2dup \ Zunaechst lege ich den imgbuf 2! \ Anfang des Disk-Image-Puffers in die 2Variable imgbuf imgbyte 2! \ und dann (zunaechst auch) in die 2Variable imgbyte. 0 spur ! \ Letzte erreichte Spur zunaechst auf 0 setzen. 0 seite ! \ Letzte erreichte Seite zunaechst auf 0 setzen. 0 flag ! \ Fehler-Flag zunaechst auf 0 setzen. begin (getdiskimage) seite @ 0 = \ Spuren- und Seitenzaehlung beginnt bei 0. Seiten: 0/1. if \ Wenn bei einer bestimmten Spur die Seite auf 0 steht, 1 seite ! \ dann Seite auf 1 schalten und Spur beibehalten. else \ Ansonsten steht die Seite auf 1. 0 seite ! \ Dann Seite wieder auf 0 setzen spur 1+! \ und Spur (es gibt 50h davon) weiterschalten. then spur @ 50 = \ Verwendbare Spuren: 0-4f. Wenn 50h erreicht ist, flag @ 0<> or \ oder auch schon vorher, wenn naemlich ein Fehler until \ aufgetreten ist, dann begin-until-Schleife verlassen. seite @ 1 = \ Spuren- und Seiten-Fortschaltung rueckgaengig machen. if \ if-then hier analog zu if-then eben. 0 seite ! else 1 seite ! spur 1-! then printparams ; \ Bildschirm-Ausgabe der (Fehler-)Parameter. \ =======================================================================