Printing (unsigned) 16-bit numbers in Assembly, how?

Basic and Machine Language

Moderator: Moderators

Post Reply
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Printing (unsigned) 16-bit numbers in Assembly, how?

Post by MrSterlingBS »

Hello,

some question about the integer to floatpoint and floatpoint to ascii routines.
When i have a result > 32768 i get a negative result.
How can i print out a value > 32768?

i use this routines from the VIC OS:

Code: Select all

; mult22.a
; from Niels Möller: https://www.lysator.liu.se/~nisse/misc/6502-mul.html
; slightly tweaked for speed
;
; 8 bit x 8 bit unsigned multiply, 16 bit result
; Average cycles: 76.48
; 563 bytes


FLPASC 	equ $DDDD
INTFLP	equ $D391		

CLRSCR	equ $E55F
WRTF	equ $E742

STROUT 	equ $CB1E
STACK	equ	$0100

multiplier	equ $26
multiplicand equ $28
min	    	equ $30		
result_low	equ $32
temp3      	equ $34		
producthigh equ $36

* = $1001
		; BASIC program to boot the machine language code
		db $0b, $10, $0a, $00, $9e, $34, $31, $30, $39, $00, $00, $00
			
	sei				; stop interrupts
	
	jsr CLRSCR		; clear screen
	
	
	lda #$00		; high
	ldy #230			; low
	sty multiplier
	jsr INTFLP		; integer to float point
	
	jsr Primm
	db "MULTIPLIER:  ",$00	
	
	jsr FLPASC
	ldy #>STACK
	lda #<STACK
	jsr STROUT
	
	
	lda #$00		; high
	ldy #155		; low
	sty multiplicand
	jsr INTFLP		; integer to float point
	
	jsr Primm
	db $0d,"MULTIPLICAND:",$00	
	
	jsr FLPASC
	ldy #>STACK
	lda #<STACK
	jsr STROUT
	
; code from the book VIC-20 MACHINE LANGUAGE GUIDE Abacus Software
	lda #0						
	sta $9129	; decrements every 256 µS	; 4 cycles
	sta $9128	; decrements every µS		; 4 cycles
	cld			; insure binary mode		; 2 cycles
	clc			; clear carry flag			; 2 cycles
; ************** Start Counter with 10 Cycles ********************	


; ***************************************************************************************

	lda multiplier
	ldx multiplicand
	
; In: Factors in A and X
; Out: High byte in A, low byte in result_low
mult:
    sta min
    cpx min
    bcc swap1
    txa
continue:
    sbc min
    tay

    ; at this point:
    ;   Y = max(inputs) - min(inputs);
    ;   X = max(inputs);
    lda sqtab_lsb,x
    sbc sqtab_lsb,y
    sta result_low
    lda sqtab_msb,x
    sbc sqtab_msb,y
    sta temp3
    clc
    ldx min
    lda result_low
    adc sqtab_lsb,x
    sta result_low
    lda temp3
    adc sqtab_msb,x
    ror
    ror result_low
    ;rts
	sta producthigh
	jmp endcalc

swap1:
    stx min
    tax
    sec
    bcs continue            ; ALWAYS branch

endcalc:

; ************** Stop Counter ********************		
	
	lda $9128		
	sta $FB
		
	lda producthigh
	ldy result_low
	jsr INTFLP		; integer to float point
	
	jsr Primm
	db $0d,$0d,"SOLUTION:",$00	
	
	jsr FLPASC
	ldy #>STACK
	lda #<STACK
	jsr STROUT
	
	
	lda #$FF
	sbc $FB
	sbc #10
	tay				; low
	
	lda #0
	jsr INTFLP		; integer to float point
	
	
	jsr Primm
	db $0d,$0d,$0d,"CYCLES:",$00	
	
	jsr FLPASC
	ldy #>STACK
	lda #<STACK
	jsr STROUT
	
		
	jmp *			; infinity jump
	
Primm:
	pla
	sta $03
	pla
	sta $04
X10D6:	
	inc $03
	bne	X10DC
	inc $04
X10DC:
	ldy #$00
	lda ($03),y
	beq X10E7
	jsr WRTF
	bcc X10D6
X10E7:
	lda $04
	pha
	lda $03
	pha
	rts
	
; align tables to page boundary for best speed
sqtab_lsb: ;<x*x
    db 0,1,4,9,$10,$19,$24,$31,$40,$51,$64,$79,$90,$a9,$c4,$e1
    db 0,$21,$44,$69,$90,$b9,$e4,$11,$40,$71,$a4,$d9,$10,$49,$84,$c1
    db 0,$41,$84,$c9,$10,$59,$a4,$f1,$40,$91,$e4,$39,$90,$e9,$44,$a1
    db 0,$61,$c4,$29,$90,$f9,$64,$d1,$40,$b1,$24,$99,$10,$89,4,$81
    db 0,$81,4,$89,$10,$99,$24,$b1,$40,$d1,$64,$f9,$90,$29,$c4,$61
    db 0,$a1,$44,$e9,$90,$39,$e4,$91,$40,$f1,$a4,$59,$10,$c9,$84,$41
    db 0,$c1,$84,$49,$10,$d9,$a4,$71,$40,$11,$e4,$b9,$90,$69,$44,$21
    db 0,$e1,$c4,$a9,$90,$79,$64,$51,$40,$31,$24,$19,$10,9,4,$1
    db 0,1,4,9,$10,$19,$24,$31,$40,$51,$64,$79,$90,$a9,$c4,$e1
    db 0,$21,$44,$69,$90,$b9,$e4,$11,$40,$71,$a4,$d9,$10,$49,$84,$c1
    db 0,$41,$84,$c9,$10,$59,$a4,$f1,$40,$91,$e4,$39,$90,$e9,$44,$a1
    db 0,$61,$c4,$29,$90,$f9,$64,$d1,$40,$b1,$24,$99,$10,$89,4,$81
    db 0,$81,4,$89,$10,$99,$24,$b1,$40,$d1,$64,$f9,$90,$29,$c4,$61
    db 0,$a1,$44,$e9,$90,$39,$e4,$91,$40,$f1,$a4,$59,$10,$c9,$84,$41
    db 0,$c1,$84,$49,$10,$d9,$a4,$71,$40,$11,$e4,$b9,$90,$69,$44,$21
    db 0,$e1,$c4,$a9,$90,$79,$64,$51,$40,$31,$24,$19,$10,9,4,$1

sqtab_msb: ;>x*x
    db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
    db 1,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3
    db 4,4,4,4,5,5,5,5,6,6,6,7,7,7,8,8
    db 9,9,9,$a,$a,$a,$b,$b,$c,$c,$d,$d,$e,$e,$f,$f
    db $10,$10,$11,$11,$12,$12,$13,$13,$14,$14,$15,$15,$16,$17,$17,$18
    db $19,$19,$1a,$1a,$1b,$1c,$1c,$1d,$1e,$1e,$1f,$20,$21,$21,$22,$23
    db $24,$24,$25,$26,$27,$27,$28,$29,$2a,$2b,$2b,$2c,$2d,$2e,$2f,$30
    db $31,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f
    db $40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f
    db $51,$52,$53,$54,$55,$56,$57,$59,$5a,$5b,$5c,$5d,$5f,$60,$61,$62
    db $64,$65,$66,$67,$69,$6a,$6b,$6c,$6e,$6f,$70,$72,$73,$74,$76,$77
    db $79,$7a,$7b,$7d,$7e,$7f,$81,$82,$84,$85,$87,$88,$8a,$8b,$8d,$8e
    db $90,$91,$93,$94,$96,$97,$99,$9a,$9c,$9d,$9f,$a0,$a2,$a4,$a5,$a7
    db $a9,$aa,$ac,$ad,$af,$b1,$b2,$b4,$b6,$b7,$b9,$bb,$bd,$be,$c0,$c2
    db $c4,$c5,$c7,$c9,$cb,$cc,$ce,$d0,$d2,$d4,$d5,$d7,$d9,$db,$dd,$df
    db $e1,$e2,$e4,$e6,$e8,$ea,$ec,$ee,$f0,$f2,$f4,$f6,$f8,$fa,$fc,$fe
	
Calc.jpg

Thanks a lot for your help!

BR
Sven
Last edited by Mike on Fri May 12, 2023 10:53 am, edited 1 time in total.
Reason: thread split from essentially unrelated topic, image link repaired
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by chysn »

Try the routine at $DDCD (PRTFIX), which takes X as low byte and Accumulator as high byte and prints a 16-bit positive integer:

Code: Select all

        PRTFIX      = $ddcd             ; Print base-10 number

        jsr Primm
        db $0d, $0d, "SOLUTION:", $00
        ldx result_low
        lda product_high
        jsr PRTFIX
        ...
The normal BASIC integer type's range is -32768 ~ 32767
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5

WIP: MIDIcast BASIC extension

he/him/his
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by MrSterlingBS »

Hi Chysn,

thanks a lot for your help.
The routine works fine now.
But...
I think you guess my question.

How can i printout 256 by 256 = 65536 or the range from 0 to 65535 ?

Is it possible?


Best regards
Sven
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by Mike »

MrSterlingBS wrote:How can i printout 256 by 256 = 65536 or the range from 0 to 65536?
As long as you are working with an unsigned 8 bit x 8 bit -> 16 bit multiply, all numbers stay within the range 0..255 and 0..65535, respectively, so the need to print 256 or 65536 is not even a issue.

If you want to handle bigger factors and product results, you will need to extend both the multiply routine and the base conversion routine by yourself. In general, for a multiply of two n bit numbers, the result will always fit within 2n bits, so it is best you write a display routine for the 2n bit result, which will then also be capable of printing the n bit factors.

You might want to use those routines in 6502.org as blueprints: Large Multiply & Divide and "Hexadecimal to Decimal Conversion" (<- actually a misnomer: these routines convert a binary value to a BCD value).

Note using BCD mode on the VIC-20 requires you to either execute the involved routines with interrupts off, or provide a small IRQ wedge with CLD as first instruction, as the NMOS 6502 does not clear the D flag upon interrupt entry, neither does the KERNAL IRQ handler.

Adaption of those routines to the VIC-20, including a BCD to ASCII conversion left as exercise for the reader.
User avatar
MrSterlingBS
Vic 20 Enthusiast
Posts: 174
Joined: Tue Jan 31, 2023 2:56 am
Location: Germany,Braunschweig

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by MrSterlingBS »

Hi,

excuse my poorly asked question.
The multiplication of 255 by 255 is 65025.
But the range is from 0…65535 ?
How can i calculate and print values above 65025?

or am I confusing something?

The german book „VC–20 intern“ describes the routine $DDCD with a range from 0…65535.

Best regards
Sven

PS: I come to the questions to understand the famous work of Tobi Lobster that he published on github.
https://github.com/TobyLobster/multiply_test
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by Mike »

MrSterlingBS wrote:How can i calculate and print values above 65025?
As I wrote in my preceding post:

"If you want to handle bigger factors and product results, you will need to extend both the multiply routine and the base conversion routine by yourself. In general, for a multiply of two n bit numbers, the result will always fit within 2n bits, so it is best you write a display routine for the 2n bit result, which will then also be capable of printing the n bit factors."

Emphasis added.
User avatar
chysn
Vic 20 Scientist
Posts: 1205
Joined: Tue Oct 22, 2019 12:36 pm
Website: http://www.beigemaze.com
Location: Michigan, USA
Occupation: Software Dev Manager

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by chysn »

MrSterlingBS wrote: Fri May 12, 2023 2:20 pm How can i calculate and print values above 65025?
If you want to make a "biggerint" type, I can point you here, which is a post I did a few years ago about Decimal Mode, how it works, some of its pitfalls:

http://sleepingelephant.com/ipw-web/bul ... php?t=9651

I'd respectfully disagree with Mike (which is admittedly an epistemologically-risky thing to do in general) about needing to worry about the IRQ when using Decimal Mode in your regular code. There are no ADCs and only a few SBCs in the whole service routine path, and their function is radix-agnostic. But it's a good idea to be careful with Decimal Mode because the VIC-20 never clears the flag; if it's left on, things get weird. So just clear it when your code ends, or before you do other ROM calls. Have a reset button.

But it promises to make base-10 printing routines pretty easy to write, regardless of what size you need.
VIC-20 Projects: wAx Assembler, TRBo: Turtle RescueBot, Helix Colony, Sub Med, Trolley Problem, Dungeon of Dance, ZEPTOPOLIS, MIDI KERNAL, The Archivist, Ed for Prophet-5

WIP: MIDIcast BASIC extension

he/him/his
tlr
Vic 20 Nerd
Posts: 567
Joined: Mon Oct 04, 2004 10:53 am

Re: Printing (unsigned) 16-bit numbers in Assembly, how?

Post by tlr »

There's also some discussion this thread: http://sleepingelephant.com/ipw-web/bul ... p?p=114085
Post Reply