Dezimalausgaben
Meist werden in Programmen Zahlen dezimal ein- und ausgegeben.
Ein grundlegender Artikel mit verschieden Zahlenbasen findet sich hier.
Während die Eingabe einer Dezimalzahl und ihre Wandlung in eine Binärzahl relativ einfach ist — siehe dazu den Artikel — gibt es bei der dezimalen Ausgabe einer Binärzahl mehrere Möglichkeiten, von denen ich einige hier zusammengestellt habe.
Beschreibung der Sammlung:
|
Allen Routinen gemeinsam ist:
- Im Register
HL steht der Binärwert
- Register werden nicht gerettet
- Die externe Routine
APUT , die die aktuelle Ziffer speichert.
Z.B.:
APUT:
push hl ; Register retten
ld hl,(DIGBUF) ; Pufferadresse laden
ld (hl),a ; Ziffer abspeichern
inc hl
ld (hl),0 ; Ende anzeigen
ld (DIGBUF),hl ; Adresse speichern
pop hl ; Register holen
ret
Vor Aufruf der Wandlung muss DIGBUF gesetzt werden.
Natürlich kann APUT auch eine Routine zur Ausgabe sein.
|
|
;
; Rekursive Wandlung
;
Methode1:
ld bc,-10 ; Konstante laden
Numb:
ld de,-1
.Numb:
add hl,bc ; 10s abziehen
inc de ; Anzahl zaehlen
jr c,.Numb ; Weiter bis Rest negativ
push hl ; Rest - 10 sichern
ex de,hl
ld a,h ; Anzahl 10 testen
or l ; Test ob Quotient Null ist
call nz,Numb ; Wenn nicht, rekursiv aufrufen
pop hl ; Rest - 10 laden
ld a,l
add a,'0'+10 ; Ziffer druckbar machen
call APUT ; Ziffer ablegen
ret
;
; Wandlung ueber Tabelle
;
Methode2:
ld ix,tentbl ; Start der Tabelle laden
ld c,1 ; Set zero flag
dotpos:
ld e,(ix) ; Get divisor
inc ix
ld d,(ix)
inc ix
ld b,-1 ; Clear digit
dotdiv:
inc b ; Count digits
or a
sbc hl,de ; Divide
jr nc,dotdiv
add hl,de ; Make > 0
xor a
or b ; Test zero digit
jr nz,dotstr
or c ; Clear leading zero
jr nz,dotbyp
dotstr:
ld c,0 ; Clear zero flag
or '0' ; Make ASCII
call APUT ; Put anywhere
dotbyp:
ld a,e ; Test end of table
cp 10
jr nz,dotpos
ld a,l
or '0'
call APUT ; Put anywhere
ret
;
tentbl:
dw 10000
dw 1000
dw 100
dw 10
;
; Wandlung ueber Tabelle
;
Methode3:
ld ix,tentbl ; Start der Tabelle laden
ld bc,256*5+'0' ; Set length
dotpos:
ld e,(ix+0) ; Get divisor
ld d,(ix+1)
ld a,'0'-1 ; Clear digit
or a
dotdiv:
inc a ; Count digits
sbc hl,de ; Divide
jr nc,dotdiv
add hl,de ; Make > 0
cp c ; Test zero digit
jr nz,dotstr
ld a,' '
inc c ; Clear leading zero
dotstr:
call APUT ; Put anywhere
dec c
inc ix
inc ix
djnz dotpos
ret
;
tentbl:
dw 10000
dw 1000
dw 100
dw 10
db 1
;
; Division mit negativen Konstanten
;
Methode4:
ld d,0 ; Set no leading zero
ld e,5 ; Set max number of digits
call divpow10 ; Get digits
dw -10000
call divpow10
dw -1000
call divpow10
dw -100
call divpow10
dw -10
ld d,'0' ; Allow zeroes now
call divpow10
dw -1
inc e
trail:
dec e ; Test all digits printed
ret z ; Yeap
ld a,' '
call APUT ; Put trailing blanks anywhere
jr trail
;
; Print quotient as decimal number [HL DIV <SP>]
;
divpow10:
ex (sp),hl
ld c,(hl) ; Fetch divisor
inc hl
ld b,(hl)
inc hl
ex (sp),hl
ld a,'0' ; Init digit
divloop:
push hl ; Save value
add hl,bc ; Divide
jr nc,divend ; Get result
inc a ; Advance quotient
inc sp ; Delete remainder
inc sp
jr divloop
divend:
pop hl ; Get back remainder
cp '0' ; Test possible leading zero
jr nz,not0 ; Nope
ld a,d ; Get state of leading zero
jr tst0 ; Test leading zero allowed
not0:
ld d,'0' ; Set no leading zero
tst0:
cp 0 ; Test leading zero allowed
ret z ; Nope
call APUT ; Put anywhere
dec e ; Count down remaining length
ret
;
; Division mit positiven Konstanten
;
Methode5:
ld b,0 ; Init flag
ld de,10000
call divpow10 ; Start with 10000s
ld de,1000
call divpow10 ; Then 1000s
ld de,100
call divpow10 ; Then 100s
ld e,10
call divpow10 ; Then 10s
ld a,l ; Get remainder
jr lastdig
divpow10:
xor a ; Clear quotient
divloop:
inc a ; Advance quotient
sbc hl,de ; Divide
jr nc,divloop ; Still positive
add hl,de ; Fix for last number
inc b ; Access flag
dec a ; Test zero digit
jr nz,lastdig ; Nope, so store result
dec b ; Test flag
ret z ; No leading zeroes
lastdig:
add a,'0' ; Make ASCII
call APUT ; Put anywhere
ret
;
; Der Wert des HL-Register wird dezimal ausgegeben, und zwar
; rechtsbuendig fuehrende Nullen werden unterdrueckt
;
Methode6:
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 ; Ausgaben
pop af
DecOut:
and 00001111b ; 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:
call APUT ; Put anywhere
ret
;
DecBuff:
ds 3