Jump to content
Sign in to follow this  
snicklin

Printing Numbers (0 to 99) - Assembly Language

Recommended Posts

I could probably work this out with enough time, but I guess that enough of you clever people know how to do something like this....

 

I have an integer stored as a byte which can be a value of between 0 and 99 inclusive.

 

I then want to create a filename, so I need this number as text.

 

If the integer is between 0 and 9 inclusive, I would like to print it as "07" (i.e. a zero at the start).

 

If the integer is greater than 9 and will always be less than 100, I just want the number as the 1st 2 bytes of the filename.

 

I want some compact code to do this, could I use CIOV somehow? Or can I do better with your code?

 

Share this post


Link to post
Share on other sites

I could probably work this out with enough time, but I guess that enough of you clever people know how to do something like this....

 

I have an integer stored as a byte which can be a value of between 0 and 99 inclusive.

 

I then want to create a filename, so I need this number as text.

 

If the integer is between 0 and 9 inclusive, I would like to print it as "07" (i.e. a zero at the start).

 

If the integer is greater than 9 and will always be less than 100, I just want the number as the 1st 2 bytes of the filename.

 

I want some compact code to do this, could I use CIOV somehow? Or can I do better with your code?

Untested, should work:

 

example:
        lda #<outputPtr
        sta ptr
        lda #>outputPtr
        sta ptr++1
        lda inputNumber
        sta number
        jsr p2dig

end:    jmp end

        ; Outputs a decimal three digit number from "000" to "999",
        ; input is in ZP variable "number" and output is written
        ; to address in ZP variables "ptr"
p3dig:
        jsr p1dig
        ; Fall-through

        ; Outputs a decimal two digit number from "00" to "99",
        ; input is in ZP variable "number" and output is written
        ; to address in ZP variables "ptr"
p2dig:
        jsr p1dig
        ; Fall-through

        ; Outputs a decimal one digit number from "0" to "9",
        ; input is in ZP variable "number" and output is written
        ; to address in ZP variables "ptr"
p1dig:
        ldx #8 ; 8 bit division...
        lda #0  ; remainder
divL:   asl number
        rol a
        cmp #10
        bcc noInc
        sbc #10
        inc number
noInc:  dex
        bne divL
        
        ora #48
        sta (ptr),y
        iny
        rts

Share this post


Link to post
Share on other sites

When I had a similar problem, I ended up using the internal FP routines to do the conversion. Takes a while to learn the use of the routines. Ended up being useful for several programs at the time but haven't used them much if at all since.

Share this post


Link to post
Share on other sites

Untested, should work:

Obviously, didn't work :-(

 

This is a working version, there are entry points for 3 digits (p3dig), 2 digits (p2dig) and one digit (p1dig).

 

example:
        lda #<outputPtr
        sta ptr
        lda #>outputPtr
        sta ptr+1
        lda inputNumber
        sta number
        jsr p2dig

end:    jmp end


        ; Outputs a decimal three digit number from "000" to "999",
        ; input is in ZP variable "number" and output is written
        ; to address in ZP variables "ptr"
p3dig:
        ldy #2
        jsr div10
        ; Fall-through

        ; Outputs a decimal two digit number from "00" to "99",
        ; input is in ZP variable "number" and output is written
        ; to address in ZP variables "ptr"
p2dig:
        ldy #1
        ; Fall-through

div10:
        ldx #8 ; 8 bit division...
        lda #0  ; remainder
divL:   asl number
        rol
        cmp #10
        bcc noInc
        sbc #10
        inc number
noInc:  dex
        bne divL

        ora #48
        sta (ptr),y

        ; Outputs a decimal one digit number from "0" to "9",
        ; input is in ZP variable "number" and output is written
        ; to address in ZP variables "ptr"
p1dig:
        ldy #0
        lda number

putdig:
        ora #48
        sta (ptr),y
        rts

Share this post


Link to post
Share on other sites

Try to organize your counter as a decimal one and advance it with:

sed
clc
lda #1
adc counter
sta counter
cld

Then conversion to 2-digit string is:

lda counter
lsr
lsr
lsr
lsr
ora #'0'
tax
lda counter
and #$f
ora #'0'

The result is in XA, where X=dozens, A=units ATASCII characters - put they where you like.

Edited by mono

Share this post


Link to post
Share on other sites

Thank you all for your input. I will just take a little time to analyse each suggestion and then I'll answer back.

 

If anyone else has any ideas, feel free to continue to suggest ways...

Share this post


Link to post
Share on other sites

I'd go with the suggestion above to use BCD mode. That stores value '0' to '9' in each nybble of the byte making it easy to mask/convert to the text equivalent. (Remember to turn off decimal mode if it is not needed for the rest of your program.)

  • Like 1

Share this post


Link to post
Share on other sites

Try to organize your counter as a decimal one and advance it with:

sed
clc
lda #1
adc counter
sta counter
cld

 

Hi Mono,

Could you clarify the above code a little more please? (sorry, I'm new to this decimal mode).

What is the difference between this and me doing a normal increment?

 

Steve

Share this post


Link to post
Share on other sites

What is the difference between this and me doing a normal increment?

In normal mode 9+1=$a, in decimal mode 9+1=$10.

Share this post


Link to post
Share on other sites

If the intent is to simply have a printable counter and not do any other operations it's probably easiest to just maintain it as either the ASCII or internal screen codes in seperate bytes.

 

The increment loop gets a bit longer and complex but you remove the need for conversion.

Share this post


Link to post
Share on other sites

 

Hi Mono,

Could you clarify the above code a little more please? (sorry, I'm new to this decimal mode).

What is the difference between this and me doing a normal increment?

 

Steve

 

BCD mode is described here: http://www.6502.org/tutorials/decimal_mode.html

In common words this does as MaPa said. Any disadvantage is that inc/dec opcodes not run with BCD, so you need to use adc/sbc instead.

As kenjennings wrote - keep in mind to do CLD after "increment".

Share this post


Link to post
Share on other sites

If the intent is to simply have a printable counter and not do any other operations it's probably easiest to just maintain it as either the ASCII or internal screen codes in seperate bytes.

 

The increment loop gets a bit longer and complex but you remove the need for conversion.

 

I intend to be using the values for more than just printing to a memory location, so I need to keep it as the original values (0-99) and then convert them.

 

And to others, thanks for explaining the difference between the modes. This is all helping my 6502 education, thanks for the assistance.

Share this post


Link to post
Share on other sites

The fast version :P

	lda first,x
	sta out
	lda second,x
	sta out+1		
	;....

first
	:10 .byte '0'
	:10 .byte '1'
	:10 .byte '2'
	:10 .byte '3'
	:10 .byte '4'
	:10 .byte '5'
	:10 .byte '6'
	:10 .byte '7'
	:10 .byte '8'
	:10 .byte '9'
second
	:10 .byte '0123456789'
  • Like 1

Share this post


Link to post
Share on other sites

You know what, I have exactly a routine doing this stuff:

;--------------------------------------------------
displaybyte ;decimal (byte), displayposition  (word)
;--------------------------------------------------
; displays decimal number as in parameters (in text mode)
; the range is (00..99 - one byte)

    ldy #1 ; there will be 2 digits
NextDigit2
    ldx #8 ; 8-bit dividee so Rotate 8 times
    lda #$00
Rotate001
    asl decimal
    rol  ; scroll dividee
    cmp #10  ; divider
    bcc TooLittle001 ; if A is smaller than divider
    ; there is nothing to substract
    sbc #10  ; divider
    inc decimal     ; because it is 0 and this is the fastest way
TooLittle001 dex
    bne Rotate001 ; and Rotate 8 times, Result will be in decimal
    tax  ; and the rest in A
    ; (and it goes to X because
    ; it is our decimal digit)
    lda digits,x
    sta decimalresult,y
    dey
    bpl NextDigit2 ; Result again /10 and we have next digit

decimalend1
    ; displaying
    mwa displayposition modify
    ldy #1
displayloop1
    lda decimalresult,y
    sta (modify),y
    dey
    bpl displayloop1
    rts
;-------decimal constans
digits   dta d"0123456789"
decimalresult  .word 0
;--------------------------------------------------------

It is awful but works. Style sucks because it was migrated from MAC65 to mads (through OMC65 in between). This is modified from a routine displaying more than 2 digits.

Share this post


Link to post
Share on other sites

OK, thank you everyone so far for your input. You've all been great and show me just how good that the Atari 8-bit community is.

 

I think that the solution from Pirx and Dmsc are similar. I didn't want to go with the counter option as I am not counting up, I am using the code to refer to tables and databases as numbers within a filename.

 

I got Pirx's code (as it was similar to Dmsc and I had to use one of them) and used that as a basis. I've then customised it to my requirements. I pass in a value in the accumulator and expect the result out in acc and x as 2 digits.

Internal_Convert099:
        STA decimal
        LDY #1
    NextDigit2:
        LDX #8
        LDA #0
    Rotate001:
        ASL decimal
        ROL                
        CMP #10            
        BCC TooLittle001
        SBC #10
        INC decimal
    TooLittle001:
        DEX
        BNE Rotate001
        TAX
        LDA digits,x
        STA decimalresult,y
        DEY
        BPL NextDigit2
    storeResults:
        LDX decimalresult+1
        LDA decimalresult+0
        RTS        
;-------decimal constants
    digits:         dta 48,49,50,51,52,53,54,55,56,57
    decimalresult:  .word 0
    decimal:        .byte

I could probably refine this a little, but I'll come back to that later, this is working as is.

 

Thanks once more to all.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...