Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Moderator: Rockford

Antworten
Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

Hallo!

Ich hab mir eine Routine geschrieben, um 16Bit-Zahlen in Assembler auf den Bildschirm auszugeben.
Dazu wandle ich die 16Bit-Zahl in BCD-Zahlen um, also 4Bit für eine Zahl. Diese extrahiere ich dann mit einem AND (und etwas shiften) und addiere den ASCII-Wert der Zahl 0 hinzu. Das kann man nun direkt in den Bildschirmspeicher schreiben.

Geht es eleganter? Schneller?

Grüße
Janko

Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Dr. Irata »

Hallo Janko,
wie genau schreibst du dann die Zahl in den Bildschirm?

Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

Hi!

Für die Umwandlung von BIN nach BCD habe ich eine Routine im Internet gefunden:

Code: Alles auswählen

;#########################################################
; # Binär nach Dezimal (BCD) Umwandlung
; #

		.proc BINBCD16

	   	sed     	; Switch to decimal mode
        	lda #0      	; Ensure the result is clear
        	sta BCD+0	
        	sta BCD+1
        	sta BCD+2
        	ldx #16     	; The number of source bits

@	     	asl BIN+0   	; Shift out one bit
        	rol BIN+1
        	lda BCD+0   	; And add into result
        	adc BCD+0
        	sta BCD+0
        	lda BCD+1   	; propagating any carry
        	adc BCD+1
        	sta BCD+1
        	lda BCD+2   	; ... thru whole result
        	adc BCD+2
        	sta BCD+2
        	dex     	; And repeat for next bit
       	 	bne @-
       		cld     	; Back to binary

		rts

BIN		.word 12345
BCD		.DS 3		; 45 23 01

		.end
Ausgegeben wird es hiermit:

Code: Alles auswählen

AusgabeConv	dey
		clc
		lda BINBCD16.BCD,y
		and #%11110000
		lsr 
		lsr 
		lsr 
		lsr 
		adc CHPOS
		sta StatusScrMem,x
		inx
		clc
		lda BINBCD16.BCD,y
		and #%00001111
		adc CHPOS
		sta StatusScrMem,x
		inx
		cpy #$00
		bne AusgabeConv
		rts
CHPOS enthält eine Speicherstelle wo der ASCII-Wert für "0" enthalten ist.
Ich lösche die untern 4 Bit und schiebe dann die oberen 4 Bit nach unten und addiere nun CHPOS, womit ich die erste Zahl habe.
Anschließend lösche ich die oberen 4Bit und addiere erneut CHPOS, womit ich die 2. Zahl habe.

Janko

Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Dr. Irata »

... aber wie wandelst du eine z.B. 16 Bit Zahl in BCD um??

Nehmen wir mal die Zahl 1977 - umgewandelt in BCD würde das so aussehen:

0001 für 1
1001 für 9
0111 für 7
0111 für 7
man hat also dann für diese Zahl 4 x 1 Byte und kann dann entsprechend die Charakter auf den Bildschirm ausgeben.
Die Zahl liegt aber ürsprünglich in dieser Form vor:

$07B9 bzw. 7 (Highbyte), 185 (Lowbyte)

Also die Frage: Wir komme ich von $07B9 auf 0001,1001,0111,0111
???

Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

Dafür gibt es den Dezimalmodus im 6502:

Code: Alles auswählen

sed     	; Switch to decimal mode
Nehmen wir einmal die Zahl 100 und nur 8Bit, damit es einfacher ist.
Hex $64 = Dez 100 = Binär %01100100

Nun shiftet das Programm 8x die Zahl nach Links und packt jeweils das Bit 7 in den Carry.

Code: Alles auswählen

Durchgang 1:
Carry = 0 
Zahl = 0
Neue Zahl = %11001000

Durchgang 2:
Carry = 1
Zahl = 1
Neue Zahl = %10010000

Durchgang 3:
Carry = 1
Zahl = 3
Neue Zahl = %00100000

Durchgang 4:
Carry = 0
Zahl = 6
Neue Zahl = %01000000

Durchgang 5:
Carry = 0
Zahl = 12
Neue Zahl = %10000000

Durchgang 6:
Carry = 1
Zahl = 25
Neue Zahl = %00000000

Durchgang 7:
Carry = 0
Zahl = 50
Neue Zahl = %00000000

Durchgang 8:
Carry = 0
Zahl = 100 -> Bingo
Da wir den Dezimalmodus aktiviert haben, ist diese Zahl nun in jeweils 4er Bit-Blöcke im Speicher abgelegt.

Janko

Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Dr. Irata »

Ich muss mir das immer praktisch vorstellen können... und habe noch nicht mit dem SED Befehl gearbeitet.
Nehmen wir also die Zahl 100 und speichern die in Speicherstelle ... sagen wir mal 40000.
Dann haben wir ja in Speicherstelle 40000 nicht 100 drin, sondern binär ja eine 8 Bit Folge: 01100100.
Was genau macht jetzt der Befehl SED?? Scheidet er die 8 Bit Folge durch und macht daraus 0110 und 0100 - und wo werden die dann abgelegt? In 40000 und 40001 ??

Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

Nein... also nach der Umwandlung von BIN in BCD hast Du im obgien Beispiel 2 Byte mit folgenden Inhalt:

Byte 0 = %0000 0000 entspricht "00"
Byte 1 = %0000 0001 entspricht "01"

Nun müssen wir diese Daten für uns nutzbar machen:

Dafür nimmt man sich das Byte 1 und macht ein AND %1111 0000

Code: Alles auswählen

    %0000 0001 
AND %1111 0000
=   %0000 0000
Das Beispiel ist ungünstig, aber es ist nun notwendig die oberen 4 Bits nach Recht zu shiften mit

Code: Alles auswählen

lsr 
lsr 
lsr 
lsr 
Jetzt hat man die erste Ziffer komplett isoliert und muss nur den ASCII-Wert für 0 addieren und kann das Ergebnis in den Bildschirm schreiben.
Nun kommt die 2. Zahl, wo wir die unteren 4 Bits haben wollen:

Code: Alles auswählen

    %0000 0001 
AND %0000 1111
=   %0000 0001
Diese Zahl wird wieder mit dem ASCII-Wert für 0 addiert und wir haben die 2. Ziffer.

Mit Byte 0 macht man das selbe und hat nun eine 4-stellige Zahl.

Ich finde es sehr aufwendig und frage mich deshalb, ob es auch einfacher geht.

Grüße
Janko

Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Dr. Irata »

hmmmm - aber wo genau legt er denn die beiden Bytes ab??
Nehmen wir mal ein anderes Beispiel und die Zahl 224

Macht er aus 11100000 dann 00000010 und 00011000 ??

Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

In meinem Code-Beispiel ganz oben sind diese Variablen definiert:

Code: Alles auswählen

BIN		.word 12345
BCD		.DS 3		; 45 23 01
In BIN steht die binäre Zahl in mit 16 Bit.
In BCD sind die 3 Byte mit der BCD Zahl.

Also die Zahl dezimal "12345" würde in den 3 Bytes in der Form "45 23 01" stehen.
Also %01000101 %00100011 %00000001

Wobei
%0100 = 4
%0101 = 5

%0010 = 2
%0011 = 3

%0000 = 0
%0001 = 1

Deshalb muss man diese Bytes rückwärts lesen. -> 01 23 45

Grüße
Janko

Benutzeravatar
pps
Beiträge: 530
Registriert: 18.06.2021 23:05
Has thanked: 115 times
Been thanked: 206 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von pps »

In "go lucky" habe ich intern 32bit HEX genutzt und dann natürlich auch eine Routine um das dann in Dezimal anzuzeigen. Allerdings sicher nicht in optimalster Weise gelöst. Aber es funktioniert halt. Ich schaue morgen mal, wo ich es habe und poste gerne meinen Weg.
PP´s of STARSOFTBerlin__________github|meine Webseite|Demozoo

Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

Hi!

Super, da würde ich mich freuen, wenn Du uns Deinen Ansatz zeigst.

Grüße
Janko

Benutzeravatar
dl7ukk
Beiträge: 532
Registriert: 25.08.2021 23:03
Has thanked: 69 times
Been thanked: 99 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von dl7ukk »

Hi,

ich habe keine Ahnung von Assembler, stand aber auch vor dieser Ausgabe
Meine Lösung war mit die Nibbels mit einer Tabelle zu wandeln. Danke Nortobor!!

Code: Alles auswählen

           LDA $F0,X	; Zahl aus $Fx holen
           TAY		;  zwischenspeichern

           AND #$F       ; hohes Nibble aussortieren
           TAX		 ; = Lo Stelle

           LDA Tab1,X	; intern --> Atascii

        Im Akku ist die  Hex Low Stelle       
        -->  ausgeben ...
   
           TYA                   ; Zahl wieder einlesen
           LSR                    ; Low-Nibble aussortieren
           LSR  
           LSR  
           LSR  
           TAX 
           LDA Tab1,X    ; intern --> Atascii
           --> ausgeben
           ....


           ORG Tab1         ; Umwandeln der Nibbel in HexZahlen
           DFB $10,$11,$12,$13,$14,$15,$16,$17,$18,$19
           DFB $21,$22,$23,$24,$25,$26
           NOP 

dl7ukk

Benutzeravatar
Kveldulfur
Beiträge: 624
Registriert: 17.08.2021 02:32
Has thanked: 238 times
Been thanked: 163 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Kveldulfur »

Danke dl7ukk!

Im Prinzip machst Du es ähnlich wie ich, nur mit Hexadezimalzahlen. Da ich aber Dezimalzahlen haben möchte, wandel ich vorher diese noch per BIN2BCD um.

Grüße
Janko

Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Dr. Irata »

Ich habe mal aus Spass in Basic gerade eine Zählschleife programmiert, um eine 16 Bit Zahl mit 5 Ziffern (geht also bis 65535) in eine entsprechende "Zifferzahl" umzuwandeln - das könnte man dann relativ einfach in Assembler umwandeln:
Exemplarisch nehme ich die Zahl 12345 (48 Hi-Byte / 57 Lo-Byte) - geht, ist aber langsam. In Basic braucht es eine gute Minute für die Berechnung:

Code: Alles auswählen

                                 
  10 A=48                               
  20 B=57                               
  30 ST1=40010                          
  40 ST2=40009                          
  50 ST3=40008                          
  60 ST4=40007                          
  70 ST5=40006                          
  100 GRAPHICS 0                        
  140 FOR X=1 TO A                   
  150 FOR F=0 TO 255                 
  160 X1=X1+1                        
  170 IF X1=10 THEN X1=0:X2=X2+1     
  200 IF X2=10 THEN X2=0:X3=X3+1     
  230 IF X3=10 THEN X3=0:X4=X4+1     
  260 IF X4=10 THEN X4=0:X5=X5+1     
  270 NEXT F                         
  280 NEXT X                         
  300 FOR F=1 TO B                   
  310 X1=X1+1                        
  320 IF X1=10 THEN X1=0:X2=X2+1     
  330 IF X2=10 THEN X2=0:X3=X3+1     
  340 IF X3=10 THEN X3=0:X4=X4+1     
  350 NEXT F                         
  500 POKE ST1,X1+16                 
  502 POKE ST2,X2+16                 
  504 POKE ST3,X3+16                 
  506 POKE ST4,X4+16                 
  508 POKE ST5,X5+16                      
Zuletzt geändert von Dr. Irata am 25.05.2022 12:22, insgesamt 1-mal geändert.

Benutzeravatar
Dr. Irata
Beiträge: 937
Registriert: 24.08.2021 14:40
Has thanked: 110 times
Been thanked: 268 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Dr. Irata »

... so ähnlich habe ich es bei meinem Score bei "ReturnToPhobos" bzw. "BattleOfEris" umgesetzt.
Allerdings ist es dort natürlich nicht so, daß er ständig diese hohe Zahl für den Score berechnen muss, sondern wenn ein bestimmtes Item getroffen wird, dann zählt er ja immer nur die Punkte hoch, die ein Item bringen - z.B. 30 oder 40 ... 10 oder 50... und das geht natürlich sehr schnell - praktisch ohne Zeitverlust. Am Ende hat man dann eine 5-stellige Zahl, die aus 5 Bytes besteht - jedes Byte steht dann für den entsprechenden Wert des Charakters für die Zahl der jeweiligen Ziffer. Das musste ich so machen, da man ja bei einer Charakterlandschaft seine Charakter neu definieren muss - entsprechend auch die Zahlen und Buchstaben, die man braucht.

Insgesamt hat man hier natürlich ein wenig Programmieraufwand, den ich aber nicht höher einschätze, als mit den anderen Methoden - der Vorteil ist sicherlich, daß ich im Prinzip gar nicht auf eine Obergrenze beschränkt bin... also auch Zahlen jenseits von 16 Bit sind so einfach darstellbar. Den Highscore speichert man dann einfach in den 5 (oder mehr) Bytes für die jeweiligen Ziffern ab, entsprechend kann man das auch auf Diskette so abspeichern. Man braucht dann einfach ein paar Bytes mehr...

Ich werde meinen Scorezähler in Assembler mal ein wenig allgemeiner anpassen und dann hier online stellen (wenn erwünscht)!

Benutzeravatar
Mathy
Beiträge: 1135
Registriert: 18.06.2021 11:13
Wohnort: Heerlen, NL
Has thanked: 449 times
Been thanked: 256 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von Mathy »

.
Hallo Peter

Prodehl hat geschrieben:
25.05.2022 12:05
Ich werde meinen Scorezähler in Assembler mal ein wenig allgemeiner anpassen und dann hier online stellen (wenn erwünscht)!
Du hast selber gesehen, wie es hilft wenn Leute hier ihren Code teilen. Irgend jemand lernt immer etwas davon.

Tschüß

Mathy
Wer oder was hat denn da geblitzt?

Benutzeravatar
pps
Beiträge: 530
Registriert: 18.06.2021 23:05
Has thanked: 115 times
Been thanked: 206 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von pps »

So, hier mein Code für die Wandlung von 32-Bit HEX nach Dezimal und Dezimal zurück nach HEX aus "go lucky".
Ich habe dort maximal 10 Stellen Dezimal gehabt und daher auch nicht weiter berechnet.
Vor dem Aufruf muss jeweils die value (in low...high) gefüllt werden und man erhält dann in result das Ergebnis (in low...high)

Code: Alles auswählen

//--------------------------
        ; converts 10 digits (32 bit values has max. 10 decimal digits)
	.local hex2dec32	;result is low...high
        ldx #0
l3      jsr div10
        sta result,x
        inx
        cpx #10
        bne l3
        rts

        ; divides a 32 bit value by 10
        ; remainder is returned in akku
div10
        ldy #32         ; 32 bits
        lda #0
        clc
l4      rol
        cmp #10
        bcc skip
        sbc #10
skip    rol value
        rol value+1
        rol value+2
        rol value+3
        dey
        bpl l4
        rts

value   .he 00 00 00 00

result  .byte 0,0,0,0,0,0,0,0,0,0
	.endl
//--------------------------
	.local dec2hex32	;result is low...high
;reset result
	lda #0
	sta result
	sta result+1
	sta result+2
	sta result+3

	ldx #0
lp	lda value,x	;immer 0-9
	sta Num1
	lda #0
	sta Num1+1
	sta Num1+2
	sta Num1+3
	lda h0,x	;x 10, x 100, x 1000, etc
	sta Num2
	lda h1,x
	sta Num2+1
	lda h2,x
	sta Num2+2
	lda h3,x
	sta Num2+3
	stx m_x
	jsr MulDWord
;Ergebnis addieren zu result
	lda Num3
	sta add32.v0
	lda Num3+1
	sta add32.v0+1
	lda Num3+2
	sta add32.v0+2
	lda Num3+3
	sta add32.v0+3
	lda result
	sta add32.v1
	lda result+1
	sta add32.v1+1
	lda result+2
	sta add32.v1+2
	lda result+3
	sta add32.v1+3
	jsr add32
	lda add32.e
	sta result
	lda add32.e+1
	sta result+1
	lda add32.e+2
	sta result+2
	lda add32.e+3
	sta result+3
	inc m_x
	ldx m_x
	cpx #10
	beq @+
	jmp lp
@	rts

value   .byte 0,0,0,0,0,0,0,0,0,0
result  .he 00 00 00 00
h0	.he 01 0a 64 e8 10 a0 40 80 00 00
h1	.he 00 00 00 03 27 86 42 96 e1 ca
h2	.he 00 00 00 00 00 01 0f 98 f5 9a
h3 	.he 00 00 00 00 00 00 00 00 05 3b
m_x	.he 00
	.endl
//--------------------------
	.local add32		;v0+v1=e
	clc
	lda v0
	adc v1
	sta e
	lda v0+1
	adc v1+1
	sta e+1
	lda v0+2
	adc v1+2
	sta e+2
	lda v0+3
	adc v1+3
	sta e+3
	rts
v0	.he 00 00 00 00
v1	.he 00 00 00 00
e	.he 00 00 00 00
	.endl
//--------------------------
;code by flashjazzcat
;	Divide Num1 by Num2 and place result in Num1
;	Remainder is left in Num3, which MUST be immediately after Num1 in RAM
;	Optimised for size rather than speed
;
	.local DivDWord	;	Divide Num1 by Num2 and place result in Num1
	lda #0	        ;preset remainder to 0
	ldx #3
@
	sta Num3,x
	dex
	bpl @-

	ldy #32		; repeat for each bit
DivLoop
	clc		; clear carry so we can use ROL throughout
	ldx #248	; dividend lb & hb*2, msb -> Carry
@
	rol.w Num1-248,x	; .w ensures ZP addressing is never used
	inx
	bne @-
	
	sec
	ldx #252
@
	lda.w Num3-252,x
	sbc.w Num2-252,x
	pha
	inx
	bne @-
	
	bcs @+
	pla
	pla
	pla
	pla
	bcc Skip
@
	ldx #3
@
	pla
	sta Num3,x
	dex
	bpl @-

	inc Num1	; and increment result because divisor fit
Skip
	dey
	bne DivLoop
	rts
;----------------
	.endl
Definition von Num:

Code: Alles auswählen

;----- for calculations
Num1	;.ds 4
	.he 00 00 00 00
Num3	;.ds 8	; must follow Num1 for Div to work
	.he 00 00 00 00 00 00 00 00
Num2	;.ds 4
	.he 00 00 00 00
Sehr wahrscheinlich nicht die beste Lösung - aber es hat funktioniert für mich und daher bin ich zufrieden.
PP´s of STARSOFTBerlin__________github|meine Webseite|Demozoo

Benutzeravatar
LarsImNetz
Beiträge: 152
Registriert: 24.08.2021 18:27
Has thanked: 109 times
Been thanked: 81 times
Kontaktdaten:

Re: Eine 16-Bit Zahl auf den Bildschirm ausgeben (Assembler)

Beitrag von LarsImNetz »

Moin,
etwas ähnliches wie die Version von dl7ukk verwende ich auch.
Wenn ich in Games einen Score habe, dann ist es IMMER BCD. Somit spare ich mir die ständige Konvertiererei von Hex/Decimal nach BCD etc. Das einzige, was man beachten muss, man sollte die Parameter zum Addieren dann halt in Hex angeben. Also die dezimale Zahl 30 ist in BCD dann halt $30. Den Rest macht der Prozessor. Man setzt das BCD Flag und addiert auf seinen aktuellen Score einfach $30 hinzu. Am Ende der Routine noch ein CLD, fertig. Bei der Ausgabe gebe ich immer 2 Zahlen aus. Die einzelnen Nibble werden per AND maskiert oder per 4xLSR geshiftet und als Index verwendet. So kann man auch gleich ein ".sbyte" nehmen, also den Wert, der addiert werden muss, damit auf dem Screen z.B. eine 0 erscheint. Das ist AFAIK die 16 für eine 1 dann 17... Das kann man an geeigneter Stelle direkt in den Screen poken, das geht sehr flott. Auch vergleichen mit aktuellem Highscore geht per CMP. Man muss nur drauf achten wenn BCD, dann immer BCD.
Und ganz wichtig, nutzt man DLIs und sollte dort mal ADC/SBC verwendet werden ist tunlichst ein CLD zu verwenden, sonst kann im DLI auf CLD verzichtet werden. Am Ende des DLI repariert das der RTI.

JM2C
Lars

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast