; Konvertier- und Hilfsroutinen für den Retro-Z80 ; =============================================== ; der Akku für's Rechnen: 48 Bit groß Akku: DEFS 6,0 ; **************** HEX-Ausgaben ***************** ; 4 und 8 Bit in A ; 16 Bit in HL ; 32 Bit in DEHL ; 48 Bit in BCDEHL HexLL_Out: PUSH HL LD H,B LD L,C CALL HexW_Out POP HL ; DWORD in DEHL als Hex ausgeben HexL_Out: PUSH HL EX DE,HL CALL HexW_Out POP HL ; WORD in HL als Hex ausgeben HexW_Out: LD A,H CALL HexB_Out LD A,L ; Byte in A als 2 Hex Stellen ausgeben HexB_Out: PUSH AF RRA RRA RRA RRA CALL HexN_Out POP AF ; Nibble in A als Hex Stelle ausgeben HexN_Out: AND 15 ADD '0' CP 3Ah JP C,Char_Out ADD 7 JP Char_Out ; **************** Dezi-Ausgaben ***************** ; in: Zahl in A, ; out: genau 3 Stellen Dezi3_Out: PUSH AF PUSH BC LD B,100 CALL up_dezi LD B,10 CALL up_dezi ADD '0' CALL Char_Out POP BC POP AF RET up_dezi: LD C,'0'-1 _updz: INC C SUB B JR NC,_updz ADD B PUSH AF LD A,C CALL Char_Out POP AF RET ; Dezimal-Ausgabe von HL auf Konsole Dezi16_Out: LD DE,0 ; 32 Bit Dezimalausgabe DEHL ; also Wertebereich von +/- 2 Giga Dezi_Out: PUSH BC PUSH DE PUSH HL LD (LMerk),HL LD (LMerk+2),DE BIT 7,D JR Z,_dezio LD A,'-' CALL Char_Out XOR A LD L,A LD H,A LD DE,(LMerk) SBC HL,DE LD (LMerk),HL LD L,A LD H,A LD DE,(LMerk+2) SBC HL,DE LD (LMerk+2),HL _dezio: XOR A LD DE,0CA00h ; 1.000.000.000 LD BC,3B9Ah CALL LNumm LD DE,0E100h ; 100.000.000 LD BC,5F5h CALL LNumm LD DE,9680h ; 10.000.000 LD BC,98h CALL LNumm LD DE,4240h ; 1.000.000 LD BC,0Fh CALL LNumm LD DE,86A0h ; 100.000 LD BC,1 CALL LNumm LD DE,10000 ; 10.000 LD BC,0 CALL LNumm LD DE,1000 ; 1.000 LD BC,0 CALL LNumm LD DE,100 ; 100 LD BC,0 CALL LNumm LD DE,10 ; 10 LD BC,0 CALL LNumm LD A,(LMerk) ADD '0' CALL Char_Out POP HL POP DE POP BC RET LNumm: ADD 1 LD HL,(LMerk) SBC HL,DE LD (LMerk),HL LD HL,(LMerk+2) SBC HL,BC LD (LMerk+2),HL JR NC,LNumm ; so oft wie kein Carry LD HL,(LMerk) ; Wert wieder dazu ADD HL,DE LD (LMerk),HL LD HL,(LMerk+2) ADC HL,BC LD (LMerk+2),HL SUB 1 ; Ziffer wieder eins weniger RET Z ; war A vorher 0 und jetzt auch --> ret OR '0' ; Ziffer '0' dazu CALL Char_Out LD A,'0' ; ab erster Nicht-Null bleibt A= '0' RET ; Dezimal-Ausgabe 48 Bit in BCDEHL ; das ergibt 14 1/2 dezimale Stellen LLong_Out: PUSH BC ; Zahl BCDEHL retten PUSH DE PUSH HL LD (Akku),HL ; und Zahl --> Akku LD (Akku+2),DE LD (Akku+4),BC BIT 7,B ; ob negativ? JR Z,_lldezio LD A,'-' CALL Char_Out CALL Neg_Akku _lldezio: LD IX,DTafel_100T LD B,14 XOR A _lldloop: PUSH BC CALL LLNum LD BC,6 ADD IX,BC POP BC DJNZ _lldloop LD A,(Akku) ADD '0' CALL Char_Out POP HL POP DE POP BC RET ; Stelle in (IX+0..5) LLNum: LD HL,(Akku) ; Akku nach BCDEHL laden LD DE,(Akku+2) LD BC,(Akku+4) ADD 1 ; Ziffer hochzählen PUSH AF ; A retten LD A,L SUB (IX) LD L,A LD A,H SBC (IX+1) LD H,A LD A,E SBC (IX+2) LD E,A LD A,D SBC (IX+3) LD D,A LD A,C SBC (IX+4) LD C,A LD A,B SBC (IX+5) LD B,A JR C,_lle LD (Akku),HL ; wieder zurückschreiben, aber LD (Akku+2),DE ; nur, wenn kein Carry LD (Akku+4),BC POP AF JR LLNum ; so oft wie kein Carry ; Ende, der vorherige Stand des Akkus (vor dem Unterlauf) ; bleibt erhalten _lle: POP AF ; Ziffer wieder nach A SUB 1 ; Ziffer wieder eins weniger RET Z ; war A vorher 0 und jetzt auch --> ret OR '0' ; Ziffer '0' dazu CALL Char_Out LD A,'0' ; ab erster Nicht-Null bleibt A= '0' RET LMerk: DEFS 6,0 DTafel_100T: DEFB 0, 40h, 7Ah, 10h, 0F3h, 5Ah ; 100 Tera DEFB 0, 0A0h, 72h, 4Eh, 18h, 9 ; 10 Tera DEFB 0, 10h, 0A5h, 0D4h, 0E8h, 0 ; 1 Tera DEFB 0, 0E8h, 76h, 48h, 17h, 0 ; 100 Giga DEFB 0, 0E4h, 0Bh, 54h, 2, 0 ; 10 Giga DTafel_1G: DEFB 0, 0CAh, 9Ah, 3Bh, 0, 0 ; 1 Giga DEFB 0, 0E1h, 0F5h, 5, 0, 0 ; 100 Mega DEFB 80h, 96h, 98h, 0, 0, 0 ; 10 Mega DEFB 40h, 42h, 0Fh, 0, 0, 0 ; 1 Mega DEFB 0A0h, 86h, 1, 0, 0, 0 ; 100 Kilo DTafel_64K: DEFB 10h, 27h, 0, 0, 0, 0 ; 10 Kilo DEFB 0E8h, 3, 0, 0, 0, 0 ; 1 Kilo DEFB 100, 0, 0, 0, 0, 0 ; 100 DEFB 10, 0, 0, 0, 0, 0 ; 10 DEFB 1, 0, 0, 0, 0, 0 ; 1 ; abgezählte Zeichen ausgeben NText_Out: PUSH HL PUSH BC _ntxo: LD A,(HL) OR A CALL NZ,Char_Out INC HL DJNZ _ntxo POP BC POP HL RET ; **************** HEX, Dezi Eingaben ************ ; DWORD Hex ab (kzi) konvertieren ; Komplettergebnis im Akku (48 Bit) ; dword Ergebnis in DEHL Get_Hex: CALL ClearAkku ; Akku:= 0; CALL IgnoreSpace ; Leerzeichen überlesen XOR A ; kein Minuszeichen EX AF,AF' gethexzykl: ; Lesezyklus in der Kdo-Zeile CALL HoleZeichen ; Char holen CALL ToUpper ; A..F Uppercase OR A ; 0 = Zeilenende? JR Z,getzahl_end ; Zeilenende-->ret SUB '0' JR C,getzahl_end ; alles < '0' CP 10 JR C,ghz_09 ; für 0..9 SUB 7 ; für A..F ghz_09: CP 16 JR NC,getzahl_end ; wenn nicht 0..F LD B,4 CALL AkkuShlB CALL Add_Akku_A JR gethexzykl ; Ende und ggf. Akku negieren getzahl_end: EX AF,AF' CP '-' ; war '-' ? CALL Z,Neg_Akku ; wenn ='-', dann Akku:= -Akku; LD HL,(Akku) LD DE,(Akku+2) RET ; LongInt ab (kzi) konvertieren ; Komplett-Ergebnis im Akku (48 Bit) ; dword Ergebnis in DEHL Get_Long: CALL ClearAkku ; Akku:= 0; CALL IgnoreSpace ; Leerzeichen übergehen XOR A ; erstmal kein '-' EX AF,AF' CALL HoleZeichen ; erstes Zeichen holen CP '-' ; ist es '-' ? JR NZ,gela ; nö, also Ziffer oder Mist EX AF,AF' ; '-' merken getlongzykl: CALL HoleZeichen ; Zeichen holen gela: OR A JR Z,getzahl_end ; 0 = Zeilenende SUB '0' ; '0'..'9'-->0..9 JR C,getzahl_end ; war < '0' CP 10 JR NC,getzahl_end ; war >= 10 CALL AkkuMal10 ; Akku:= Akku * 10; CALL Add_Akku_A ; Akku:= Akku + A JR getlongzykl ; ************* 48 Bit Akku-Methoden *************** ; Akku mit Zahl ab (HL) laden LadeAkku: PUSH HL PUSH DE PUSH BC LD DE,Akku LD BC,6 LDIR POP BC POP DE POP HL RET ; Akku nach Zahl ab (HL) speichern StoreAkku: PUSH HL PUSH DE PUSH BC LD DE,Akku EX DE,HL LD BC,6 LDIR POP BC POP DE POP HL RET ; Akku löschen ClearAkku: PUSH BC LD B,6 PUSH HL LD HL,Akku clzy: LD (HL),0 INC HL DJNZ clzy POP BC POP HL RET ; Addieren: Akku:= Akku + BCDEHL Add_Akku_BCDEHL: PUSH DE PUSH HL PUSH DE LD DE,(Akku) ADD HL,DE LD (Akku),HL POP DE LD HL,(Akku+2) ; Bits 16..31 ADC HL,DE LD (Akku+2),HL LD HL,(Akku+4) ; Bits 32..47 ADC HL,BC LD (Akku+4),HL POP HL POP DE RET ; Addieren: Akku:= Akku + A; Add_Akku_A: PUSH BC PUSH HL LD B,0 LD C,A ; BC:= A; LD HL,(Akku) ADD HL,BC LD (Akku),HL LD C,B ; BC:= 0; LD HL,(Akku+2) ADC HL,BC LD (Akku+2),HL LD HL,(Akku+4) ADC HL,BC LD (Akku+4),HL POP HL POP BC RET ; Akku:= -Akku; Neg_Akku: PUSH HL PUSH DE SCF CCF ; Carry auf 0 setzen LD DE,(Akku) ; Akku:= 0 - Akku; LD HL,0 SBC HL,DE LD (Akku),HL LD DE,(Akku+2) ; Akku.2:= 0 - Akku.2 - Carry; LD HL,0 SBC HL,DE LD (Akku+2),HL LD DE,(Akku+4) ; Akku.4:= 0 - Akku.4 - Carry; LD HL,0 SBC HL,DE LD (Akku+4),HL POP DE POP HL RET ; Akku:= Akku shl B AkkuShlB: PUSH IX LD IX,Akku ashlb: SLA (IX) RL (IX+1) RL (IX+2) RL (IX+3) RL (IX+4) RL (IX+5) DJNZ ashlb POP IX RET ; Akku:= Akku shr B (mit Erhalt des Vorzeichens) AkkuShrB: PUSH IX LD IX,Akku ashrb: SRA (IX) ; Vorzeichen bleibt erhalten RR (IX+1) RR (IX+2) RR (IX+3) RR (IX+4) RR (IX+5) DJNZ ashrb POP IX RET ; Akku:= Akku * 10 AkkuMal10: PUSH HL PUSH DE PUSH BC LD HL,(Akku) LD DE,(Akku+2) LD BC,(Akku+4) PUSH BC LD B,2 CALL AkkuShlB POP BC CALL Add_Akku_BCDEHL LD B,1 CALL AkkuShlB POP BC POP DE POP HL RET ; ************ Text-Funktionen ********************** ; Match = Testet ob Substring in Kommandozeile. ; Aufruf: CALL Match ; DEFB 'KOMMANDOWORT',0 ; DEFW Adresse Ziel-UP IfMatch: CALL IgnoreSpace ; vor bis nächstes Zeichen POP IX ; Ret-Adr mit Kdo-Wort nach IX LD HL,(kzi) ; Index retten LD D,H ; und in DE retten LD E,L matz: LD A,(IX) ; Substring-Zeichen laden OR A ; ob Stringende JR Z,matfundend LD B,A LD A,(HL) CALL ToUpper CP B JR NZ,matnotend ; ungleich INC HL INC IX JR matz matfundend: ; INC HL ; auf nächstes Zeichen im KdoString LD (kzi),HL ; Index hinter Kommandowort setzen INC IX ; von null auf low(UP-Adresse) LD L,(IX) ; HL mit Zieladresse laden INC IX LD H,(IX) INC IX PUSH IX ; Returnadresse auf den Stack JP (HL) matnotend: LD (kzi),DE ; Index zurückstellen mlop: LD A,(IX) ; Nullchar suchen INC IX OR A JR NZ,mlop INC IX ; UP-Adresse übergehen INC IX JP (IX) ; zurückspringen ; Leerzeichen im Kommandostring (kzi) übergehen IgnoreSpace: LD HL,(kzi) ; Word, extern zu dieser Quelle LD A,(HL) ; Zeichen aus kzeile lesen OR A ; null? RET Z ; Ret am Ende der Zeile CP ' ' ; Leerzeichen? RET NZ ; Ret wenn nicht INC HL ; HL weiterstellen LD (kzi),HL JR IgnoreSpace ; nächstes Zeichen aus der Kommandozeile holen HoleZeichen: LD HL,(kzi) ; Word, extern zu dieser Quelle LD A,(HL) ; Zeichen aus kzeile lesen OR A RET Z ; wenn 0, dann HL nicht weiterstellen INC HL LD (kzi),HL RET ; Zeichen in Uppercase liefern ToUpper: CP 7Bh ; 'z'+1 RET NC CP 'a' RET C SUB 32 RET ; ----- ende -----