PROGRAM installieren_des_eumel_shards ; {$U-} CONST vers = '2.1 vom 22.01.87' ; shard_file = 'EUMEL.COM' ; floppy_boot_file = 'FBOOT.COM' ; conf_offset = $37 ; { Anfang ohne LOAD-Modul (phys.-Adr $00000) } { 2.1: 22.01.87 mit Pascal SCSI-Routinen & Konfiguration } {$I SCSI.PAS} TYPE SECTOR = ARRAY[0..255] OF BYTE ; FLAGTYPE = SET OF (x0, x1, x2, x3, autoboot, curvol, b64180, b6502) ; IDTYPE = (free, ucsd, dos, cpm, prodos, id5, eumel, id7, id8, id9, id10, id11, id12, id13, id14, spare) ; STRING15 = STRING[15] ; LUN = RECORD drive, high, low : BYTE END ; DISKENTRYTYPE = RECORD entrylength : BYTE ; first_block : LUN ; reserved : BYTE ; last_block : LUN ; { exclusiv } params : ARRAY [0..7] OF BYTE ; name : STRING15 ; volumes : BYTE ; { Anzahl Volumes } autoboot : CHAR ; { Volumekennzeichen fuer Autoboot } waittime : INTEGER ; { Wartezeit vor Autoboot in 1.46ms } END ; VOLUMEENTRYTYPE = RECORD flags : FLAGTYPE ; first : LUN ; kz : CHAR ; { Kennzeichen in der VOLTAB } last : LUN ; { Letzer Block exclusiv } params: ARRAY[0..7] OF BYTE ; name : STRING15 ; loadpage : BYTE ; { Highbyte Ladeadresse im 6502-Memory } jumppage : BYTE ; { Highbyte Startadresse im 6502-Memory } pages : BYTE ; { Anzahl zu ladender Seiten } volid : IDTYPE ; END ; VAR f : FILE ; floppy_version : BOOLEAN ; shard_size, volume : INTEGER ; volume_name, scsi_floppy : STRING15 ; buffer : ARRAY[0..$3F] OF SECTOR ; boot_buffer: ARRAY[0..15] OF SECTOR ; conf : RECORD offset : ARRAY[1..conf_offset] OF BYTE ; umsch : ARRAY[1..8] OF BYTE ; blinkp : BYTE ; { Cursor Blinkfrequenz in 50ms } beepfreq: BYTE ; { Kanal 1: Beepfrequenz } arc31 : LUN ; { SCSI-Floppy LUN } mode : INTEGER ; { EUMEL-MODE-Word } id4 : INTEGER ; { Lizenznummer des SHards } id5 : INTEGER ; { Installationsnummer des SHards } id6 : INTEGER ; { Reserviert fuer SHard } urlk1 : BYTE ; { Primaerer Urladerkanal } urlk2 : BYTE ; { Sekundaerer Urladerkanal } free : BYTE ; irqvecs : ARRAY[1..$40] OF BYTE ; { Interruptvektoren } ikantab : ARRAY[0..7] OF BYTE ; { phys. --> log. Kanalnr. } kantab : ARRAY[0..32] OF BYTE ; { log. --> phys. Kanalnr. } ioftb : ARRAY[0..31] OF BYTE ; { 'typ'-Bits der Kanaele } cpmofs : LUN ; { LUN & Anfangs-Adr. eines CP/M-Volumes } cpmlast : LUN ; { LUN & Endadr. (excl.) eines CP/M-Volumes } END ABSOLUTE buffer ; superdirectory : RECORD diskentry : DISKENTRYTYPE ; volumeentry : ARRAY[1..26] OF VOLUMEENTRYTYPE ; END ; PROCEDURE errorstop (message : STRING77) ; BEGIN writeln ; writeln (#7, 'FEHLER: ', message) ; halt END { errorstop } ; FUNCTION yes (question : STRING77) : BOOLEAN ; VAR zeichen : CHAR ; CONST answer : SET OF CHAR = ['y', 'Y', 'n', 'N', 'j', 'J'] ; BEGIN WHILE keypressed DO read (KBD, zeichen) ; { empty buffer } write (question, ' (j/n) ? ') ; REPEAT read (KBD, zeichen) ; IF zeichen = #27 THEN errorstop ('Abbruch mit ESC') ; IF NOT (zeichen IN answer) THEN write (#7) ELSE writeln (zeichen) UNTIL zeichen IN answer ; yes := zeichen IN ['y', 'Y', 'j', 'J'] END { yes } ; FUNCTION txt (nr : INTEGER) : STRING15 ; VAR result : STRING15 ; BEGIN str (nr, result) ; txt := result END { txt } ; PROCEDURE shard_lesen ; BEGIN fillchar (buffer, sizeof (buffer), 0) ; assign (f, shard_file) ; reset (f) ; shard_size := filesize (f) ; blockread (f, buffer, shard_size) ; close (f) ; IF (shard_size < 3) OR (shard_size > 2 * $3F) THEN errorstop ('Die Datei ' + shard_file + ' ist inkonsistent!') END { shard_lesen } ; PROCEDURE shard_schreiben ; VAR eumel_track : INTEGER ; BEGIN WITH superdirectory.volumeentry[volume].first DO BEGIN eumel_track := low DIV 32 + high * 8 + (drive AND $3F) * 2048 END ; hd_write (buffer, eumel_track * 32, 32) ; hd_write (buffer[32], succ (eumel_track) * 32, 32) END { shard_schreiben } ; PROCEDURE eumel_volume_suchen ; VAR name : STRING[255] ; BEGIN volume := 1 ; WITH superdirectory DO BEGIN WHILE volume <= diskentry.volumes DO BEGIN IF volumeentry[volume].volid = eumel THEN IF yes ('SHard auf Volume "' + volumeentry[volume].name + '" installieren') THEN exit ; volume := succ (volume) ; END { WHILE } ; writeln ('Kein (weiteres) EUMEL-Volume gefunden.') ; IF yes ('Soll ein anderes Volume zu einem EUMEL-Volume werden') THEN BEGIN volume := 1 ; WHILE volume <= diskentry.volumes DO BEGIN IF volumeentry[volume].volid <> spare THEN IF yes ('SHard auf Volume "' + volumeentry[volume].name + '" installieren') THEN BEGIN IF yes ('Volumename aendern') THEN BEGIN write ('Neuer Volumename: ') ; REPEAT readln (name) ; IF length (name) > 15 THEN writeln ('Zu lang!') UNTIL (name <> '') AND (length (name) < 16) ; volumeentry[volume].name := name ; END ; exit ; END ; volume := succ (volume) END { WHILE } ; writeln ('Kein (weiteres) Volume gefunden.') ; END { IF } ; writeln ('Installation abgebrochen.') ; halt END { WITH } END { eumel_volume_suchen } ; PROCEDURE superdirectory_lesen ; BEGIN hd_read (superdirectory, 2, 4) ; END { superdirectory_lesen } ; PROCEDURE superdirectory_schreiben ; BEGIN WITH superdirectory.volumeentry[volume] DO BEGIN flags := [b64180] ; (* Boot in 64180-Code geschrieben *) loadpage := $10 ; jumppage := loadpage ; pages := $3F ; (* Da $40 nicht geht (Timeout auf Cylindergrenze) *) volid := eumel ; END ; hd_write (superdirectory, 2, 4) END { superdirectory_schreiben } ; FUNCTION sector_write (trk, sec, adr : INTEGER) : BOOLEAN ; BEGIN bios (9, trk) ; bios (10, sec) ; bios (11, adr) ; sector_write := (bios (13, 0) = 0) ; END ; PROCEDURE shard_auf_floppy_schreiben ; VAR trk, sec, curdrv, drive : INTEGER ; zeichen : CHAR ; BEGIN fillchar (boot_buffer, sizeof (boot_buffer), 0) ; assign (f, floppy_boot_file) ; reset (f) ; blockread (f, boot_buffer, filesize (f)) ; { max. 4k Boot } close (f) ; boot_buffer[0][$FF] := 0 ; WHILE boot_buffer[0][$FF] = 0 DO BEGIN IF yes ('2 * 80 Track (Erphi) Format') THEN boot_buffer[0][$FF] := $E0 ELSE IF yes ('1 * 35 Track (Apple) Format') THEN boot_buffer[0][$FF] := $81 ELSE IF yes ('2 * 80 Track (Ehring) Format')THEN boot_buffer[0][$FF] := $A0 ; END ; curdrv := bdos (25, 0) ; { current_drive } drive := curdrv ; write ('Floppy-Drive (Abbruch mit ESC): ', chr (drive + 65), #8) ; REPEAT read (KBD, zeichen) ; IF zeichen = #27 THEN errorstop ('Abbruch mit ESC') ; zeichen := upcase (zeichen) ; IF NOT (zeichen IN ['A'..'P']) THEN write (#7) ELSE writeln (zeichen) UNTIL zeichen IN ['A'..'P'] ; drive := ord (zeichen) - 65 ; IF drive = curdrv THEN REPEAT UNTIL yes ('(Leere) Destinationdiskette eingelegt') ; writeln ; bios (8, drive) ; { Select Floppy Drive } FOR sec := 0 TO 15 DO { Floppy-Boot/Taskloop schreiben } IF NOT sector_write (0, sec, addr (boot_buffer [sec])) THEN BEGIN bios (8, curdrv) ; errorstop ('Schreibfehler auf Drive ' + zeichen + ':, Track 0, Sektor ' + txt (sec)) END ; FOR trk := 1 TO 4 DO { SHard schreiben } FOR sec := 0 TO 15 DO IF NOT sector_write (trk, sec, addr (buffer [sec + pred(trk) * 16])) THEN BEGIN bios (8, curdrv) ; errorstop ('Schreibfehler auf Drive ' + zeichen + ':, Track ' + txt (trk) + ', Sektor ' + txt (sec)) END ; bios (8, curdrv) ; { Select previous Drive } END ; PROCEDURE cpm_volume_suchen ; BEGIN WITH superdirectory DO BEGIN REPEAT volume := 1 ; WHILE volume < diskentry.volumes DO BEGIN IF volumeentry[volume].volid = cpm THEN IF yes (volumeentry[volume].name) THEN exit ; volume := succ (volume) ; END UNTIL yes ('Kein (weiteres) Volume gefunden, erstes Volume nehmen') ; volume := 1 ; writeln ('Volume "', volumeentry[volume].name, '" wird angenommen.') ; END END { cpm_volume_suchen } ; PROCEDURE kanalzuordnungen ; VAR i, j, channel : INTEGER ; ok : BOOLEAN ; FUNCTION kanal_erfragen (log : INTEGER) : INTEGER ; VAR channel : INTEGER ; BEGIN REPEAT channel := 255 ; write (' ':77, #13) ; write ('Logischer Kanal ', log:2, ' ---> physischer Kanal: -'#8) ; buflen := 2 ; read (channel) ; write (#13) ; UNTIL ((channel >= 0) AND (channel < 7)) OR ((channel >= 28) AND (channel < 32)) OR (channel = 255) ; kanal_erfragen := channel END ; PROCEDURE message (msg : STRING77) ; VAR zeichen : CHAR ; BEGIN write (#13, ' ', msg, ' - Taste -'#13) ; read (KBD, zeichen) END { message } ; BEGIN { kanalzuordnungen } REPEAT clrscr ; writeln ('--- Zuordnung der logischen/physischen Kanaele ---') ; writeln ; writeln ('Den logischen Kanaelen werden physische Kanaele zugeordnet,') ; writeln ('dabei sind folgende Einschraenkungen zu beachten:') ; writeln ('- Kanal 0 und 31 muessen als Blockkanal definiert werden.') ; writeln ('- Kanal 1 muss als Streamkanal definiert werden (Systemstart).') ; writeln ('- Kein physischer Kanal darf mehrfach zugeordnet werden.') ; writeln ; writeln ('Folgende physische Kanaele stehen zur Verfuegung:') ; writeln ; writeln ('Streamkanaele: Blockkanaele:') ; writeln ('-------------- -------------') ; writeln ('1 ... Basis - Konsole 0 ... SCSI - Harddisk #0') ; writeln ('2 ... ruc180 - Serielle B ( 1 ... Basis - Graphikkonsole)') ; writeln ('3 ... ruc180 - Serielle A 28 ... SCSI - Volume "', volume_name, '"') ; writeln ('4 ... ruc180 - Centronics 29 ... Basis - Diskdrive 1') ; writeln ('5 ... Basis - Serielle 30 ... Basis - Diskdrive 0') ; writeln ('6 ... Basis - Centronics 31 ... SCSI - ', scsi_floppy) ; writeln ; conf.kantab[32] := 32 ; { Parameterkanal } writeln ; FOR i:= 0 TO 31 DO BEGIN REPEAT REPEAT channel := kanal_erfragen (i) ; ok := FALSE ; IF channel = 255 THEN IF (i = 0) OR (i = 1) OR (i = 31) THEN message ('Kanal 0, 1 und 31 muessen definiert werden!') ELSE ok := TRUE ELSE IF ((i = 0) OR (i = 31)) AND ((conf.ioftb[channel] AND 12) <> 12) THEN message ('Kanal ' + txt (i) + ' muss ein Blockkanal (0, 28..31) sein!') ELSE IF (i = 1) AND ((conf.ioftb[channel] AND 3) <> 3) THEN message ('Kanal 1 muss ein Stream I/O-Kanal sein!') ELSE ok := TRUE UNTIL ok ; IF channel <> 255 THEN BEGIN j := 0 ; WHILE (j < i) AND (conf.kantab[j] <> channel) DO j := succ (j) ; IF j < i THEN message ('Der phys. Kanal ' + txt(channel) + ' wurde schon dem log. Kanal ' + txt (j) + ' zugeordnet!') ; END ; UNTIL (j = i) OR (channel = 255) ; conf.kantab[i] := channel ; { Zuordnung log. --> phys. } IF channel < 7 THEN conf.ikantab[channel] := i ; { Zuordnung phys. --> log. } END ; clrscr ; writeln ('So sind die physischen Kanaele den logischen Kanaelen zugeordnet:') ; FOR i:= 0 TO 31 DO BEGIN gotoxy (succ ((i DIV 16) * 40), 3 + (i MOD 16)) ; write (i:2, ': ') ; CASE conf.kantab[i] OF 0 : write ('SCSI - Harddisk #0') ; 1 : write ('Basis - Konsole') ; 2 : write ('ruc180 - Serielle B') ; 3 : write ('ruc180 - Serielle A') ; 4 : write ('ruc180 - Centronics') ; 5 : write ('Basis - Serielle') ; 6 : write ('Basis - Centronics') ; 28 : write ('SCSI - Volume "', volume_name, '"') ; 29 : write ('Basis - Diskdrive 1') ; 30 : write ('Basis - Diskdrive 0') ; 31 : write ('SCSI - ', scsi_floppy) ; 255 : write (' -') END { CASE } ; END ; writeln ; writeln ; UNTIL yes ('Alle Kanal-Zuordnungen korrekt') ; END { kanalzuordnungen } ; PROCEDURE konfigurieren ; VAR freq : REAL ; BEGIN writeln ; writeln ('************************* Systemstart - Parameter ************************') ; writeln ; IF yes ('EUMEL-Vortest beim Systemstart') THEN IF NOT yes ('Speichertest durchfuehren') THEN conf.mode := $0100 ELSE conf.mode := 0 ELSE conf.mode := $0200 ; writeln ; conf.urlk1 := 31 ; conf.urlk2 := 0 ; IF NOT yes ('Soll der Urlader zuerst auf dem Archivkanal gesucht werden') THEN BEGIN conf.urlk1 := 0 ; conf.urlk2 := 31 END ; writeln ; writeln ('**************** Parameter der Konsole (phys. Kanal 1) ******************') ; writeln ; freq := conf.blinkp * 0.1 ; write ('Cursor Blinkperiode (s) : ', freq:2:1, #8#8#8#8) ; REPEAT readln (freq) UNTIL (freq >= 0.05) AND (freq <= 25.5) ; conf.blinkp := round (freq * 10.0) ; writeln ; freq := int (5000.0/conf.beepfreq + 0.5) ; write ('Tonfrequenz bei Bell (Hz): ', freq:4:0, #8#8#8#8) ; REPEAT readln (freq) UNTIL freq >= 1.0 ; conf.beepfreq := round (5000.0/freq) ; writeln ; IF NOT floppy_version THEN BEGIN writeln ('********** Parameter fuer Harddisk-Volume (phys. Kanal 28) **************') ; writeln ; writeln ('Welches CP/M-Volume soll angesprochen werden ?') ; cpm_volume_suchen ; conf.cpmofs := superdirectory.volumeentry[volume].first ; conf.cpmlast := superdirectory.volumeentry[volume].last ; volume_name := superdirectory.volumeentry[volume].name ; END ELSE volume_name := '(1. Volume)' ; writeln ; writeln ('************* Parameter fuer SCSI-Floppy (phys. Kanal 31) ****************') ; writeln ; conf.arc31.drive := $60 ; scsi_floppy := 'Floppy #1' ; IF yes ('SCSI-Floppy #0 statt SCSI-Floppy #1') THEN BEGIN conf.arc31.drive := $40 ; scsi_floppy := 'Floppy #0' END ; writeln ; IF yes ('Zuordnung der logischen/physischen Kanaele aendern') THEN kanalzuordnungen ; writeln ; writeln ; END { konfigurieren } ; BEGIN { MAIN } clrscr ; writeln (' EUMEL-SHard Installation') ; writeln (' Version ', vers) ; writeln (' (c) M. Staubermann (ruc)') ; writeln ; writeln ; IF yes ('SHard auf der Harddisk installieren') THEN BEGIN floppy_version := FALSE ; shard_lesen ; superdirectory_lesen ; IF yes ('SHard-Defaults aendern') THEN konfigurieren ; eumel_volume_suchen ; shard_schreiben ; superdirectory_schreiben ; writeln ('SHard erfolgreich auf Harddisk installiert.') END ELSE IF yes ('SHard auf einer (CP/M-)Floppy installieren') THEN BEGIN floppy_version := TRUE ; shard_lesen ; IF yes ('SHard-Defaults aendern') THEN konfigurieren ; shard_auf_floppy_schreiben ; writeln ('SHard erfolgreich auf Floppy installiert.') END ELSE writeln ('Kein SHard installiert.') END.