(* SHard-Patcher fuer Schoenbeck AT-Shard V2.7: - Vortest/Speichertest - Keyboard Repeatfrequenz - Baudrates 19200/38400 werden angeboten - Refresh-Intervall änderbar (bis zu 5% mehr Leistung) - control (-3,,,r) liefert im Highbyte das Modemstatusregister (RI etc.) - control (-5,8,,r) geht in ruc-Bios-Graphikmodus (mit Textausgabe: Text mit 'out', 'put' etc. schreiben, cursor (x, y) mit y:1..43, Codes ""4"", ""5"", Scroll löschen jetzt vernünftig (Attribut von 7 auf 0 geändert), Achtung: getcursor (x, y) im 'begin plot' einbauen. cursor (x,y) im 'end plot' einbauen, wegen y<25 im Textmodus!) - Kanal 30 (Archiv 1) jetzt für MF-Laufwerke (5.25" bzw. 3.5"), Default- Size ist 1.2MB (Achtung bei Formatieren von 3.5"-Floppys!) - Mit control (-10/-11,...) ("stop", "weiter") wird an den RS232-Kanälen jetzt nicht nur RTS active/inactive gesetzt sondern auch DTR (Modem). - An Kanal 32: Mit control (-3, x, mcr*32+kanal, r) (mcr ist Modemcontrolregister Wert, x egal) können RTS, DTR explizit gesetzt werden. - id (6) > 0 : SHard wurde gepatcht. Michael Staubermann, Version 2: 09.10.87, Keyboardrepeat, Baudrates Version 3: 04.11.87, Graphikcursor & Graphikmodi Version 3.1: 20.11.87, >32MB Partitionen f. M+ Version 4: 04.12.87, TX-Interrupt restart Version 4.1: 10.01.88, Refresh-Intervall änderbar Version 5: 21.02.88, Kanal 30 1.2MB-Format (3.5") Version 5.1: 22.02.88, *) LET setup channel = 28 ; LET max partitions = 4 , patch version = 5 , shard bloecke = 18 ; patch shard ; ROW shard bloecke ROW 256 INT VAR block ; ROW shard bloecke BOOL VAR modified ; INT VAR old session := 0 ; REAL VAR partition size := 0.0, partition start 1 := 256.0 * 65536.0 -1.0 ; INT VAR i ; FOR i FROM 1 UPTO shard bloecke REP modified (i) := FALSE PER ; ROW 256 INT VAR partition table ; INT OP & (TEXT CONST hex) : INT VAR i, h := 0 ; IF LENGTH hex > 4 THEN errorstop ("OP &: LENGTH > 4") FI ; FOR i FROM 1 UPTO LENGTH hex REP rotate (h, 4) ; INT CONST c :: code (hex SUB i) ; IF c >= 97 AND c <= 102 THEN h := h OR (c-87) ELIF c >= 65 AND c <= 70 THEN h := h OR (c-55) ELIF c >= 48 AND c <= 57 THEN h := h OR (c-48) ELSE errorstop ("OP &: ungültiges Hexdigit ("+code(c)+")") FI ; PER ; h ENDOP & ; TEXT OP % (INT CONST int) : LET hex = "0123456789ABCDEF" ; TEXT VAR t := "" ; INT VAR i, r := int ; FOR i FROM 1 UPTO 4 REP rotate (r, 4) ; t CAT (hex SUB ((r AND 15)+1)) ; PER ; t ENDOP % ; PROC poke (INT CONST shard adr, INT CONST byte) : (* Der Shard beginnt bei 1280 d.h. 0500H, EUCONECT bei 504H (='EUMEL') *) INT VAR block no, block offset ; IF shard adr < 256 THEN errorstop ("poke: Adresse < 256") ; LEAVE poke FI ; block offset := shard adr-256 ; rotate (block offset, -1) ; block offset := (block offset AND 255) + 1 ; block no := shard adr - 256 ; rotate (block no, -9) ; block no := (block no AND 63) + 1 ; IF block no < 1 OR block no > shard bloecke THEN errorstop ("poke: falsche Adresse") ; LEAVE poke FI ; TEXT VAR t := " " ; replace (t, 1, block (block no)(block offset)) ; replace (t, (shard adr AND 1) + 1, code (byte AND 255)) ; modified (block no) := TRUE ; block (block no)(block offset) := t ISUB 1 ; ENDPROC poke ; PROC poke2 (INT CONST shard adr, INT CONST word) : INT VAR r := word ; poke (shard adr, r) ; rotate (r, 8) ; poke (shard adr+1, r) ; ENDPROC poke2 ; PROC poken (INT CONST shard adr, TEXT CONST str) : INT VAR i, adr := shard adr ; i := 1 ; WHILE i <= LENGTH str REP IF (str SUB i+2) = " " OR (str SUB i+2) = "" THEN poke (adr, &subtext (str, i, i+1)) ; i INCR 3 ; adr INCR 1 ELIF (str SUB i+4) = " " OR (str SUB i+4) = "" THEN poke2 (adr, &subtext (str, i, i+3)) ; i INCR 5 ; adr INCR 2 ELSE errorstop ("poken: Zuviele zusammenhängende Bytes") FI ; PER ; ENDPROC poken ; INT PROC peek (INT CONST shard adr) : INT VAR block no, block offset ; block offset := shard adr ; IF shard adr < 256 THEN errorstop ("peek: Adresse < 256") ; LEAVE peek WITH 0 FI ; block offset := shard adr-256 ; rotate (block offset, -1) ; block offset := (block offset AND 255) + 1 ; block no := shard adr-256 ; rotate (block no, -9) ; block no := (block no AND 63) + 1 ; IF block no < 1 OR block no > shard bloecke THEN errorstop ("peek: falsche Adresse") ; LEAVE peek WITH 0 FI ; TEXT VAR t := " " ; replace (t, 1, block (block no)(block offset)) ; code (t SUB ((shard adr AND 1) + 1)) ENDPROC peek ; INT PROC peek2 (INT CONST shard adr) : INT VAR r := peek (shard adr + 1) ; rotate (r, 8) ; r + peek (shard adr) ENDPROC peek2 ; PROC get partition : INT VAR partition, cyls, heads, secs ; get media size (setup channel, cyls, heads, secs) ; get partition table ; get partition number from user ; line ; IF (partition size high AND -256) <> 0 OR (partition start high AND -256) <> 0 THEN errorstop ("Sorry, Partitionsangaben zu hoch") FI ; line ; partition start1 := real24 (partition start high, partition start low)-1.0; partition size := real24 (partition size high, partition size low) ; putline ("Platte hat " + text (cyls) + " Cylinder, " + text (heads) + " Heads, " + text (secs) + " Sektoren = " + text (real(cyls)*real(heads)*real(secs)/2048.0, 5, 1) + " MB") ; putline ("Partionsanfang: " + text ((partition start 1+1.0)/2.0, 6, 0) + " KB = Cylinder " + text (int ((partition start 1+1.0)/real(secs)/real(heads)))) ; putline ("Partionsgrösse: " + text (partition size/2.0, 6, 0) + " KB = " + text (int (partition size/real(secs)/real(heads))) + " Cylinder"); put ("Diese Partition ist") ; IF NOT partition active THEN put (""15"nicht"14"") FI ; putline ("aktiviert.") ; line . get partition table : blockin (setup channel, partition table, 0.0) . get partition number from user : FOR partition FROM 1 UPTO max partitions REP IF eumel partition CAND yes ("EUMEL-Partiton " + text (partition type) + " patchen") THEN LEAVE get partition number from user FI PER ; partition := 0 ; errorstop ("Keine EUMEL Partition gefunden") . eumel partition : partition type >= 69 AND partition type <= 72 . entry : 216 + partition * 8 . partition active : bit (partition table (entry), 7) . partition type : partition table (entry + 2) AND 255 . partition start low : partition table (entry + 4) . partition start high: partition table (entry + 5) . partition size low : partition table (entry + 6) . partition size high: partition table (entry + 7) . ENDPROC get partition ; PROC read shard : INT VAR i ; old session := session ; FOR i FROM 1 UPTO shard bloecke REP cout (i) ; modified (i) := FALSE ; blockin (setup channel, block (i), partition start1 + real(i-1)) PER ; ENDPROC read shard ; PROC write shard : INT VAR i ; FOR i FROM 1 UPTO shard bloecke REP IF modified (i) THEN IF session <> old session THEN errorstop ("RERUN während patch") FI ; blockout (setup channel, block (i), partition start1+real(i-1)) ; modified (i) := FALSE FI ; cout (i) PER ENDPROC write shard ; REAL PROC real24 (INT CONST high, low) : real (high) * 65536.0 + low real . low real : IF low < 0 THEN real (low) + 65536.0 ELSE real (low) FI ENDPROC real24 ; PROC split real24 (REAL CONST r, INT VAR high, low) : high := int (r/65536.0) ; low := (code (int (r MOD 256.0)) + code (int ((r MOD 65536.0)/256.0))) ISUB1 ENDPROC split real24 ; PROC patch shard : get partition ; read shard ; check if patch possible ; patch baudrate ; patch id and mode ; patch typematic ; patch refresh ; patch modem status ; patch cursor maxima ; patch attribute bytes ; patch out restart ; patch dtr inactive ; patch mcr set routine ; patch archive 1 format ; IF yes ("Änderungen permanent machen") THEN write shard ; putline ("Änderungen durchgeführt, System neu booten.") ; ELSE putline ("Keine Änderungen durchgeführt.") ; FI . check if patch possible : IF peek2 (&"0300") <> &"05EA" THEN errorstop ("Partition enthaelt keinen SHard") ELSE IF peek2 (shard ver) <> 7 THEN errorstop ("Dies ist die falsche SHard-Version") ELIF peek2 (id6) = patch version THEN putline ("Hinweis: Dieser SHard wurde bereits gepatcht") ELIF peek2 (id6) <> 0 THEN putline ("Der SHard-Patch wird upgedated") FI FI . shard ver: &"0554" . mode: &"0556" . id 6: &"055C" . patch baudrate : putline ("Baudrates 50, 75 entfernt, 19200, 38400 eingefügt.") ; poke2 (&"07E8", 1047) ; (* 3: 110 *) poke2 (&"07EA", 857) ; (* 4: 134.5 *) poke2 (&"07EC", 768) ; (* 5: 150 *) poke2 (&"07EE", 384) ; (* 6: 300 *) poke2 (&"07F0", 192) ; (* 7: 600 *) poke2 (&"07F2", 96) ; (* 8: 1200 *) poke2 (&"07F4", 64) ; (* 9: 1800 *) poke2 (&"07F6", 48) ; (* 10: 2400 *) poke2 (&"07F8", 32) ; (* 11: 3600 *) poke2 (&"07FA", 24) ; (* 12: 4800 *) poke2 (&"07FC", 16) ; (* 13: 7200 *) poke2 (&"07FE", 12) ; (* 14: 9600 *) poke2 (&"0800", 6) ; (* 15: 19200 *) poke2 (&"0802", 3) ; (* 16: 38400 *) (* Korrektur der Adressoffsetberechnung auf Baudtable *) (* Maschinencode nicht veraendern! 08F4: i8250_baud: CMP BH,17 JNC i8250_not_ok CMP BH,3 JC i8250_not_ok .... 0918: MOV AX,WORD PTR i8250_baud_table-6[BX] *) poken (&"08F4", "17 73 75 80 FF 03 72 70") ; poken (&"0918", "87 E2") . patch id and mode : poke2 (id6, patch version) ; (* Update Patch Version *) IF yes ("Soll ein Vortest durchgeführt werden") THEN IF yes ("Soll ein Speichertest durchgefuehrt werden") THEN poke2 (mode, 0) ELSE poke2 (mode, 256) FI ELSE poke2 (mode, 512) FI . patch modem status: poke (&"0A5D", 6) . (* Modem Status Register Offset = 6 *) patch typematic: (* Nur mit ruc-Bios *) INT VAR typematic ; IF yes ("Schneller Keyboardrepeat") THEN typematic := 4 (* Fast *) ELSE typematic := 2 * 256 + 12 (* Standard *) FI ; (* Maschinencode, nicht veraendern! 0E20: XOR AX,AX ; Set Default Video Mode INT 10H MOV AX,0342 ; Set Typematic + Marwin MOV BX,typematic ; BH = Delay (0..3), BL = Rate (0..31) INT 16H 0E2C: MOV AL,54H ; Ab hier in 'patch refresh' OUT [43H],AL ; JMP $+2 ; MOV AL,interval ; interval = 1.19 * us OUT [41H],AL ; RET ; End pc_init *) poken (&"0E20", "33 C0 CD 10 B8 42 03 BB " + %typematic + " CD 16 C3") . (* RET wird ueberschrieben von Refresh *) patch refresh: INT VAR refresh ; TEXT VAR ref := "15.126" ; line ; putline ("215us Refresh-Intervall bringen 5% mehr RAM-Performance.") ; putline ("Achtung: Nicht bei allen RAMs moeglich (z.B. 120ns Toshiba nicht).") ; put ("RAM-Refresh Intervall (in us):") ; editget (ref) ; line ; refresh := int (1.19 * real (ref) + 0.5) ; IF refresh < 1 THEN refresh := 1 ELIF refresh > 255 THEN refresh := 256 FI ; put (real (refresh) / 1.19) ; putline ("us Refresh-Intervall eingestellt.") ; IF refresh = 256 THEN refresh := 0 FI ; poken (&"0E2C", "B0 54 E6 43 EB 00 B0 " + subtext (%refresh, 3, 4) + " E6 41 C3") . patch cursor maxima: (* Es werden nur die Maxima bei CURSOR(,) veraendert, CLEOL, CLEOP,SCROLL etc. arbeiten weiter mit 24 Zeilen, 80 Spalten *) (* CURSOR y:0..43, x:0..89 EUMEL lässt allerdings nur 0..79 zu *) poke (&"0EFF", 43) ; poke (&"0F16", 89) . patch attribute bytes: poke (&"0FD4", 0) ; poke (&"0FE8", 0) ; (* CLEOP *) poke (&"1002", 0) ; (* CLREOL *) poke (&"1027", 0) . (* SCROLL *) patch out restart : poke (&"09BA", 0) . (* out_restart immer: JP $+0 *) patch dtr inactive : poke (&"0A30", 8) . (* RTS + DTR inaktiv, OUT2 muss an bleiben *) patch mcr set routine : (* 0812: 20 Bytes zur Verfügung MOV DX,(DI+i8250_base) ADD DX,i8250_mcr MOV AL,BH ; Highbyte 2. IOCONTROL Parameter OUT [DX],AL MOV CX,0 RET *) poken (&"0812", "8B 95 1B 00 83 C2 04 88 F8 EE B9 00 00 C3") . patch archive 1 format : line ; putline ("Archiv-Kanal 30-Laufwerk (bitte Typnummer angeben):") ; putline (" 0: Nicht vorhanden") ; putline (" 1: 360K (Standard/Doublestep)") ; putline (" 2: 720K (Standard/Singlestep)") ; putline (" 3: 1.2MB (Multifunction)") ; putline ("ESC: Nichts verändern") ; put ("Typ:") ; TEXT VAR t ; REP inchar (t) UNTIL t >= "0" AND t <= "3" OR t = ""27"" PER ; putline (t) ; line ; IF t = "0" OR t = "1" THEN poken (&"21DE", "00 01") ELIF t = "2" THEN poken (&"21DE", "04 02") ELIF t = "3" THEN poken (&"21DE", "01 03") FI . ENDPROC patch shard ; PROC blockin (INT CONST kanal, ROW 256 INT VAR block, REAL CONST blockno) : INT VAR r, my channel :: channel, high, low ; split real24 (blockno, high, low) ; continue (kanal) ; blockin (block, high AND 255, low, r) ; continue (my channel) ; SELECT r OF CASE 0 : CASE 1 : errorstop ("Harddisk kann nicht gelesen werden") CASE 2 : errorstop ("Lesefehler bei Block " + text (blockno)) CASE 3 : errorstop ("Block " + text(blockno) + " zu hoch") OTHERWISE errorstop ("unbekannter Lesefehler auf Harddisk") ENDSELECT . ENDPROC blockin ; PROC blockout (INT CONST kanal, ROW 256 INT VAR block, REAL CONST blockno): INT VAR r, my channel :: channel, high, low ; split real24 (blockno, high, low) ; continue (kanal) ; blockout (block, high AND 255, low, r) ; continue (my channel) ; SELECT r OF CASE 0 : CASE 1 : errorstop ("Harddisk kann nicht beschrieben werden") CASE 2 : errorstop ("Schreibfehler bei Block " + text (blockno)) CASE 3 : errorstop ("Block " + text (blockno) + " zu hoch") OTHERWISE errorstop ("unbekannter Schreibfehler auf Harddisk") ENDSELECT . ENDPROC blockout ; PROC get media size (INT CONST kanal, INT VAR cyls, heads, secs) : INT CONST old channel :: channel ; continue (kanal) ; control (-10, 0, 0, cyls) ; cyls INCR 1 ; control (-11, 0, 0, secs) ; control (-12, 0, 0, heads) ; continue (old channel) ENDPROC get media size ; (* PROC dump block (INT CONST adr) : TEXT VAR t ; FOR i FROM adr UPTO adr+511 REP IF (i AND 15) = 0 THEN line ; put (%i+":") ; t := "" ; FI ; INT CONST j :: peek (i) ; IF j < 32 OR j > 126 THEN t CAT "." ELSE t CAT code (j) FI ; outsubtext (%j, 3, 4) ; out (" ") ; IF (i AND 15) = 15 THEN out (t) FI PER ; line ENDPROC dump block ; putline ("Partitionstabelle lesen...") ; get partition ; putline ("SHard lesen...") ; read shard ; put (%peek (1364)) ; *)