title Diskzap, der Diskettendoktor unter CP/M Plus name ('DISKZAP') ; Dieses Programm wurde abgedruckt in der CHIP SPECIAL von 1987 ; mit dem Titel "Besser programmieren" ; Allerdings funktioniert dieser Quelltext NICHT mit dem M80 ; ===== ; Daher folgende Aenderungen: ; (1) Labels fuer 'equ' ohne Doppelpunkt ; (2) Labels 'dec1', 'dec2' und 'dr1' mit Doppelpunkt ; (3) Label 'Laufwerk_selektieren' mit Doppelpunkt ; (4) Label 'Laufwerk_selektieren' heisst 'LaufwerkSelektieren' ; (5) Instruktion 'add ..' aendern in 'add a,..' (12x) ; (6) Am Anfang 'cseg' ; -------------------------------------------- ; Weitere Aenderungen: ; (7) Fehlerkorrektur ; (8) Mehr Kommentare: ; Real programmers don't comment their code. ; If it was hard to write, it should be hard to read. ; (9) Mehr 'equ' fuer bessere Lesbarkeit ; (10) In HEXDEZ Labels 'Lxxxx' geaendert ; (11) 'defb/defw/defs' in 'db/dw/ds' geaendert ; Alle Aenderungen von Werner Cirsovius cseg FALSE equ 0 TRUE equ not FALSE WBOOT equ 0000h BDOS equ 0005h ; CPMv equ 30h ; ; BDOS Funktionen ; .conout equ 2 .condir equ 6 .string equ 9 .linin equ 10 .vers equ 12 .seldsk equ 14 .curdsk equ 25 .getDPB equ 31 .BIOS equ 50 ; _get equ 0fdh ; ; BIOS Funktionen ; _SETTRK equ 10 _SETSEC equ 11 _SETDMA equ 12 _READ equ 13 _WRITE equ 14 ; ; Offsets im DPB ; _dsm equ 5 _off equ 13 esc equ 1bh cr equ 0dh lf equ 0ah eot equ '$' LOMASK equ 00001111b HIMASK equ 11110000b INPLEN equ 8 DISPROW equ 8 DISPCOL equ 16 ; CHROFFS equ 3*(DISPCOL+1)+2 ; Anfang der Zeichenspalte BYTOFFS equ 3+2 ; Anfang der Bytespalte ; ; Cursorpositionen ; _BYTX equ 40 ; Fuer Editieren _BYTY equ 1 ; _EDX equ 1 ; Fuer Ende Editieren _EDY equ 12 ; ; Cursortasten ; _CUR equ 'D'-'@' ; Rechts _CUL equ 'S'-'@' ; Links _CUO equ 'E'-'@' ; Oben _CUU equ 'X'-'@' ; Unten _CUT equ 'C'-'@' ; ASCII/Byte jp start ; Die nachfolgenden Zellen muessen fuer den jeweiligen Computer ; angepasst werden ; Cls ist die Zeichenfolge fuer Bildschirm loeschen ; Das erste Byte gibt die Anzahl der folgenden Zeichen an, die ; zwischen 1 und 4 liegen kann, wobei dies natrlich erweitert ; werden kann ; SetC ist die Zeichenfolge fuer Cursor setzen ; Das erste Byte gibt die Anzahl der folgenden Zeichen an, die ; zwischen 1 und 4 liegen kann, wobei dies natrlich erweitert ; werden kann ; ColOffset ist der Offset, der zur Spaltennummer addiert ; werden mua ; lineoffset ist der Offset, der zur Zeilennummer addiert ; werden mua ; Falls noetig, muss auch die Routine SetCursor verndert, ; wenn z.B. Zeile und Spalte in umgekehrter Reihenfolge ; gesendet werden mua. Dazu kann man einfach das H-Register ; und das L-Register vertauschen. Cls: db 2 db esc,'*',0,0 SetC: db 2 db esc,'-',0,0 ColOffset: db 32 LineOffset: db 32 ; ; Einen physikalischen Sektor lesen ; ReadSec: ld bc,Puffer ; Pufferadresse laden call SetDMA ; Als Puffer einstellen ld bc,(Track) ; Spur laden call SetTrk ; Spur einstellen ld hl,(Sector) ; Sektor laden ld a,(PhysShift) ; Schiebefaktor laden ld b,a rs1: srl h ; Realen Sektor berechnen rr l djnz rs1 ld b,h ld c,l call SetSec ; Sektor einstellen call Read ; Sektor lesen or a ; Test ob erfolgreich jr nz,ReadErr ; Lesefehler ld hl,(Sector) ; Werte umtragen ld (LastSector),hl ld hl,(Track) ld (LastTrack),hl ld a,(Drive) ld (LastDrive),a ret ReadErr: push af ld de,RdErrMsg call PrtStr ; Fehler ausgeben pop af ret ; RdErrMsg: db 'Lesefehler' db cr,lf,eot ; ; Einen physikalischen Sektor schreiben ; WriteSec: ld bc,Puffer ; Pufferadresse laden call SetDMA ; Als Puffer einstellen ld bc,(Track) ; Spur laden call SetTrk ; Spur einstellen ld hl,(Sector) ; Sektor laden ld a,(PhysShift) ; Schiebefaktor laden ld b,a ws1: srl h ; Realen Sektor berechnen rr l djnz ws1 ld b,h ld c,l call SetSec ; Sektor einstellen ld c,1 call Write ; Sektor sofort schreiben or a ; Test ob erfolgreich jr nz,WrtErr ; Schreibfehler ld hl,(Sector) ; Werte umtragen ld (LastSector),hl ld hl,(Track) ld (LastTrack),hl ld a,(Drive) ld (LastDrive),a ret WrtErr: push af ld de,WrErrMsg call PrtStr ; Fehler ausgeben pop af ret ; WrErrMsg: db 'Schreibfehler' db cr,lf,eot ; ; String auf Bildschirm ausgeben ; PrtStr: ld c,.string jp BDOS ; Ausgabe ; ; !!! BIOS Funktionen ueber BDOS aufrufen !!! ; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ; ; Spur einstellen ; SetTrk: ld a,_SETTRK jr DirectBIOS ; ; Sektor einstellen ; SetSec: ld a,_SETSEC jr DirectBIOS ; ; Diskpuffer einstellen ; SetDMA: ld a,_SETDMA jr DirectBIOS ; ; Sektor lesen ; Read: ld a,_READ jr DirectBIOS ; ; Sektor schreiben ; Write: ld a,_WRITE ; ; BIOS Funktionen ueber BDOS aufrufen ; Im Accu steht die Funktion ; Register BC haelt Parameter ; DirectBIOS: ld (BIOSPB),a ; Funktion eintragen ld (BIOSPB+2),bc ; Parameter speichern ld c,.BIOS ld de,BIOSPB jp BDOS ; BIOS-Funktion ausfuehren ; BIOSPB: ds 2*4 ; ; Offset fuer den logischen Sektor im Puffer berechnen ; Offset: push af ld a,(PhysMaske) ; Sektormaske laden ld l,a ld a,(LastSector) ; Letzten Sektor holen and l ; Und maskieren ld l,a ld h,0 add hl,hl ; * 2 add hl,hl ; * 4 add hl,hl ; * 8 add hl,hl ; * 16 add hl,hl ; * 32 add hl,hl ; * 64 add hl,hl ; *128 pop af ret ; ; Das Byte im Akku in Hex ausgeben ; HexOut: push af srl a ; Hoeherwertigen Bits laden srl a srl a srl a call HexASCII ; Bits ausgeben pop af and LOMASK ; Niederwertige Bits laden HexASCII: cp 9+1 ; Test ob dezimal jr c,NoLetter ; Ja add a,'A'-'0'-10 ; Hex Korrektur NoLetter: add a,'0' ; In Zeichen wandeln jp TTYOut ; Ausgeben ; ; Falls das Zeichen im Akku eine Hex-Ziffer ist, ; so ist das Carry-Flag nicht gesetzt ; HexPruefen: cp '0' ; Bereich testen ret c ; Nicht im Bereich cp 'F'+1 ccf ret c cp 'A' ret nc cp '9'+1 ccf ret ; ; Sektornummer um eins erhoehen ; IncSec: ld hl,(MaxSector) ; Maximalen Sektorwert laden ld de,(Sector) ; Aktuellen Wert laden scf sbc hl,de ; Test ob Bereich ok jr c,inc1 ; Nein inc de ; Sektor erhoehen ld (Sector),de ret inc1: ld hl,(MaxTrack) ; Maximalen Spurwert laden ld de,(Track) ; Aktuellen Wert laden scf sbc hl,de ; Test ob Bereich ok jr nc,inc2 ; Ja ld hl,(MaxTrack) ld (track),hl ; Maximalwerte setzen ld hl,(MaxSector) ld (Sector),hl ret inc2: inc de ; Spur erhoehen ld (Track),de ld hl,0 ld (Sector),hl ; Sektor auf Anfang ret ; ; Sektor nummer um eins erniedrigen ; DecSec: ld hl,(Sector) ; Aktuellen Wert laden ld a,h or l ; Test ob bereits am Anfang jr z,dec1 ; Ja dec hl ; Sektor erniedrigen ld (Sector),hl ret dec1: ld hl,(Track) ; Aktuellen Wert laden ld a,h or l ; Test ob bereits am Anfang jr nz,dec2 ; Nein ret dec2: dec hl ; Spur erniedrigen ld (Track),hl ld hl,(MaxSector) ld (Sector),hl ; Maximalen Wert setzen ret ; ; Dezimalzahl einlesen ; in HL steht die Adresse auf den Zahlenstring ; Jedes andere Zeichen, das nicht im Bereich '0'..'9' ; liegt, beendet das Einlesen ; Das Ergebnis steht im HL-Register ; DezHex: ld de,0 ; Ergebnis setzen NextZif: ld a,(hl) ; Zeichen laden cp '0' ; Test ob dezimal jr c,StringEnd ; Ende wenn nicht cp '9'+1 jr nc,StringEnd ex de,hl add hl,hl ; Alt * 2 ld b,h ld c,l add hl,hl ; * 4 add hl,hl ; * 8 add hl,bc ; *10 sub '0' ld c,a ; Neue Ziffer ld b,0 add hl,bc ; Ziffer addieren ex de,hl inc hl jr NextZif StringEnd: ex de,hl ; Ergebnis holen ret ; ; Der Wert des hl-Register wird dezimal ausgegeben, und zwar ; rechtsbuendig fuehrende Nullen werden unterdrueckt ; Hexdez: ex de,hl ld a,0 ld b,3 ld hl,DecBuff HexIni: ld (hl),a ; Bytes loeschen inc hl djnz HexIni ld b,16 ; Bitlaenge setzen HexDiv: ex de,hl add hl,hl ; Hoechstes Bit holen ex de,hl push bc ld b,3 ld hl,DecBuff HexBCD: ld a,(hl) adc a,(hl) ; Hoechstes Bit addieren daa ; Zahl als BCD ld (hl),a inc hl djnz HexBCD pop bc djnz HexDiv ld b,3 ; Anzahl Bytes laden ld c,3*2 ; Anzahl Zeichen laden ld hl,DecBuff+2 ; Zeiger auf hoechste BCD Zahl nbyte: ld a,(hl) ; BCD laden call ByteOut ; Ausgeben dec hl djnz nbyte ret ; ; BCD Byte im Accu ausgeben ; ByteOut: push af srl a ; Obere Bits holen srl a srl a srl a call DecOut ; Ausgeben pop af DecOut: and LOMASK ; Bits maskieren or '0' dec c ; Test ob letzte Stelle jr z,TTYOut ; Dann kein Test ob Null bit 7,c ; Test ob fuehrende Null jr nz,TTYOut ; Nein cp '0' ; Ist dies eine Null? jr z,Zero ; Falls ja, dann ignorieren set 7,c ; Markierung keine Null Zero: jr nz,TTYOut ; Ausgabe ld a,' ' ; Fuehrende Null als Leerzeichen ; ; Zeichen auf Konsole ausgeben ; TTYOut: push bc push de push hl ld e,a ; Zeichen umpacken ld c,.conout call BDOS ; Ausgeben pop hl pop de pop bc ret ; DecBuff: ds 4 ; ; Ein Zeichen von der Tastatur lesen ; TTYin: ld e,_get ld c,.condir jp BDOS ; Zeichen lesen ; ; MaxSector, MaxTrack und PhysMaske bestimmen ; GetDiskPar: ld c,.getDPB call BDOS ; Disk Parameter Block holen ld a,(hl) ; Anzahl von Rekords je Spur holen inc hl push hl ld h,(hl) ld l,a dec hl ld (maxsector),hl ; Als Maximalwert ablegen pop hl inc hl ld b,(hl) ; Blockschiebeaktor laden inc hl inc hl inc hl ld a,(hl) ; Anzahl von Bloecken laden inc hl push hl ld h,(hl) ld l,a inc hl ; Justieren weil oben -1 DiskPar: add hl,hl ; Bloecke schieben djnz DiskPar ex de,hl ld hl,(MaxSector) ; Maximalwer als Divisor inc hl ex de,hl ld a,h ; Dividenden laden ld c,l call div ; Dividieren ld d,a ; Ergebnis umpacken ld e,c ld a,l or h ; Test ob Rest vorhanden jr nz,DiskPar1 dec de ; Ergebnis justieren falls nicht DiskPar1: pop hl ld bc,_off-(_dsm+1) add hl,bc ; Zeiger auf Anzahl reservierter Spuren ld c,(hl) ; Anzahl laden inc hl ld b,(hl) push hl ex de,hl add hl,bc ; Gesamtspur berechnen ld (MaxTrack),hl ; Eintragen pop hl inc hl ld a,(hl) ld (PhysShift),a ; Sektorschiebefaktor speichern inc hl ld a,(hl) ld (PhysMaske),a ; Sektormaske speichern ld de,String7 call PrtStr ld hl,(MaxTrack) call hexdez ; Maximale Spur ausgeben ld de,String8 call PrtStr ld hl,(MaxSector) call hexdez ; Maximalen Sektor ausgeben jp crlf ; Zeile auf Konsole schliessen String7: db 'Maximale Spurnummer =',eot String8: db ' Maximale Sektornummer =',eot ; ; Divisionsroutinc fuer 16 BIT ; in AC steht der Dividend ; in DE der Divisor ; in AC das Ergebnis ; in HL der Rest ; div: ld hl,0 ; Rest einstellen ld b,16 ; Anzahl Bits setzen div1: rl c ; Division ausfuehren rla adc hl,hl sbc hl,de jr nc,div2 add hl,de div2: ccf djnz div1 rl c ret ; ;fuehrende Leerzeichen ueberlesen ; DelSpace: ld a,(hl) ; Zeichen laden cp ' ' ; Test ob Leerzeichen ret nz ; Nein, ok inc hl ; Leerzeichen ueberlesen jr DelSpace ; ; Bildschirm loeschen ; ClrScr: ld hl,Cls ; Zeiger auf Kontrollsequenz ld a,(hl) ; Laenge laden or a ; Test ob definiert ret z ; Nein, dann Ende ld b,a clr1: inc hl ld a,(hl) call TTYOut ; Kontrollsequenz ausgeben djnz clr1 ret ; ; Cursor setzen ; Spalte im H-Register ; Zeile im L-Register ; SetCursor: dec h ; Auf 0 relativieren dec l ex de,hl ld hl,SetC ; Zeiger auf Kontrollsequenz ld a,(hl) ; Laenge laden or a ; Test ob definiert ret z ; Nein, dann Ende ld b,a set1: inc hl ld a,(hl) call TTYOut ; Kontrollsequenz ausgeben djnz set1 ld a,(LineOffset) add a,e ; Spaltenoffset addieren call TTYOut ; Zeile ausgeben ld a,(ColOffset) add a,d ; Zeilenoffset addieren jp TTYOut ; Spalte ausgeben ; ; Sektor anzeigen, wenn keine Zahl dahinter angegeben ist, ; ansonsten Sektornummer einlesen ; SektorFestlegen: call DelSpace ; Fuehrende Leerzeichen ueberlesen ld a,(hl) ; Zeichen laden or a ; Test, ob Nummer jr z,Secf1 ; Nein, anzeigen call DezHex ; Nummer wandeln ld (Sector),hl ex de,hl ld hl,(MaxSector) or a sbc hl,de ; Test ob gueltig ret nc ; Nein add hl,de ld (Sector),hl ; Sektor festlegen ret Secf1: ld de,String5 call PrtStr ; Sektor anzeigen ld hl,(Sector) jp hexdez ; Sektor ausgeben ; String5: db 'Sektor =',eot ; ; Spur anzeigen oder einlesen ; SpurFestlegen: call DelSpace ; Fuehrende Leerzeichen ueberlesen ld a,(hl) ; Zeichen laden or a ; Test, ob Nummer jr z,Spurf1 ; Nein, anzeigen call DezHex ; Nummer wandeln ld (Track),hl ex de,hl ld hl,(MaxTrack) or a sbc hl,de ; Test ob gueltig ret nc ; Nein add hl,de ld (Track),hl ; Spur festlegen ret Spurf1: ld de,String6 call PrtStr ; Spur anzeigen ld hl,(Track) jp hexdez ; Spur ausgeben ; String6: db 'Spur =',eot ; ; falls das Zeichen im Akku auf dem Bilds. nicht darstellbar ; ist, dann wird stattdessen ein Punkt ausgegeben ; Druck: call Druckbar ; Ist Zeichen druckbar? jr nc,dr1 ; Ja ld a,'.' ; Sonst Punkt ausgeben dr1: jp TTYOut ; Zeichen ausgeben ; ; Falls das Zeichen im Akku nicht darstellbar ist, ; so ist das Carry-Flag gesetzt ; Druckbar: cp ' ' ; Druckbaren Bereich testen ret c cp '~'+1 ccf ret ; ; Alle Kleinbuchstaben werden in Grossbuchstaben umgewandelt ; UPCASE: cp 'a' ; Test ob Kleinbuchstabe ret c ; Nein cp 'z'+1 ret nc sub 'a'-'A' ; In Grossbuchstaben wandeln ret ; ; Sektor auf dem Bildschirm ausgeben ; SektorAusgeben: call ClrScr ; Bildschirm loeschen ld de,String1 call PrtStr ld a,(LastDrive) add a,'A' call TTYOut ; Laufwerk ausgeben ld de,String2 call PrtStr ld hl,(LastTrack) call hexdez ; Letzte Spur ausgeben ld de,String3 call PrtStr ld hl,(LastSector) call hexdez ; Letzten Sektor ausgeben call crlf ; Zeile auf Konsole schliessen call crlf ld b,0 ; Zeilenzaehler setzen ; ; Teil 1 : Ausgabe Hexbytes ; seca3: push bc ld a,b ; Zeile holen sla a ; * 2 sla a ; * 4 sla a ; * 8 sla a ; *16 push bc call HexOut ; Zeile ausgeben ld a,' ' call TTYOut ; Leerzeichen ausgeben ld a,' ' call TTYOut pop bc ld c,0 ; Spalte setzen seca1: push bc ld a,b ; Zeile holen sla a ; * 2 sla a ; * 4 sla a ; * 8 sla a ; *16 add a,c ; Spalte addieren ld c,a ld b,0 call Offset ; Offset berechnen ld de,Puffer add hl,de ; Adresse im Puffer berechnen add hl,bc ld a,(hl) ; Byte laden call HexOut ; Byte in Hex ausgeben ld a,' ' call TTYOut ; Leerzeichen ausgeben pop bc inc c ; Spalte erhoehen ld a,DISPCOL cp c ; Test ob Ende jr nz,seca1 ; Naechste Spalte ld c,0 ; Spalte setzen ; ; Teil 1 : Ausgabe Zeichen ; seca2: push bc ld a,b ; Zeile holen sla a ; * 2 sla a ; * 4 sla a ; * 8 sla a ; *16 add a,c ; Spalte addieren ld c,a ld b,0 call Offset ; Offset berechnen ld de,Puffer add hl,de ; Adresse im Puffer berechnen add hl,bc ld a,(hl) ; Byte laden call Druck ; Als Zeichen ausgeben pop bc inc c ; Spalte erhoehen ld a,DISPCOL cp c ; Test ob Ende jr nz,seca2 ; Naechste Spalte call crlf ; Zeile auf Konsole schliessen pop bc inc b ; Zeile erhoehen ld a,DISPROW cp b ; Test ob Ende jr nz,seca3 ; Naechste Zeile ret ; String1: db 'Laufwerk ',eot String2: db ': Spur ',eot String3: db ' Sektor ',eot ; ; Cursor auf das entsprechende Byte am Bilds. positionieren ; PosCurByte: ld a,(CurPos) ; Aktuelle Position laden dec a ld c,a and LOMASK ; Maskieren ld b,a sla a ; *2 add a,b ; *3 ld b,a ld a,(HighLow) ; Reihenfolge laden add a,b ld b,BYTOFFS add a,b ; Offset addieren ld h,a ; Spalte setzen ld a,c srl a srl a srl a srl a inc a inc a inc a ld l,a ; Reihe setzen jp SetCursor ; Cursor setzen (X=H, Y=L) ; ; Cursor auf das entsprechende Zeichen am Bildschirm positionieren ; PosCurChar: ld a,(CurPos) ; Aktuelle Position laden dec a ld c,a and LOMASK ld b,CHROFFS add a,b ; Offset addieren ld h,a ; Spalte setzen ld a,c ; Position laden srl a ; / 2 srl a ; / 4 srl a ; / 8 srl a ; /16 inc a ; Offset ueberspringen inc a inc a ld l,a ; Reihe setzen jp SetCursor ; Cursor setzen (X=H, Y=L) ; ; Cursor wird um ein Byte oder ein Zeichen nach rechts bewegt ; CursorRechts: ld a,(ASCII) ; Modus laden or a ; Test ob Zeichen jr z,cr1 ; Nein, Byte ld a,(CurPos) ; Aktuelle Position laden cp DISPROW*DISPCOL ; Test ob letzte Position ret z ; Dann ignorieren inc a ld (CurPos),a ; Neue Position setzen ret cr1: ld a,(HighLow) ; Reihenfolge laden or a ; Test ob unteres Byte jr nz,cr2 ; Ja, schon eingestellt inc a ld (HighLow),a ; Reihenfolge auf unteres Byte setzen ret cr2: ld b,a ld a,(CurPos) ; Aktuelle Position laden cp DISPROW*DISPCOL ; Test ob letzte Position ret z ; Dann ignorieren inc a ld (CurPos),a ; Neue Position setzen xor a ld (HighLow),a ; Reihenfolge auf oberes Byte setzen ret ; ; Cursor wird um ein Byte oder ein Zeichen nach links bewegt ; CursorLinks: ld a,(ASCII) ; Modus laden or a ; Test ob Zeichen jr z,cl1 ; Nein, Byte ld a,(CurPos) ; Aktuelle Position laden cp 1 ; Test ob erste Position ret z ; Dann ignorieren dec a ld (CurPos),a ; Neue Position setzen ret cl1: ld a,(HighLow) ; Reihenfolge laden or a ; Test ob oberes Byte jr z,cl2 ; Ja, schon eingestellt dec a ld (HighLow),a ; Reihenfolge auf oberes Byte setzen ret cl2: ld b,a ld a,(CurPos) ; Aktuelle Position laden cp 1 ; Test ob erste Position ret z ; Dann ignorieren dec a ld (CurPos),a ; Neue Position setzen ld a,1 ld (HighLow),a ; Reihenfolge auf unteres Byte setzen ret ; ; Cursor wird um ein Byte oder ein Zeichen nach oben bewegt ; CursorOben: ld a,(CurPos) ; Aktuelle Position laden cp DISPCOL+1 ret c ; Ende falls schon oben sub DISPCOL ; Auf vorige Reihe setzen ld (CurPos),a ret ; ; Cursor wird um ein Byte oder ein Zeichen nach unten bewegt ; CursorUnten: ld a,(CurPos) ; Aktuelle Position laden cp DISPCOL*(DISPROW-1)+1 ret nc ; Ende falls schon unten add a,DISPCOL ; Auf naechste Reihe setzen ld (CurPos),a ret ; ; im C-Register steht ein Hex-Zeichen, wobei mit diesem der hoeher- ; oder niederwertige Teil des Bytes veraendert wird ; ChangeByte: call Offset ; Offset berechnen ld a,(CurPos) ; Aktuelle Position laden dec a ld e,a ld d,0 add hl,de ld de,Puffer add hl,de ; Adresse im Puffer berechnen ld a,(HighLow) ; Reihenfolge laden or a ; Test ob oberes Byte jr nz,cb1 ; Nein ld a,c call ASCIIhex ; ASCII nach hex umwandeln sla a ; * 2 sla a ; * 4 sla a ; * 8 sla a ; *16 ld b,a ld a,(hl) ; Alstes Byte laden and LOMASK ; Oberen Teil auf Null setzen or b ; Neue Bits einfuegen ld (hl),a ; Und abspeichern ret cb1: ld a,c call ASCIIhex ; ASCII nach hex umwandeln ld b,a ld a,(hl) ; Alstes Byte laden and HIMASK ; Unteren Teil auf Null setzen or b ; Neue Bits einfuegen ld (hl),a ; Und abspeichern ret ; ; Ascii nach hex umwandeln ; ASCIIhex: sub '0' ; Offset abziehen cp 9+1 ; Bereich testen ret c sub 'A'-'0'-10 ret ; ; Sektor im Puffer editieren ; SektorEditieren: xor a ld (HighLow),a ; Reihenfolge einstellen ld (Ende),a ; Noch kein Ende ld (ASCII),a ; Byte voreinstellen inc a ld (CurPos),a ; Erste Position einstellen call SektorAusgeben ; Sektor ausgeben se0: ld hl,se4 push hl ; Ruecksprungadresse setzen ld h,_BYTX ld l,_BYTY call SetCursor ; Cursor setzen (X=H, Y=L) ld de,String4 call PrtStr ; Ausgabe fuer aktuelle Sektorposition ld a,(CurPos) ; Aktuelle Position laden ld l,a ld h,0 call hexdez ; Sektorposition ausgeben ld a,(ASCII) ; Modus laden or a ; Test ob Byte oder ASCII push af call z,PosCurByte ; Cursor auf Byte positionieren pop af call nz,PosCurChar ; Cursor auf Zeichen positionieren call TTYin ; Zeichen von Tastatur lesen ld b,a ; Zeichen retten ld a,(ASCII) ; Modus laden or a ; Test ob Byte oder ASCII ld a,b call z,UPCASE ; In Grossbuchstaben wandeln falls Byte cp esc ; Test ob Ende jr nz,se1 ; Nein ld a,TRUE ld (Ende),a ; Ende falls ja ret se1: cp _CUR ; Test ob Cursorbewegung jp z,CursorRechts cp _CUL jp z,CursorLinks cp _CUO jp z,CursorOben cp _CUU jp z,CursorUnten cp _CUT ; Test ob Umschaltung ASCII/Byte jr nz,se2 ld a,(ASCII) cpl ; Modus umschalten ld (ASCII),a ret se2: ld b,a ; Zeichen retten ld a,(ASCII) ; Modus laden or a ; Test Byteeingabe ld a,b jr nz,se3 ; Nein ; ; Byteeingabe ; call HexPruefen ; Test ob Hex Zeichen ret c ; Ende falls nicht push af call TTYOut ; Zeichen ausgeben pop af ld c,a call ChangeByte ; Byte aendern call PosCurChar ; Cursor auf Zeichen positionieren call Offset ; Offset berechnen ld a,(CurPos) ; Aktuelle Position laden dec a ld e,a ld d,0 ld bc,Puffer add hl,de ; Adresse im Puffer berechnen add hl,bc ld a,(hl) ; Byte laden call Druck ; Als Zeichen ausgeben jp CursorRechts ; Cursor weiter bewegen ; ; Zeicheneingabe ; se3: call Druckbar ; Ist Zeichen druckbar? ret c ; Nein push af call TTYOut ; Zeichen ausgeben call Offset ; Offset berechnen ld a,(CurPos) ; Aktuelle Position laden dec a ld e,a ld d,0 pop af ld bc,Puffer add hl,de ; Adresse im Puffer berechnen add hl,bc ld (hl),a ; Zeichen eintragen push af xor a ld (HighLow),a ; Reihenfolge einstellen call PosCurByte ; Cursor auf Byte positionieren pop af call HexOut ; Byte in Hex ausgeben jp CursorRechts ; Cursor weiter bewegen ; se4: ld a,(Ende) ; Test ob Ende or a jp z,se0 ; Nein, neue Eingabe ld h,_EDX ld l,_EDY jp SetCursor ; Cursor setzen (X=H, Y=L) ; String4: db 'Byte ',eot ; ; Entsprechendes Laufwerk auswaehlen ; LaufwerkSelektieren: ld a,(hl) ; Laufwerk laden or a ; Test ob definiert jr nz,ls1 ; Ja ld a,'A' ; Sonst Laufwerk A: einstellen ls1: call UPCASE ; Zeichen in Grossbuchstaben wandeln sub 'A' ; Wandeln in binaer ld (drive),a ; Abspeichern ld c,.seldsk ; Disk waehlen ld e,a call BDOS jp GetDiskPar ; Diskparameter laden ; ; Zeile auf Konsole schliessen ; crlf: ld a,cr call TTYOut ; Simple Ausgabe ld a,lf jp TTYOut ; ; Programm abbrechen falls nicht CP/M Plus ; KeinPlus: ld de,String9 call PrtStr ; Meldung ausgeben jp WBOOT ; Abbruch ; String9: db cr,lf,'Dieses Programm laeuft nur unter CP/M 3.X',eot ; ; ##################### ; ### Start DISKZAP ### ; ##################### ; Start: ld c,.vers call BDOS ; BDOS Version laden ld a,CPMv-1 cp l ; Test ob CP/M Plus jr nc,KeinPlus ; Nein, dann Ende ld hl,0 ld (track),hl ; Werte auf Null setzen ld (sector),hl ld (LastTrack),hl ld (LastSector),hl xor a ld (Quit),a call GetDiskPar ; Diskparameter laden ld c,.curdsk call BDOS ; Aktuelles Laufwerk laden ld (drive),a ld (LastDrive),a call ReadSec ; Sektor lesen s0: ld hl,s8 push hl ; Rueckkehradresse laden call crlf ; Zeile auf Konsole schliessen ld a,'?' call TTYOut ; Anzeige, dass Eingabe erforderlich ist ld a,' ' call TTYOut ; Leerzeichen ausgeben ld de,Befehl ld a,INPLEN ld (de),a ; Eingabelaenge setzen ld c,.linin call BDOS ; Befehl lesen ld hl,Befehl+1 ld c,(hl) ; Laenge laden ld b,0 inc hl push hl ; Textstart retten add hl,bc ; Ende der Zeile xor a ld (hl),a ; Ende setzen pop hl ; Textstart holen call DelSpace ; Fuehrende Leerzeichen ueberlesen ld a,(hl) ; Befehl laden inc hl call UPCASE ; Zeichen in Grossbuchstaben wandeln cp 'T' jr nz,s1 ; ; Befehl Tx : Spurnummer x festlegen ; jp SpurFestlegen ; Spur eingeben oder anzeigen s1: cp 'S' jr nz,s2 ; ; Befehl Sy : Sektornummer y festlegen ; jp SektorFestlegen ; Sektor eingeben oder anzeigen s2: cp 'R' jr nz,s3 ; ; Befehl R : Sektor in den Puffer lesen ; call ReadSec ; Sektor lesen call z,SektorAusgeben; Sektor ausgeben ret s3: cp 'W' jr nz,s4 ; ; Befehl W : Puffer auf Diskette schreiben ; jp WriteSec ; Sektor schreiben s4: cp '+' jr nz,s5 ; ; Befehl + : Sektornummer um eins erhoehen ; call IncSec ; Sektornummer um eins erhoehen call ReadSec ; Sektor lesen call z,SektorAusgeben; Sektor ausgeben ret s5: cp '-' jr nz,s6 ; ; Befehl - : Sektornummer um eins erniedrigen ; call DecSec ; Sektornummer um eins erniedrigen call ReadSec ; Sektor lesen call z,SektorAusgeben; Sektor ausgeben ret s6: cp 'D' ; ; Befehl D : Puffer auf Bildschirm ausgeben ; jp z,SektorAusgeben; Sektor ausgeben cp 'E' ; ; Befehl E : Puffer editieren ; jp z,SektorEditieren; Sektor editieren cp 'L' jr nz,s7 ; ; Befehl Lm : Laufwerk m auswaehlen ; call DelSpace ; Fuehrende Leerzeichen ueberlesen jp LaufwerkSelektieren; Neues Laufwerk s7: cp 'Q' jr nz,s8 ; ; Befehl Q : Programm beenden ; ld a,TRUE ld (Quit),a ; Ende setzen ret s8: ld a,(Quit) or a ; Test Programmende jp z,s0 ; Nein jp WBOOT ; Warmstart ; Drive: db 0 LastDrive: db 0 Track: dw 0 LastTrack: dw 0 Sector: dw 0 LastSector: dw 0 MaxTrack: dw 0 MaxSector: dw 0 Quit: db FALSE ; Quittungsangabe Ende: db FALSE ; Endeangabe fuer Editieren HighLow: db 0 ; Reihenfolge - 0 ist oberes, 1 unteres Byte ASCII: db 0 CurPos: db 0 ; Aktuelle Position im Sektor PhysMaske: db 0 ; Physikalische Sektormaske (0:128, 1:256, 3:512..) PhysShift: db 0 ; Physikalischer Sektorschiebefaktor (0:128, 1:256, 2:512..) Befehl: ds 1+1+INPLEN ; Gewaehlter Befehl Puffer: end